Category: Software Development

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

Automatic Binding of Settings Classes to Configuration

I’ve had the idea to do this for a while now. It usually pops back into my head when I start a new project and I have to read configuration information into the application. Microsoft’s IOptions<T> is nice, but there is still a bit of ceremony in having to bind each class to it’s configuration in Startup.cs. It seemed like I should just be able to tell the system in some light-weight, unobtrusive way where to get this configuration from and be done with it.

The Dream

So what is this magical “light-weight, unobtrusive way” you speak of? Well, I’m glad you asked! My thought was to create a NuGet package so that I could just plug it into any project, add an attribute to my settings class(es), and set a single constructor parameter that was the section of the configuration to bind it to. Something like this:

    [AutoBind("Features")]
    public class Features
    {
        public bool IsCoolFeatureEnabled { get; set; }
        public int CoolFeatureCount { get; set; }
        public bool IsUberFeatureEnabled { get; set; }
        public bool IsSecretFeatureEnabled { get; set; }
    }

In my magical world that should automatically bind to a section in my configuration named “Features”.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Features": {
    "IsCoolFeatureEnabled": true,
    "CoolFeatureCount": 4,
    "IsUberFeatureEnabled": true,
    "IsSecretFeatureEnabled": false 
  },
  "AllowedHosts": "*"
}

Then, for example, I could inject an instance of “Features” into a controller and use them to control the availability of features in my application (for example). In this case I’m just going to pass the settings (“Features”) to my view to control the layout of the page like so:

    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly Features _features;

        public HomeController(ILogger<HomeController> logger, Features features)
        {
            _logger = logger??throw new ArgumentNullException(nameof(logger));
            _features = features ?? throw new ArgumentNullException(nameof(features));
        }

        public IActionResult Index()
        {
            return View(_features);
        }

        ...
    }

The Startup Code (“The Glue”)

The only “glue” to hold all this together is a little one-liner in the Startup.cs file’s ConfigureServices method, that you only have to make once. You don’t have to go back to the startup each time you want to configure a new class for configuration settings.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAutoBoundConfigurations(Configuration).FromAssembly(typeof(Program).Assembly);
        services.AddControllersWithViews();
    }

The AddAutoBoundConfigurations(…) method sets up a builder with your configuration root. Each time you call FromAssembly(…) using the fluent API it will scan that assembly for any classes with the AutoBind attribute, create an instance, bind it to your configuration, and configure it as a singleton for dependency injection.

The fluent API also exposes a Services property which will allow you to chain back into the services fluent API to continue your setup if you wish to like this.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAutoBoundConfigurations(Configuration)
                .FromAssembly(typeof(Program).Assembly)
                .Services
                .AddControllersWithViews();
    }

Wrapping it up – Back to the View

I’ve created a view that uses the “Features” settings to enable features (OK, they’re just div tags on the page, but you get the idea.) and to control the number of CoolFeatures that are on the page. Here’s the razor view:

@model AutoBind.Demo.Settings.Features
@{
    ViewData["Title"] = "Home Page";
}
    <div class="row">
        <div class="col-sm-12 mb-5">
            <h1 class="text-4">Features</h1>
        </div>
    </div>
    <div class="row">
    @if (Model.IsCoolFeatureEnabled)
    {
        @for (int index = 1; index <= Model.CoolFeatureCount; index++)
        {
            <div class="col-sm-4">
                <div class="card text-white bg-info mb-3">
                    <div class="card-header">Cool Feature # @index</div>
                    <div class="card-body">
                        <p class="card-text">Here's my cool feature!</p>
                    </div>
                </div>
            </div>
        }
    }
    @if (Model.IsUberFeatureEnabled)
    {
        <div class="col-sm-4">
            <div class="card text-white bg-dark mb-3">
                <div class="card-header">Uber Feature</div>
                <div class="card-body">
                    <p class="card-text">Here's my uber feature!</p>
                </div>
            </div>
        </div>
    }
    @if (Model.IsSecretFeatureEnabled)
    {
        <div class="col-sm-4">
            <div class="card text-white bg-warning mb-3">
                <div class="card-header">Secret Feature</div>
                <div class="card-body">
                    <p class="card-text">Here's my secret feature!</p>
                </div>
            </div>
        </div>
    }
    </div>

Here’s what the rendered page looks like in the browser:

Screenshot

Summary

This is a simple example, but in larger projects with lots of configuration its nice to be able to quickly create and use your configuration settings classes without having to deal with the plumbing.

The package is available on NuGet.org. You can install it in your projects from Visual Studio by searching for the package DotNetNinja.AutoBoundConfiguration or install it from the command line with:

dotnet add package DotNetNinja.AutoBoundConfiguration

The source is available on GitHub @ https://github.com/DotNet-Ninja/DotNetNinja.AutoBoundConfiguration.

Using Libman – The New Visual Studio Library Manager

Libman or “Library Manager” is a new tool built into Visual Studio 2017 (version 15.8+) for managing simple client side dependencies. For example, if you just want to create a simple ASP.NET Core MVC web application with Bootstrap 4, you can quickly and easily pull in just the CSS and JavaScript files you need, and you can put them where you want them. Unlike the old days when we pulled in client side packages using the NuGet Package Manager and the package maker decided where the files went and you just had to deal with it (or deal with the consequences of moving them) or today when using NPM where everything goes into the node_modules folder, with Libman you get to choose where the files go in your project. Not only can you choose where the files go, but you can choose exactly the files you want and ignore the rest if you don’t need them in your project. Obviously there are still plenty of scenarios where NPM fits the bill perfectly, but for the projects where you just want to manage a few of small dependencies and you want to keep it “lean and mean”, Libman may just be the right choice.

Managing Libraries Using the GUI

You can add/manage files with the Library Manager in a couple of different ways.

The first way is through the dialog which can be invoked by right clicking on a folder in the solution and selecting “Add..” and then “Client Side Library…” from the context menu. As an example, lets say we want to update all of our libraries in the lib folder @ -/wwwroot/lib to be managed by Libman. (You’ll want to clean out the folder first if you are going to use Libman to manage all of your libraries.)

  • Right click on the lib folder in -/wwwroot and select “Add..” and then “Client Side Library…”
  • A dialog will open allowing you to select the library you would like to pull in.
    • Choose a provider (More on this in a bit, we’ll leave it on cdnjs for now)
    • Start typing the name of the library (jQuery in this case), you’ll get intellisense to help you find the packages available.
      • Be sure to use tab to complete the library selection. This will fill in the version and populate the files list.
      • You can also type jquery@ and you’ll get an auto complete list of all the available versions.
  • I usually select “Choose specific files” and select the files I want in my project specifically.
  • “Target Location” will be populated automatically from the location you right clicked on in your project and the name of the library you chose, but you can customize it if you like.
  • And finally, just click install to add the file(s) to you project.

The first time you do this a libman.json file will be created in the root of your project. This acts a lot like the old package.config for NuGet packages in .NET Framework applications in that it keeps track of the relevant settings for Libman and lists all of the libraries being managed by Libman.

In order to replace all of the original libraries you’ll need to do this for each library and update the references to the individual items in the ~/Views/Shared/_Layout.cshtml and the ~/Views/Shared/_ValidationScriptsPartial.cshtml files. (The original libraries and version are jquery@3.3.1, jquery-validate@1.17.0, jquery-validation-unobtrusive@3.2.9, and twitter-bootstrap@3.3.7 .)

Managing Libraries Manually

The second way you can manage libraries is by right clicking the project and selecting “Manage Client-Side Libraries …”. This will open up the libman.json file at the root of your project to be edited. (If libman.json does not exist, one will be created for you.) Here’s an example of a new empty file:

{
  "version": "1.0", 
  "defaultProvider": "cdnjs",
  "libraries": []
} 

To add your first library to this file manually expand the brackets [] after libraries (libraries is an array) and start a new object with braces {}. Inside the braces add four new elements:

  • “provider” – the value for this should be one of the following:
    • “cdnjs” – use cdnjs.com as your provider.
    • “unpkg” – use unpkg.com as your provider.
    • “filesystem” – use your local file system.
  • “location” – The path from the root of your project to put the library files into.
  • “library” – The name of the library
  • “files” – A Json array of file names.

Here’s what it might look like with cdnjs as the provider, the same location we used above (-/wwwroot/lib) for jquery 3.3.1.

{
  "version": "1.0", 
  "defaultProvider": "cdnjs", 
  "libraries": [ 
    {
      "provider": "cdnjs", 
      "destination": "wwwroot/lib/jquery", 
      "library": "jquery@3.3.1", 
      "files": [ 
        "jquery.js", 
        "jquery.min.js", 
        "jquery.min.map"
      ]
    }
  ]
} 

Microsoft has provided a nice editor experience for this file inside Visual Studio. You get autocomplete for just about everything including the library names and file names. If you set the insertion point inside of a library object a light bulb will show up in the margin you can click on or you can use ctrl-. to activate a menu of options to update or uninstall that library. Also notice line 3 “defaultProvider : “cdnjs”? This means that if you omit the provider in a given library then “cdnjs” will be the provider by default. You can also add a line “defaultLocation” : “my/default/path” which will allow you to omit the location in each of the library objects.

Summary

When I read the initial blog post about this new feature there was no GUI at all, just the Json file. At first I wasn’t a fan, but after trying it out and seeing the autocomplete work it began to grow on me. Now I still use the Json editor even with the GUI being available. It’s a simple, but useful tool that does exactly what is needed and nothing more (and I can finally control where my client side dependencies get installed).

Resources

Setting Up Dependency Injection in ASP.NET MVC with AutoFac

There are lots of IOC (Inversion of Control) containers out there that you can use to do dependency injection in your ASP.NET MVC project.  Honestly, most of them are pretty good, and having chosen to use one is really far more important than which one in most cases.  Having said that, there can be some significant differences in performance and features.  I typically use Autofac because it is one of the fastest and it can reliably and automatically call Dispose() on the IDisposables that it creates in a per http request scope.

Adding Autofac To Your Project

Thanks to the magic of NuGet, you can quickly and painlessly add Autofac to your solution and get started.  In my example here I’ll be adding Autofac support to an ASP.NET MVC 5.2 web application with Web API 2.2.  To do that I’ll need to add 2 packages to my project, Autofac ASP.NET MVC 5 Integration (Id: Autofac.Mvc5 / Version: 3.3.3) and Autofac ASP.NET Web API 2.2 Integration (Id: Autofac.WebApi2 / Version: 3.4.0) .  Adding those packages will add the dependent package Autofac (Id: Autofac / Version 3.5.0), which is the actual core Autofac assembly.  Once completed I have the following packages installed:

ASP.NET MVC AutoFac NuGet Packages

Configuring The Container

Now that we have the packages installed we will need to configure our IOC container and register it with the system.  In keeping with the pattern already in place for handling start up application configuration in ASP.NET MVC, I add a DependencyConfig class to the App_Start folder of my MVC project.  This is a static class that has only a single public method named RegisterDependencyResolvers() and two private methods.

public static IContainer RegisterDependencyResolvers()
{
    ContainerBuilder builder = new ContainerBuilder();
    RegisterDependencyMappingDefaults(builder);
    RegisterDependencyMappingOverrides(builder);
    IContainer container = builder.Build();
    // Set Up MVC Dependency Resolver
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    // Set Up WebAPI Resolver
    GlobalConfiguration.Configuration.DependencyResolver= new AutofacWebApiDependencyResolver(container);
    return container;
}

In the above code snippet line 3 creates a container builder that we will use to configure and create our IOC container.  Lines 4 and 5 call our private methods to configure the type mappings our container will use, we’ll circle back to that in just a minute here.  Line 6 actually creates our Autofac container and line 8 registers a new AutofacDependencyResolver (using our container) as the dependency resolver for ASP.NET MVC.  That means that not only have we set up a dependency resolver for services that we need in our code, but also for the services that ASP.NET MVC will need as well.  For example when ASP.NET needs to create an instance of a controller to handle requests to our site, it will use the container we just created to create an instance of that controller (and all of it’s dependencies).  Line 10 does the same thing as line 8, but this time it is registering a dependency resolver with the WebAPI engine.  Finally line 11 returns an instance of the container we created.  I sometimes use this for unit testing that the dependency mappings have been set up correctly.

Registering Types With The Container

In order for the Autofac container to resolve the dependencies we need we’ll need to tell it what to use for the implementation of the service interfaces our items require.  This is not the only way to do this, but it is the way I prefer and it seems to work out pretty well.  In the first method below we are going to create some global registrations to put in place some general rules so we don’t have to explicitly specify the type for every single thing we need.

private static void RegisterDependencyMappingDefaults(ContainerBuilder builder)
{
    Assembly coreAssembly = Assembly.GetAssembly(typeof (IStateManager));
    Assembly webAssembly = Assembly.GetAssembly(typeof (MvcApplication));
    builder.RegisterAssemblyTypes(coreAssembly).AsImplementedInterfaces().InstancePerRequest();
    builder.RegisterAssemblyTypes(webAssembly).AsImplementedInterfaces().InstancePerRequest();

    builder.RegisterControllers(webAssembly);
    builder.RegisterModule(new AutofacWebTypesModule());
}

On lines 3 & 4 I am getting a reference to the assemblies that contain types I want to register in my solution.  In this case I have a core assembly that contains my models and logic and a web assembly which contains my web UI (Controllers, Views, etc…).  Lines 5 & 6 register every type in the assembly as the implementation for any interface they implement.  Let’s assume that I have a class Foo that implements the IBar interface in one of these assemblies.  With this registration I have registered Foo as the implementation of IBar and if I ask the container to resolve an IBar it will give me an instance of Foo.  It also means that if I ask the container to resolve an item that requires an IBar as a constructor parameter that it will create a Foo and pass it into the constructor of the type I am asking for.   The last part of these two lines defines the lifetime or scope of the objects created.  In this case we are specifying InstancePerRequest.  That means that the container will create one instance of any given type per http request and use it to fulfill any requests for that type.  At the end of the request any objects created will be destroyed.  There are a number of scopes you can choose.  InstancePerRequest and SingleInstance are the two I use the most.  See the docs for more details.

Line 8 registers the MVC Controllers in the web assembly so that ASP.NET can use our resolver to resolve them.  Line 9 then registers an Autofac Module with the container that allows the container to resolve certain web types (like HttpContextBase) so that they can be injected into our classes. (This makes it much simpler to mock & unit test our classes that depend on these web types!)

Now that we have our global registration in place we will probably want to be specific in a few cases.  For example, if you have more than one implementation of a given interface you may want to be specific about which one to use (FYI: last one registered wins…), or you may want certain objects to be create in a different scope as I have done below.

private static void RegisterDependencyMappingOverrides(ContainerBuilder builder)
{
    builder.RegisterType<WebSettingManager>().AsImplementedInterfaces().SingleInstance();
}

In this case I have registered the WebSettingManager class as the implementation of it’s interface(s) and set it to use a SingleInstance scope effectively making it a singleton that lives across http requests.

Final Set Up – The Global.Asax

The last thing you will need to do is actually invoke the RegisterDependencyResolvers method during application start up so that everything gets hooked up properly.

In your global.asax file in Application_Start you will need to add one line of code.

DependencyConfig.RegisterDependencyResolvers()

Here is the entire DependencyConfig.cs

public static class DependencyConfig
{
    public static IContainer RegisterDependencyResolvers()
    {
        ContainerBuilder builder = new ContainerBuilder();
        RegisterDependencyMappingDefaults(builder);
        RegisterDependencyMappingOverrides(builder);
        IContainer container = builder.Build();
        // Set Up MVC Dependency Resolver
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        // Set Up WebAPI Resolver
        GlobalConfiguration.Configuration.DependencyResolver=new AutofacWebApiDependencyResolver(container);
        return container;
    }

    private static void RegisterDependencyMappingDefaults(ContainerBuilder builder)
    {
        Assembly coreAssembly = Assembly.GetAssembly(typeof (IStateManager));
        Assembly webAssembly = Assembly.GetAssembly(typeof (MvcApplication));

        builder.RegisterAssemblyTypes(coreAssembly).AsImplementedInterfaces().InstancePerRequest();
        builder.RegisterAssemblyTypes(webAssembly).AsImplementedInterfaces().InstancePerRequest();

        builder.RegisterControllers(webAssembly);
        builder.RegisterModule(new AutofacWebTypesModule());
    }

    private static void RegisterDependencyMappingOverrides(ContainerBuilder builder)
    {        
        builder.RegisterType<WebSettingManager>AutofacDependencyResolver()
                  .AsImplementedInterfaces().SingleInstance();
    }
}

Resources

Project Home Page: http://autofac.org/

Project Documentation: http://autofac.readthedocs.org/en/latest/#

Project Source Code: https://github.com/autofac/Autofac

NuGet Packages: http://www.nuget.org/packages?q=autofac