Starting a Paved Path with .NET Templates

“Good templates are like good habits – they make doing the right thing easy and automatic.” – Scott Hanselman, Principal Program Manager at Microsoft

In our previous post, we introduced the concept of paved paths as a solution to the challenges posed by monolithic architectures and mono repos. Today, we’re going to dive into the technical details of how to implement a key component of paved paths: new project templates. We’ll use .NET as our example, demonstrating how to create custom templates that embody your organization’s best practices and preferred setup.

Why .NET Templates?

.NET templates are an excellent tool for implementing paved paths because they allow you to:

  1. Standardize project structure and initial setup
  2. Embed best practices and common configurations
  3. Quickly bootstrap new services or applications
  4. Ensure consistency across different teams and projects

Getting Started with .NET Templates

The .NET CLI provides a powerful templating engine that we can leverage to create our paved path templates. Let’s walk through the process of creating a custom template.

Step 1: Create a Template Project

First, let’s create a new project that will serve as our template:

dotnet new webapi -n MyCompany.Template.WebApi

This creates a new Web API project that we’ll customize to serve as our template.

Step 2: Customize the Template

Now, let’s make some modifications to this project to align it with our organization’s standards. For example:

  1. Add common NuGet packages
  2. Set up a standard folder structure
  3. Add common middleware or services
  4. Configure logging and monitoring

Here’s an example of how you might modify the Program.cs file:

using MyCompany.Shared.Logging;
using MyCompany.Shared.Monitoring;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Add MyCompany standard services
builder.Services.AddMyCompanyLogging();
builder.Services.AddMyCompanyMonitoring();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

// Use MyCompany standard middleware
app.UseMyCompanyLogging();
app.UseMyCompanyMonitoring();

app.Run();

Step 3: Create Template Configuration

Next, we need to add a special configuration file that tells the .NET CLI how to treat this project as a template. Create a new folder in your project called .template.config, and inside it, create a file called template.json:

{
  "$schema": "http://json.schemastore.org/template",
  "author": "Your Name",
  "classifications": [ "Web", "WebAPI" ],
  "name": "MyCompany Web API",
  "identity": "MyCompany.WebApi.Template",
  "groupIdentity": "MyCompany.WebApi",
  "shortName": "mycompany-webapi",
  "tags": {
    "language": "C#",
    "type": "project"
  },
  "sourceName": "MyCompany.Template.WebApi",
  "preferNameDirectory": true
}

This configuration file defines metadata about your template and tells the .NET CLI how to use it.

Step 4: Package the Template

Now that we have our template project set up, we need to package it for distribution. We can do this by creating a NuGet package. Add the following to your .csproj file:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <PackageType>Template</PackageType>
    <PackageVersion>1.0</PackageVersion>
    <PackageId>MyCompany.WebApi.Template</PackageId>
    <Title>MyCompany Web API Template</Title>
    <Authors>Your Name</Authors>
    <Description>Web API template for MyCompany projects</Description>
    <PackageTags>dotnet-new;templates;mycompany</PackageTags>

    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <IncludeContentInPack>true</IncludeContentInPack>
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <ContentTargetFolders>content</ContentTargetFolders>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="**\*" Exclude="**\bin\**;**\obj\**" />
    <Compile Remove="**\*" />
  </ItemGroup>
</Project>

Step 5: Build and Pack the Template

Now you can build and pack your template:

dotnet pack

This will create a NuGet package in the bin/Debug or bin/Release folder, depending on your build configuration.

Step 6: Install and Use the Template

To use your new template, you first need to publish it to your internal nuget server and then you can install:

dotnet new -i MyCompany.WebApi.Template --nuget-source https://your.internal.nuget

Now you can use your template to create new projects:

dotnet new mycompany-webapi -n MyNewWebApi

Maintaining and Updating Templates

As your organization’s needs evolve, you’ll want to update your templates. Here are some tips for maintaining your templates:

  1. Version your templates and keep a changelog
  2. Regularly review and update dependencies
  3. Collect feedback from developers using the templates
  4. Consider creating multiple templates for different use cases

Conclusion

By creating custom .NET templates, we’ve taken a significant step in implementing paved paths in our organization. These templates encapsulate our best practices, preferred project structure, and common configurations, making it easy for developers to start new projects that align with our standards.

Remember, templates are just one part of a paved path strategy. In future posts, we’ll explore other aspects such as shared libraries, infrastructure as code, and CI/CD pipelines. Stay tuned!

Leave a comment