Creating Project Templates for dotnet – Part 1 – Getting Started

This is part 1 of a 4 part series of posts


Custom project templates can be a great time saver for you and your team and the can promote a level of consistency across all of your projects. In my experience within any given organization a great deal of effort is wasted every time a new project is started creating the new project, writing plumbing code to handle routine, cross cutting concerns like logging, health checks, authentication/authorization as well as just generally configuring the project layout to conform with your teams practices, importing common libraries & corporate style sheets, setting up continuous integration pipelines etc. By doing all this once up front and baking it into a project template you can save that time each time a new project is started and the team can get down to providing actual business value almost immediately.

For this post I’m going to walk through creating a new template for an ASP.NET 5.0 MVC Web Application. We’ll start off with the default template and modify from there over the next few posts.

Getting Started / Setting Up the Project Structure

To get started we’ll create a new repository in source control (GitHub in my case) and clone it.

Initial Repository Listing

Next we let’s add a src folder and in that folder we’ll add a content folder that will contain the contents of our template. Ultimately this content folder will become the content folder within a NuGet package for our template.

md src
cd src
md content
cd content

When my template is run, I want it to create a src folder with my web application in it and a tests folder with my unit tests. To accomplish that we’ll create a new src folder and then use the existing, out of the box MVC template and then create a tests folder and use the existing, out of the box Xunit template.

md src
cd src
dotnet new mvc -n DotNetNinja.Templates.Mvc
cd ..
md tests
cd tests
dotnet new xunit -n DotNetNinja.Templates.Mvc.Tests
cd ..

Now let’s create a solution file, add the projects to it and create the project reference from the unit tests to the web project.

dotnet new sln -n DotNetNinja.Templates.Mvc
dotnet sln add .\src\DotNetNinja.Templates.Mvc
dotnet sln add .\tests\DotNetNinja.Templates.Mvc.Tests
dotnet add .\tests\DotNetNinja.Templates.Mvc.Tests reference .\src\DotNetNinja.Templates.Mvc

At this point we should have a fully working solution created. One of the great things about the new template system is that your templates are actually functioning projects that can be built and run. That also means that all of the tools that you use for day to day development like Intellisense, syntax highlighting, and tools like Resharper can all be used during your template development process making it much easier and more intuitive to create quality templates.

Now that we have scaffolded out the entire solution we can go ahead and open it up in Visual Studio and see what we have to start with.

Making Our Solution a Template

Having laid out the basic structure we are looking for we have a good foundation. Let’s go ahead and convert it to a template. In our content folder we’ll need to add a .template.config folder and place a template.json file in that folder.

md .template.config
cd .template.config
New-Item template.json

Next let’s open the template.json file up, add in our basic template definition and take a look at what we have.

{    
    "$schema": "http://json.schemastore.org/template",
    "author": "Larry House",
    "classifications": [ "Web" ],
    "name": "DotNetNinja MVC Template",
    "identity": "DotNetNinja.Templates.Mvc",        
    "shortName": "ninjamvc",                 
    "tags": {
        "language": "C#",    
        "type": "project"                 
    },
    "sourceName": "DotNetNinja.Templates.Mvc",
    "preferNameDirectory" : true
}
  • $schema: Sets the json schema and gives us intellisense for our json file.
  • author: Sets the author of the template.
  • classifications: An array of project types. This can be used for filtering in the Visual Studio new project dialog.
  • name: Is the friendly/display name for the template.
  • identity: Is a unique identifier for the template, I typically use the NuGet package id here.
  • shortName: is the short name for the template that is used to invoke it with dotnet new (ex. dotnet new ninjamvc)
  • tags: Tags for the template. These show up in the dotnet new list and can be used to filter in Visual Studio as well.
  • sourceName: This one is important as it specifies the name/value in the source to be automatically replaced with the name of the generated project. Typically that includes the project name, project file name, default namespace etc.
  • preferNameDirectory: This should generally be set to true for most templates. It determines if the directory name is used as the project name when a name is not specified.

That covers what is required in the template.json file to make a template and it this point we technically have a working template. You can install a template from a directory just the way we have it laid out, however the normal means of delivering a template is to package it up as a NuGet package.

Packaging the Template

To package up our template as a NuGet package for consumption we’ll need to add a nuspec file to the solution and then use the nuget pack command to package it up. To perform these steps you’ll need to have the NuGet cli installed and available on your path. (downloads | documentation)

You can generate a nuspec file and then modify it as needed by using the nuget spec command. (Or you can just copy the nuspec below and modify to fit your needs)

nuget spec DotNetNinja.Templates.Mvc

Here is my modified nuspec ready to go. (Note the template version is in this file. You will want to update that version with each release of your template!)

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
  <metadata>
    <id>DotNetNinja.Templates.Mvc</id>
    <version>1.0.0</version>
    <description>
      Template for creating an ASP.NET Core MVC Solution
    </description>
    <authors>Larry House</authors>
    <license type="expression">MIT</license>
    <packageTypes>
      <packageType name="Template" />
    </packageTypes>
  </metadata>
  <files>
    <file src="Content\**\*.*" exclude="Content\**\bin\**\*.*;Content\**\obj\**\*.*" target="Content" />
  </files>  
</package>

We will place this file in our outer src folder (at the same level as our content folder) so it is outside our template.

To package the template navigate to the root of your repository and run a nuget pack command pointed to your nuspec file.

nuget pack .\src\DotNetNinja.Templates.Mvc.nuspec -OutputDirectory C:\Packages\NuGet

Note: I have a local NuGet source set up on my development machine in C:\Packages\NuGet. While this is not strictly required (you can install the template by specifying that path to the package) it does make the workflow easier (and it is convenient for testing other nuget packages). To set this up create the folder you want to use (ex. C:\Packages\NuGet) and run the following command.

nuget source add -Name LocalPackages -Source C:\Packages\NuGet

Being the lazy type ( 🙂 ), I’ve added a PowerShell script named Build-Template.ps1 in the root of my solution and put the nuget pack command in there so I don’t have to type out the full command all the time.

Our package should look something like this:

At this point it is probably a good time to install and do a quick test run of our template and ensure that everything is in order.

Assuming you have published your package to a folder that is a nuget source (as mentioned above) simply run the the following to install the template.

dotnet new -i DotNetNinja.Templates.Mvc

Notice that the new template has the name, short name, language, and tags we specified in our config file earlier. Now let’s run the template and create a new project from it. (You’ll probably want to create a test directory somewhere, don’t run it inside your template. Doing that will make a mess. Trust me.)

dotnet new ninjamvc -n SampleWeb

Here is a look at the Solution Explorer of my generated solution in Visual Studio.

If you look through the project you’ll find that all instances of DotNetNinja.Template.Mvc have been replaced with the name we specified above (SampleWeb). That includes the project names, namespaces, folder names etc.

In the next post we’ll take a look extending the template with optional files.

Resources

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.