Creating a Custom Template

Today’s header image was created by Frank McKenna at Unsplash
I’ve talked about .NET Core’s shiny new templating system before, and even covered using their Angular template. But those were always making use of someone else’s template.
Recently I built and open sourced
because of course I did
my own .NET Core template, and in this article I’ll show you how I did it.
if you want to skip the whole article and get straight to the template, you can find it here
Template Creation
The boffins at Microsoft have realised that most of the templates that we need are built from pre-existing code bases.
perhaps your organisation or group has a pre-existing .NET Framework template? We can use that with .NET Core, but with a few tweaks.
This means that you can stub out the structure and workflow for most of your projects within the template before having others use it. Once you’ve done that, it’s a case of adding a file called template.config
and running a console command.
It’s really quite simple, and if you follow along, you’ll see just how simple it is.
But first…
psst, if you want to skip directly to converting a solution to a template, click here
Introducing: FullStackTemplate
I’d noticed that I was spending time writing a lot of common, boilerplate code when setting up new solutions. So I decided to create my own template: FullStackTemplate
I started by looking at the common code and structure among all of my pre-existing solutions, extracting what was common. I then took a look at some suggested best practises for .NET Core application organisation.
“application organisation” is fun to say. Say it with me
Which lead me to a talk by K. Scott Allen (of OdeToCode) from this year’s NDC in London.
if you’re reading this in the future, “this year” is 2017
I’ll embed the full talk here:
He raises some very interesting points (and a few that you should be doing anyway, like bundling with WebPack)
hey, I’ve written about that before
The talk was given back before .NET Core 2.0 was in preview, but most of the points are still valid for .NET Core 2.0. It’s also an hour long, so it’ll take some time to sit through the whole thing, but it’s totally worth it. K. Scott Allen really knows his stuff and has a lot of useful advice.
If audio is more your thing, then I’d check out this episode of .NET Rocks!
I’d also really recommend .NET Rocks! as it’s a fantastic podcast
From that, I took some time to refactor my Startup class, add Feature folders and use Façades rather than mediators.
for a quick description of the difference between these patterns, take a look at this Stack Overflow answer
I also decided to target .NET Core 2.0, ASP.NET Core 2.0 and EF Core 2.0.
and all the other common libraries, at version 2.0
Before I talk about how to use the template, I thought I’d talk through it a little. So without further ado:
Startup class
if you want to skip straight to installing and using the template, click here
Taking details directly out of K. Scott Allen’s approach, I decided to clean up my Startup class by using extension methods.
Here’s the cleaned up (.NET Core 2.0 Startup class in my template):
using ClacksMiddleware.Extensions; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
namespace FullStackTemplate.UI | |
{ | |
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
Configuration = configuration; | |
} | |
public IConfiguration Configuration { get; } | |
// This method gets called by the runtime. Use this method to add services to the container. | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddDbContext(); | |
services.AddTransientServices(); | |
services.AddFacades(); | |
services.AddCustomizedMvc(); | |
services.AddFeatureFolders(); | |
} | |
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |
{ | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
} | |
else | |
{ | |
app.UseExceptionHandler("/Home/Error"); | |
} | |
app.GnuTerryPratchett(); | |
app.UseStaticFiles(); | |
app.UseCustomisedMvc(); | |
} | |
} | |
} |
wait?! What’s GnuTerryPratchett?
The highlighted lines show where I’ve leveraged extension methods to clear up the Startup class by implementing the Newpaper Metaphor.
Here’s a description of the Newspaper metaphor, taken from Mona’s Learning Blog:
code should read like a newspaper article. First the title, then the introduction, only later the details. Name should be simple but explanatory. The article should be short enough to make it attractive to read
source: “Clean Code” Robert C. Martin at Mona’s Learning Blog
if you’ve not read Clean Code but take your career seriously, then I’d recommend that you read it. And soon.
ConfigureServices
The ConfigureServices
method in the Startup class is used to set up the container that our application will use, so the extension methods used in that method are found in the ConfigureContainerExtenstions.cs file. Here’s an example of one of the extension methods (this one adds the Façades):
/// <summary> | |
/// Adds all transient facades into .NET Core's Dependency Injection Service | |
/// </summary> | |
/// <param name="serviceCollection"></param> | |
public static void AddFacades(this IServiceCollection serviceCollection) | |
{ | |
// TODO add more transient facades here | |
// Api Facades | |
serviceCollection.AddTransient<IBaseApiFacade, BaseApiFacade>(); | |
serviceCollection.AddTransient<IDatabaseFacade, DatabaseFacade>(); | |
// Feature Facades | |
serviceCollection.AddTransient<IHomeFacade, HomeFacade>(); | |
} |
Before we continue our look at the Startup class, let’s take a look at Feature Folders.
Feature Folders
Feature Folders are a great way to use MVC’s routing to collect as much of our MVC code together in single units.
as you’ll soon see, Feature Folders is a little like Areas
In traditional MVC, you might have something like the following:

In this example, if you want to add some new properties to a model, you need to visit:
- The Models directory (to add the properties to the model)
- The Controllers directory (to populate the new properties on the model)
- The Views directory (to consume the new properties on the model)
And that’s assuming that you’re consuming the view model in one View.
I’ve seen the same view model being consumed across multiple different views (in different view directories) before
If all of the affected files are related to the same view, then why not have them collected together?
That’s where Feature Folders comes in.
I prefer “directory” over “folder”, but I’ll stick with folder for consistency
In Feature Folders we take all of the Controllers, Views and Models for a given feature (say, the Home pages) and put them into a single directory. An example of an MVC app using feature folders would be:

This isn’t for everyone, but I really like this layout.
Back To The Startup Class
Taking a look at the AddFeatureFolders
extension method:
/// <summary> | |
/// Adds rules to the <see cref="RazorViewEngineOptions"/> for dealing with Feature Folders | |
/// </summary> | |
/// <param name="serviceCollection"> | |
/// The <see cref="IServiceCollection"/> created in <see cref="Startup.ConfigureServices"/> | |
/// </param> | |
public static void AddFeatureFolders(this IServiceCollection serviceCollection) | |
{ | |
serviceCollection.Configure<RazorViewEngineOptions>(options => | |
{ | |
options.ViewLocationExpanders.Add(new FeatureLocationExpander()); | |
}); | |
} |
Here I’m making use of the RazorViewEngineOptions
class to set up ASP.NET Core’s view routing for our Feature Folders.
This is different from MVC routing. The list of view location expanders is what Razor uses to figure out out where to look for the controllers, views and models for our request.
I’m passing in the output of the FeatureLocationExpander
class into the ViewLocationExpanders
property on the RazorViewOptions class.
Here’s what the FeatureLocationExpander looks like:
using System.Collections.Generic; | |
using JetBrains.Annotations; | |
using Microsoft.AspNetCore.Mvc.Razor; | |
[assembly: AspMvcViewLocationFormat("~/Api/{1}{0}.cshtml")] | |
[assembly: AspMvcViewLocationFormat("~/Features/{1}/{0}.cshtml")] | |
[assembly: AspMvcViewLocationFormat("~/Features/Shared/{0}.cshtml")] | |
namespace FullStackTemplate.UI | |
{ | |
/// <summary> | |
/// Used to apply Features directories (rather than separate Controller, Model | |
/// and View directories). | |
/// </summary> | |
/// <remarks> | |
/// See: https://scottsauber.com/2016/04/25/feature-folder-structure-in-asp-net-core/ | |
/// </remarks> | |
public class FeatureLocationExpander : IViewLocationExpander | |
{ | |
public void PopulateValues(ViewLocationExpanderContext context) | |
{ | |
// Don't need anything here, but required by the interface | |
} | |
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) | |
{ | |
// The old locations are /Views/{1}/{0}.cshtml and /Views/Shared/{0}.cshtml | |
// where {1} is the controller and {0} is the name of the View | |
// Replace /Views with /Features | |
return new string[] | |
{ | |
"/Api/{1}/{0}.cshtml", | |
"/Features/{1}/{0}.cshtml", | |
"/Features/Shared/{0}.cshtml" | |
}; | |
} | |
} | |
} |
The first highlighted section is a fix for ReSharper. Without this fix ReSharper, and by extension Rider
which I would recommend to anyone
would complain that the models, views and controllers could not be found. This isn’t required for .NET Core, but it’s nice to not have the dev tools complain at you.
The ExpandViewLocations
method returns a list of places for ASP.NET Core’s view routing to look in order to build the responses to incoming requests.
i.e where the models, views and controllers are
Configure
The Configure
method in the Startup class is used to set up the HTTP Pipeline that our application will use, so the extension methods used in that method are found in the ConfigureHttpPipelineExtentions.cs file. Let’s take another look at the contents of the Configure
method in the Startup class:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |
{ | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
} | |
else | |
{ | |
app.UseExceptionHandler("/Home/Error"); | |
} | |
app.GnuTerryPratchett(); | |
app.UseStaticFiles(); | |
app.UseCustomisedMvc(); | |
} |
the keen eye’d among you will notice a cheeky reference to one of my NuGet packages
There is currently only one method in the ConfigureHttpPipelineExtentions
class, and that is for adding customised MVC routes:
using Microsoft.AspNetCore.Builder; | |
using Microsoft.Extensions.DependencyInjection; | |
using FullStackTemplate.Persistence; | |
namespace FullStackTemplate.UI | |
{ | |
/// <summary> | |
/// This class is based on some of the suggestions bty K. Scott Allen in | |
/// his NDC 2017 talk https://www.youtube.com/watch?v=6Fi5dRVxOvc | |
/// </summary> | |
public static class ConfigureHttpPipelineExtentions | |
{ | |
public static void UseCustomisedMvc(this IApplicationBuilder applicationBuilder) | |
{ | |
applicationBuilder.UseMvc(routes => | |
{ | |
routes.MapRoute( | |
name: "default", | |
template: "{controller=Home}/{action=Index}/{id?}"); | |
}); | |
} | |
} | |
} |
I agree that this is the standard MVC route, but the idea is that a consuming user could edit the contents of this method to suit their application’s requirements.
Façades
I’d decided on using Façades for controllers because it maintains the single responsibility principle, and moves all non-controller code out of the controllers.
I’ve seen quite a few MVC code bases where the Controllers did a lot of non-Controller stuff. By that I mean something like this
[Route("/[controller]") | |
public class EmployeesController : Controller | |
{ | |
public IActionResult UpdateEmployee(EmployeeViewModel employeeData) | |
{ | |
// get record from database | |
var dbEmployee = _employeeService.GetOrCreate(employeeData.id); | |
// do a bunch of validation | |
if (string.IsNullOrWhiteSpace(employeeData.GivenName)) | |
{ | |
throw new ArgumentException($"nameOf({employeeData.GivenName}) is required"); | |
} | |
else if (string.IsNullOrWhiteSpace(employeeData.FamilyName)) | |
{ | |
throw new ArgumentException($"nameOf({employeeData.FamilyName}) is required"); | |
} | |
// etc... | |
else | |
{ | |
dbEmployee.GivenName = employeeData.GivenName; | |
dbEmployee.FamilyName = employeeData.FamilyName; | |
dbEmployee.SocialSecurityNumber = employeeData.SocialSecurityNumber; | |
// a bunch of other properties later | |
// update the entity in the database | |
_employeeService.AddOrUpdate(dbEmployee); | |
_employeeService.SaveData(); | |
} | |
// re-direct the user to the relevant view | |
return View(); | |
} | |
} |
and yes, that’s based on a real controller method I once found.
What’s not so great about the above controller method is that of the 40 lines of code in the method, there is only one line which needs to be there.
can you guess which one it is?
What a controller should do (in my opinion), is it should take in the data from the client side, do validation on it, and return a response. Everything else should be the responsibility of some other service.
Currently, the above version of the controller method needs access to:
- The Employee ViewModel
- The Employee DB Entity Model
- The Employee service
And that is two things too many.
So let’s reduce the surface area of the controller. What I’m about to show you is controversial, and I’ll talk you though why it’s controversial after I’ve shown you it.
The first thing should do is make the controller simpler:
[Route("/[controller]") | |
public class EmployeesController : Controller | |
{ | |
public IActionResult UpdateEmployee(EmployeeViewModel employeeData) | |
{ | |
// do a bunch of validation | |
if (!employeeData.Validate()) | |
{ | |
// we've want to do something more relevant here. This is | |
// an example after all | |
return StatusCode(500); | |
} | |
var status = _employeeFacade.UpdateEmployee(employeeData); | |
// re-direct the user to the relevant view | |
return View(status); | |
} | |
} |
Anyone looking at this controller method can see, at a glance, what it does. It follows both the single responsibility principle (by taking the request, generating a response, and having something else deal with all the middle bits), and the Newspaper metaphor (as you can read it easily, or choose to drill down to get the details).
The validator could be as simple (and badly written) as this:
public static class EmployeeViewModelValidator | |
{ | |
public static bool Validate(this EmployeeviewModel employeeviewModel) | |
{ | |
if (string.IsNullOrWhiteSpace(employeeData.GivenName)) | |
{ | |
return false; | |
} | |
if (string.IsNullOrWhiteSpace(employeeData.FamilyName)) | |
{ | |
return false; | |
} | |
// etc. | |
return true; | |
} | |
} |
It wouldn’t really matter, because the controller doesn’t need to know.
having a separate validation method is called a Guard Clause or Method. For more on Guard Clauses, I’d recommend this episode of Weekly Dev Tips by Steve Smith (yes, THAT Steve Smith)
And the Façade could also follow the same principles by looking like this:
public class EmployeeFacade | |
{ | |
private readonly IEmployeeService _employeeService; | |
public EmployeeFacade(IEmployeeFacade employeeFacade) | |
{ | |
_employeeFacade = employeeFacade; | |
} | |
public UpdateStatus UpdateEmployee(EmployeeviewModel employeeData) | |
{ | |
// get record from database | |
var dbEmployee = _employeeService.GetOrCreate(employeeData.id); | |
// update the database model | |
dbEmployee.UpdateDbModel(employeeData); | |
// update the entity in the database | |
_employeeService.AddOrUpdate(dbEmployee); | |
return _employeeService.SaveData(); | |
} | |
} |
With the mapper looking like this:
public static class EmployeeMapper | |
{ | |
public static void UpdateDbModel (this EmployeeDbEntity dbEmployee, EmployeeViewModel viewModel) | |
{ | |
dbEmployee.GivenName = employeeData.GivenName; | |
dbEmployee.FamilyName = employeeData.FamilyName; | |
dbEmployee.SocialSecurityNumber = employeeData.SocialSecurityNumber; | |
// etc. | |
} | |
} |
Why The Controversy?
This is a controversial model because you still have to do the work, down the line; and you run the risk of separating things out and making them more complex. It also means that you have to traverse through several files and layers of abstraction to get a full understanding of how the whole façade method works.
I feel like it’s worth the effort to read through the façade, though. As it helps to hide away as much detail as possible. But that’s just my personal opinion.
Converting A Solution Into A Template
Now that I’ve talked through FullStackTemplate, it’s time for the main attraction.
drums, please
So you want to take as pre-existing template and make it into a template, increasing the speed at which you can make your amazing applications? Look no further.
The first thing we need to do is to prepare the solution. This is why I specifically built FullStackTemplate, but you can use any pre-existing template you wish. This might include cleaning up or removing some code, but it’s easy enough to do and out of the scope of this article.
Once your solution is in the right shape and is ready to be converted into a template, we need to create a Unix style hidden directory.
If you’re a Windows user, this does not mean right-clicking and setting the directory to hidden in it’s properties. In Unix-like operating systems, you can hide a directory by prefixing it’s name with a dot (or ‘.’ character). For example: “.userSecrets” is a Unix-style hidden directory.
for more on Unix-style hidden directories, take a look at this wiki article
The hidden directory needs to be called .template.config
and needs to be placed in the root of the solution directory. For example:

In the above screenshot, the red arrow is pointing at the .template.config
directory.
you’ll may need to show hidden directories in your file explorer
This is an important directory and will contain the config for your template
talk about bleeding obvious
and within this directory, we need to add a file called template.json
.
Here is the template.json file for FullStackTemplate:
{ | |
"author": "Jamie Taylor", | |
"classifications": ["Web"], | |
"name": "Full Stack Template", | |
"identity": "FullStack.Template", | |
"shortName": "fullstack", | |
"tags": { | |
"language": "C#" | |
}, | |
"sourceName": "FullStackTemplate", | |
"preferNameDirectory": "true" | |
} |
Let’s talk a walk through this file
it wont take long, honest
template.json
{ | |
"author": "Jamie Taylor", | |
"classifications": ["Web"], | |
"name": "Full Stack Template", | |
"identity": "FullStack.Template", | |
"shortName": "fullstack", | |
"tags": { | |
"language": "C#" | |
}, | |
"sourceName": "FullStackTemplate", | |
"preferNameDirectory": "true" | |
} |
I’ve highlighted the lines of code which are used by the output of dotnet new --list
.
classifications
is an array and is used in the tags list for the templatename
(surprisingly) is the name of the templateidentity
is used as a namespace-like id for the templateshortname
is used as a handy short name for the template
gotta save those key strokes
tags
is a useful array of properties for sorting and ordering our templatessourcename
this is the most powerful of the above properties
The sourcename
property is used by the .NET Core SDK as a find and replace key to ensure that solutions created with the template all have the correct names for projects and namespaces.
Using FullStackTemplate as an example, whenever we create a new solution from this template
more on that in a moment
FullStackTemplate
will be replaced, across all of the files created, with the name that we supply for the new solution.
Installing A Local Template
Assuming that we’ve created the template solution and filled in the template.json
file in the .template.config
directory, all we have to do is issue a command based on the following:
dotnet new --install /path/to/parent/of/.template.config |
Where /path/to/parent/of/.template.config
is the path to the root directory of the template solution.
As a more concrete example, here is the command I would run on my machine, in order to install FullStackTemplate:
dotnet new --install ~/Code/FullStackTemplate/ |
This works because I have all of my code cloned down to ~/Code
for Windows users, this is the equivalent of my Users directory, with a sub-directory called Code
When that command has completed, you’ll see the following output:
Templates Short Name Language Tags | |
-------------------------------------------------------------------------------------------------------- | |
Console Application console [C#], F#, VB Common/Console | |
Class library classlib [C#], F#, VB Common/Library | |
Unit Test Project mstest [C#], F#, VB Test/MSTest | |
xUnit Test Project xunit [C#], F#, VB Test/xUnit | |
Full Stack Template fullstack [C#] Web | |
ASP.NET Core Empty web [C#], F# Web/Empty | |
ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC | |
ASP.NET Core Web App razor [C#] Web/MVC/Razor Pages | |
ASP.NET Core with Angular angular [C#] Web/MVC/SPA | |
ASP.NET Core with React.js react [C#] Web/MVC/SPA | |
ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA | |
ASP.NET Core Web API webapi [C#], F# Web/WebAPI | |
global.json file globaljson Config | |
Nuget Config nugetconfig Config | |
Web Config webconfig Config | |
Solution File sln Solution | |
Razor Page page Web/ASP.NET | |
MVC ViewImports viewimports Web/ASP.NET | |
MVC ViewStart viewstart Web/ASP.NET |
Which is the same as running dotnet new --list
.
Using the Template
Using the new template from the terminal is extremely simple. Once it’s installed, run the following command:
dotnet new templateName --name MyProject |
Substituting the shortname property for FullStackTemplate into the above (and using a useful name), we get the following command:
dotnet new fullStack --name fullStackDemo |
Which should respond with something similar to the following:
The template "Full Stack Template" was created successfully. |
Uninstalling the Template
The time may come when you need to retire the template
for whatever reason
and doing that is almost as simple as installing it in the first place. Here is the vague version of the command:
dotnet new --uninstall /path/to/parent/of/.template.config |
And here is the version of the command I would run to remove FullStackTemplate:
dotnet new --uninstall ~/Code/FullStackTemplate/ |
remember, I have my code cloned down to ~/Code
And that’s about it.
External Resources
For more information on creating templates in .NET Core, I’d check out the following resources:
I’d start here, as this is the repo for the templating engine and there are links to a number of the popular templates which you can install from the terminal.
This goes into more depth about some of the things you can do with templates (like conditional includes, parameters, and all sorts of cool stuff).
If videos are more your thing, then I would check out this video of Sayed talking Jon Galloway through the process of creating a template (almost from scratch).
Have you created any .NET Core 2.0 templates? Are they open or closed source? I’ve shown you mine, care you share yours?
ooh er
Would you be more willing to create your own templates now that you know how?
What do you think of FullStackTemplate? How would you improve it?
Pull requests are welcome, so if there’s something which could be improved then please do
Let me know in the comments and let’s keep the conversation going.