Custom .NET Project Templates

As a software architect and consultant I'm always on the lookout for tools and practices to effectively communicate and apply project conventions. Agile, design guides, code reviews and pair programming have all been useful tools. But I've found no better tool than reading and working with real code.

As a project lead my ultimate goal is always to focus as much as possible on delivering business features over organizing, instrumenting or reinventing code.

One of the things I've tried to  do several times is to come up with a good new project template with all the logging, authentication and system or company packages already included.  I've had some success creating project templates in the past. Recently when working with an IdentityServer4 project template I discovered a new way of using dotnet to create project templates. I think it's been around for a while but it's new to me.

Creating the Template

To demonstrate I'll take my existing paging example project and add the ability to use it as a project template.

Following the documentation we first create a new ".template.config" folder in our project folder with a "template.json" file.  

.template.config folder

The "template.json" defines how our template is exposed to the dotnet new command.   For our paging example project we setup the following file.

{
    "author": "andrewhason",
    "classifications": [
        "AspNetCore",
        "Pagination",
        "RazorPages"
    ],
    "name": "Hanson.io PagingExample",
    "identity": "HansonIoPagingExample",
    "shortName": "hio_paging_example",
    "tags": {
        "language": "C#"
    },
    "sourceName": "PagingExample",
    "preferNameDirectory": "true"
}

The key properties to pay attention to are:

  • identity - unique way to reference our project template
  • shortName - the user will type in "dotnet new [shortName]"
  • sourceName - all instances of this value in the source tree and  file contents will be replaced by the value provided for the -n or --name parameter
In addition to replacing the "sourceName" there are additional replacements that can be defined in the template.json file, checkout the reference for details on more advanced transforms.

Installing the Template

Once we have the template.json file created we can install the template directly from the source with the following command

$ dotnet new -i ./src
results of install

Using the Template

We can create a new project from this template just like we can with any other project template that is shipped with .NET.

$ dotnet new hio_paging_example -n MyPagingProject

Now we have a working project, with our new name and all ready to start working on features.

newly created project

We can uninstall the template using "dotnet new -u" followed by the absolute path the template source.  (we can install using a relative path but have to uninstall using an absolute path)

$  dotnet new -u /Users/andrew/Projects/pagingexample/src

Creating a NuGet Package

Installing and uninstalling from the source of the template will work for smaller teams. Just place the project template in a git repository, add a readme  and move on.  With larger organizations we can upgrade the template to be hosted in a NuGet package.

Step 1

The first step is to make sure that our project source code is in a sub folder.  The documentation uses a "template" folder but I preferred to use a "src" folder. (I may be picky but I wanted my template project to feel just like all my other projects).

Step 2

I spent way more time trying to get the project to package than I expected.  Turns out I was trying to use the same project file for developing the project and for packaging the template. That didn't work. It turns out I needed to create a dedicated .csproj file just for packaging.  Once I did that it was pretty straightforward.

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <PackageType>Template</PackageType>
    <PackageId>Hansonio.Examples.Paging</PackageId>
    <PackageVersion>1.0.1</PackageVersion>
    <IsPackable>true</IsPackable>
    <Title>Hanson.io Paging Example</Title>
    <Authors>Andrew Hanson</Authors>
    <Description>ASP.NET Simple Paging Example</Description>
    <PackageTags>dotnet-new;template;aspnet;hansonio;paging</PackageTags>
    <IncludeContentInPack>true</IncludeContentInPack>
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <ContentTargetFolders>content</ContentTargetFolders>
    <EnableDefaultContentItems>false</EnableDefaultContentItems>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="src\**" Exclude="src\**\bin\**;src\**\obj\**;src\**\.vs\**;src\app.db" />
    <Compile Remove="**\*" />
  </ItemGroup>

</Project>

The MSFT documentation does a good job of walking through the project file format. I simply had to change the 'template' folder path to 'src' to match my folder structure.  

Additionally, I excluded the SQLite database I used when developing the project template.

Step 3

Now that we have the pack specific project file created we can call the "dotnet pack" command to generate the ".nupkg" file

$ dotnet pack PagingExampleTemplate.csproj -o ./artifacts/

This will create a file called "Hansonio.Examples.Paging.1.0.1.nupkg" in the artifacts directory.

Step 4

We can install the template from the package file in the same way we  installed from source but by pointing to the package file instead.  

$ dotnet new -i ./artifacts/Hansonio.Examples.Paging.1.0.1.nupkg

We could also push this package to a NuGet server and  install it by name directly from the server.

Step 5

Now that the project is installed we can create a new project from the template just like we did before.

$ dotnet new hio_paging_example -n MyPagingFromNuGet

Conclusion

What I really like about this way of creating project templates is that I can create a template from any existing project without make any significant changes to the project.

I'm excited to see how I can use this way of creating project templates to make my teams more efficient or kickstart prototypes or proof of concept projects more quickly.

Other Scenarios

  • Create a template for a single item instead of an entire project

Learn More

Cover image by Kieran Wood on Unsplash