Step-by-Step Guide to Building Custom .NET Templates

RickRick
4 min read

Introduction

The .NET SDK provides a powerful templating engine that allows developers to create reusable templates for projects, files, and solution structures. This guide covers how to create, package, and distribute custom templates using the dotnet new command-line interface.

Understanding .NET Templates

Templates in .NET are packages that contain source files and a configuration that determines how those files should be transformed when instantiated. They provide a way to standardize project structures, apply consistent patterns, and save time when creating new applications or components.

Key Concepts

  • Template: A set of files and folders that can be transformed into a working project or component

  • Template Package: A NuGet package containing one or more templates

  • Template Engine: The system that processes templates and generates output

Template Structure

A basic template consists of:

  1. Source Files and Folders: The content that will be used to generate new projects

  2. Configuration Files: JSON files that control how the template behaves

The .template.config Directory

Every template must have a .template.config directory at its root containing at least a template.json file. This file provides metadata and configuration for the template.

template.json

The template.json file defines how the template works. Here's a breakdown of the essential fields:

{
  "$schema": "http://json.schemastore.org/template",
  "author": "Your Name",
  "classifications": ["Category1", "Category2"],
  "identity": "Your.Template.Identity",
  "name": "User-friendly Template Name",
  "shortName": "template-shortname",
  "sourceName": "TemplateSourceName",
  "preferNameDirectory": true,
  "tags": {
    "language": "C#",
    "type": "project"
  }
}
  • $schema: Reference to the JSON schema

  • author: Creator of the template

  • classifications: Categories for organizing templates

  • identity: Unique identifier for the template

  • name: Display name for the template

  • shortName: Command-line alias for the template

  • sourceName: The name in source files to be replaced with the user's specified name

  • preferNameDirectory: Whether to create a directory for the output

  • tags: Metadata for filtering templates

Advanced Template Configuration

Parameters and Symbols

Templates can define parameters that users can specify when creating a new instance:

"symbols": {
  "ParameterName": {
    "type": "parameter",
    "datatype": "bool",
    "defaultValue": "false",
    "description": "Parameter description"
  }
}

Conditional Content

You can include or exclude files based on parameter values:

"sources": [
  {
    "modifiers": [
      {
        "condition": "(!ParameterName)",
        "exclude": ["ExcludedFolder/**/*"]
      }
    ]
  }
]

Post-Creation Actions

You can define actions to be executed after the template is instantiated:

"postActions": [
  {
    "description": "Additional setup steps",
    "manualInstructions": [
      {
        "text": "Instructions for the user after template creation"
      }
    ],
    "actionId": "CB9A6CF3-4F5C-4860-B9D2-03A574959774",
    "continueOnError": true
  }
]

Packaging and Distribution

Creating a NuGet Package

To distribute your template, you need to create a NuGet package:

  1. Create a .csproj file to define the package:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <PackageType>Template</PackageType>
    <PackageVersion>1.0.0</PackageVersion>
    <PackageId>Your.Template.Package</PackageId>
    <Title>Your Template Package</Title>
    <Authors>Your Name</Authors>
    <Description>Your template description</Description>
    <PackageTags>dotnet-new;templates;yourKeywords</PackageTags>
    <TargetFramework>netstandard2.0</TargetFramework>

    <IncludeContentInPack>true</IncludeContentInPack>
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <ContentTargetFolders>content</ContentTargetFolders>
    <NoWarn>$(NoWarn);NU5128</NoWarn>
    <NoDefaultExcludes>true</NoDefaultExcludes>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="content/**/*" Exclude="content/**/bin/**;content/**/obj/**" />
    <Compile Remove="**/*" />
  </ItemGroup>
</Project>
  1. Organize your files:
YourTemplatePackage/
├── YourTemplatePackage.csproj
└── content/
    ├── .template.config/
    │   └── template.json
    └── YourTemplateFiles/
  1. Build the package:
dotnet pack -c Release

Installing Templates

Templates can be installed from various sources:

  1. From a NuGet package:
dotnet new install Your.Template.Package
  1. From a local .nupkg file:
dotnet new install path/to/Your.Template.Package.1.0.0.nupkg
  1. From a file system directory:
dotnet new install path/to/template/directory

Using Templates

Once installed, you can use your template with:

dotnet new template-shortname -n ProjectName [--parameter1 value1]

Template Localization

Templates can be localized to display in different languages. Create a localize folder in the .template.config directory with JSON files named according to the language code:

.template.config/
├── template.json
└── localize/
    ├── templatestrings.en-US.json
    └── templatestrings.es-ES.json

Each localization file contains key-value pairs matching the fields in template.json that should be translated.

Visual Studio Integration

To make your template appear in Visual Studio's "New Project" dialog:

  1. Add Visual Studio metadata to the template.json:
"tags": {
  "language": "C#",
  "type": "project",
  "vs-workload": "dotnetcore"
}
  1. For complete integration, consider creating a Visual Studio Extension (VSIX) package.

Best Practices

  1. Clear naming: Choose descriptive, specific names for your templates

  2. Good documentation: Include clear descriptions and examples

  3. Minimal dependencies: Avoid unnecessary dependencies

  4. Thoughtful defaults: Provide sensible default values for parameters

  5. Testing: Test your templates in various environments before distribution

  6. Versioning: Follow semantic versioning for your template packages

  7. Organization: Keep templates focused and organized by functionality

Troubleshooting

Common Issues

  1. Template Not Found: Ensure the template is installed correctly

  2. File Not Included: Check your include/exclude patterns

  3. Parameter Not Working: Verify parameter configuration in template.json

  4. Template Not Visible in VS: Check Visual Studio integration settings

Debugging

For detailed logs when using templates:

dotnet new template-shortname -n ProjectName --verbosity diagnostic

Conclusion

Custom .NET templates are a powerful way to standardize code structures, enforce architectural patterns, and improve productivity. By following this guide, you can create, package, and distribute templates that will help your team or the wider .NET community build better software more efficiently.

Resources

0
Subscribe to my newsletter

Read articles from Rick directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rick
Rick

15+ years of experience having fun building apps with .NET I began my professional career in 2006, using Microsoft technologies where C# and Windows Forms and WPF were the first technologies I started working with during that time. I had the opportunity to actively participate in the Windows ecosystem as an MVP and Windows 8/Windows Phone application developer from 2013-2018. Throughout my career, I have used Azure as my default cloud platform and have primarily worked with technologies like ASP.NET Core for multiple companies globally across the US, UK, Korea, Japan, and Latin America. I have extensive experience with frameworks such as: ASP.NET Core Microsoft Orleans WPF UWP React with TypeScript Reactive Extensions Blazor I am an entrepreneur, speaker, and love traveling the world. I created this blog to share my experience with new generations and to publish all the technical resources that I had been writing privately, now made public as a contribution to enrich the ecosystem in which I have developed my career.