ASP .NET 5 Application Configuration, Part 2

In Part 1, we saw how to retrieve basic application settings from a range of formats available in ASP .NET 5. In this article, we will see techniques used for settings that go beyond simple key-value representation.

Getting a Config Section

Let’s say we have this appsettings.json:

{
  "Title": "configuration",
  "DataSettings": {
    "ConnectionString": "SomeConnectionString",
    "AuditDatabaseName": "AuditDB"
  }
}

…and we want to map the DataSettings to the following C# class:

    public class DataSettings
    {
        public string ConnectionString { get; set; }
        public string AuditDatabaseName { get; set; }
    }

We can start with configuration loading code from the Part 1 article:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddJsonFile("appsettings.json");
            Configuration = configurationBuilder.Build();

            // TODO code goes here
        }

At this point, we need to add the following dependency to our project.json:

    "Microsoft.Extensions.OptionsModel": "1.0.0-rc1-final"

Then, in the TODO part in the code above, we can add the following to read the DataSettings section into its strongly-typed C# class equivalent:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddJsonFile("appsettings.json");
            Configuration = configurationBuilder.Build();

            var section = Configuration.GetSection("DataSettings");
            services.Configure<DataSettings>(section);
        }

You may be disappointed to find that this doesn’t give you an object you can use right away. However, what we are doing is putting our config section in the services collection, which is basically ASP .NET 5’s built-in dependency injection. In the next section, we’ll see how we can actually use this.

Note that by reading a config section, you’re basically pulling out only that section from the config. In the example above, the Title setting is not included in the section we read.

Dependency Injection with the Options Model

One of the most important parts of ASP .NET 5 Configuration is the options model, which is just a fancy way of saying dependency injection. By calling services.Configure() in the previous section, we have set up our settings class with dependency injection. So how do we use it?

Let’s make a simple Web API controller to see this in action. In ASP .NET 5, Web API and MVC are the same thing, so we’ll need the MVC package. Also make sure you have the OptionsModel package from the previous section:

    "Microsoft.Extensions.OptionsModel": "1.0.0-rc1-final",
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final"

We’ll need to do some simple setup in Startup.cs for MVC to work:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddJsonFile("appsettings.json");
            Configuration = configurationBuilder.Build();

            var section = Configuration.GetSection("DataSettings");
            services.Configure<DataSettings>(section);

            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.UseMvc();
        }

Finally, we can add our controller:

    [Route("api/[controller]")]
    public class DataController : Controller
    {
        IOptions<DataSettings> dataSettings;

        public DataController(IOptions<DataSettings> dataSettings)
        {
            this.dataSettings = dataSettings;
        }

        public IActionResult Index()
        {
            return new ObjectResult(this.dataSettings.Value.ConnectionString);
        }
    }

Notice how by putting an IOptions<DataSettings> in the constructor, we can get our settings class from the dependency injection framework. Accessing its Value gives us the DataSettings instance that we configured earlier.

Sure enough, it works:

aspnet5-web-api-dependency-injection

Strongly-Typed Configuration from Root

We don’t always need to read just a section. Sometimes, it can be handy to read the whole configuration file.

So let’s say I have these settings classes:

    public class MySettings
    {
        public string Title { get; set; }
        public List<string> SupportedFormats { get; set; }
        public List<Hero> Heroes { get; set; }
    }

    public class Hero
    {
        public string CharacterName { get; set; }
        public string ActorName { get; set; }
    }

Our appsettings.json now contains the following:

{
  "Title": "configuration",
  "SupportedFormats": [ "json", "xml", "ini" ],
  "Heroes": [
    {
      "CharacterName": "Luke Skywalker",
      "ActorName": "Mark Hamill"
    },
    {
      "CharacterName": "Han Solo",
      "ActorName": "Harrison Ford"
    }
  ]
}

Then, I can read all this stuff into MySettings as follows:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddJsonFile("appsettings.json");
            Configuration = configurationBuilder.Build();

            var mySettings = new MySettings();
            Configuration.Bind(mySettings);
        }

And… there you go:

aspnet5-config-from-root

If you take a moment to look at the stuff I put into the appsettings.json, you’ll begin to appreciate just how powerful this is. We can read basic strings, arrays, and even lists of entire objects like this. If you’ve experienced what a pain in the ass it is to read a simple list of data from a key in Web.config with the ASP .NET we’re used to, then this should feel like a breath of fresh air.

Custom Configuration Providers

If none of the default setting file formats match what you need, then you’ll probably need to create your own custom configuration provider. The example in the official docs shows a reasonable example: retrieving settings from a database. Unfortunately, however, that example doesn’t work (at the time of writing this article), because the APIs have changed and the official docs have not been updated.

Just for the sake of example, let’s imagine we want to load a file containing pipe-delimited settings. We’ll work with the following pipeconfig.txt:

key1|value1|key2|value2

Our custom provider class needs to:

  1. Inherit from ConfigurationProvider
  2. Override the Load() method
  3. Set the Data dictionary

Here’s an example of what our pipe-delimited-setting loader could look like:

    public class PipeDelimitedConfigSource : ConfigurationProvider
    {
        private string filename;

        public PipeDelimitedConfigSource(string filename)
        {
            this.filename = filename;
        }

        public override void Load()
        {
            string fileContents = File.ReadAllText(filename);
            string[] tokens = fileContents.Split(new char[] { '|' });

            for (int i = 0; i < tokens.Length; i += 2)
            {
                var key = tokens[i];
                var value = tokens[i + 1];
                this.Data[key] = value;
            }
        }
    }

Then, back in Startup.cs, we can feed it to our ConfigurationBuilder using its Add() method:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            var configSource = new PipeDelimitedConfigSource("../pipeconfig.txt");
            configurationBuilder.Add(configSource);
            Configuration = configurationBuilder.Build();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                var setting1 = this.Configuration["key1"];
                var setting2 = this.Configuration["key2"];
                string output = $"<h1>{setting1}</h1><h2>{setting2}</h2>";

                await context.Response.WriteAsync(output);
            });
        }

Here’s the output:

aspnet5-custom-config-examplet

Config files and wwwroot

Before ASP .NET 5, configuration resided in Web.config. Having a single file makes it easy to configure web servers not to serve it. The flexibility afforded by having different possible formats and source for configuration in ASP .NET 5 thus begs the question: how do we prevent our config files from being served?

This is easy to deal with if we understand the role of the wwwroot folder. Before ASP .NET 5, the project root and the website root were one and the same. In ASP .NET 5, the website root (called wwwroot by default, but configurable) is a subfolder of the project folder. Thus, to keep files out of reach, it is necessary only to keep them out of wwwroot.

This way, the application code will have access to these files, but they will not be served as static files via simple web requests.

The role of web.config

By reading this article and the previous one, you have hopefully learned that there is no longer a standard web.config file that stores all the web application’s settings. With this in mind, you might be a little surprised to find that standard ASP .NET 5 project templates actually come with a web.config in the wwwroot folder.

At the time of writing this article, the contents of the file (although not important here) are the following:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
    </handlers>
    <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600"/>
  </system.webServer>
</configuration>

The reason for the presence of the web.config is explained in this StackOverflow answer, which I quote:

“Web.config is strictly for IIS Configuration. It is not needed unless hosting in IIS. It is not used when you run the app from the command line.

“In the past Web.config was used for both IIS configuration and application configuration and settings. But in asp.net 5 it is not used by the application at all, it is only used for IIS configuration.

“This decoupling of the application from IIS is part of what makes cross platform possible.”

Summary

In this article, we have seen more complex ways in which we can read application configuration. The configuration model in ASP .NET 5 is indeed powerful, as we can map settings files to strongly-typed objects, and pass them on to our controllers via dependency injection. Where necessary, we can extend the range of built-in configuration providers by creating our own.

In the final sections, we have also discussed how to protect settings files from being accidentally served over the web, and why there is a web.config file in wwwroot by default despite ASP .NET 5 doing away with web.config.

ASP .NET 5 Application Configuration, Part 1

ASP .NET 5 moves away from the traditional web.config for storing application configuration. Instead, the configuration itself is configurable, and developers may use a combination of different sources. Support for JSON, XML, INI, environment variables, command-line arguments and in-memory configuration are all available. It is also possible to specify custom configuration sources.

Using JSON Configuration

ASP .NET 5 supports a number of different formats for application settings. The preferred format is JSON. In Visual Studio, you can add a new ASP.NET Configuration File, which by default is called appsettings.json:

aspnet5-add-appsettings.json

Let’s keep things simple for now, so throw out the default contents of appsettings.json and replace them with the following instead:

{
  "title": "My Brand New Website",
  "subtitle": "The one and only"
}

In Startup.cs, we need to set up our configuration. We do this thanks to ConfigurationBuilder as follows:

        private IConfiguration Configuration { get; set; }

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddJsonFile("appsettings.json");
            Configuration = configurationBuilder.Build();
        }

We’ll see more about the capabilities of ConfigurationBuilder shortly, but for now, all we need is JSON support. In this simple example, since we’re going to use configuration directly within the Startup class, we’re putting our configuration in a Configuration property within the same class. Normally, however, we would set up our configuration in the application’s dependency injection so that it can be used elsewhere. We’ll see how to do that later, too.

Now, we just have to actually use that configuration:

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                var title = this.Configuration["title"];
                var subtitle = this.Configuration["subtitle"];
                string output = $"<h1>{title}</h1><h2>{subtitle}</h2>";

                await context.Response.WriteAsync(output);
            });
        }

Don’t understand the funny $ syntax? That’s string interpolation, a new feature in C# 6.

Here’s the output:

aspnet5-example-json-config

Using XML Configuration

XML configuration isn’t going away anytime soon. And although it’s supported by official packages, it’s not so out-of-the-box as many sources claim. To enable XML configuration support, you need to add a NuGet package to your project.json dependencies:

  "dependencies": {
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.Xml": "1.0.0-rc1-final"
  },

Once that is done, a new extension method is available for ConfigurationBuilder that you can use:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddXmlFile("appsettings.xml");
            Configuration = configurationBuilder.Build();
        }

As an example, I’m going to use the following XML file, named appsettings.xml:

<root>
  <title>My XML-driven website</title>
  <subtitle>On a server far, far away</subtitle>
</root>

Without changing the code we added to Configure() in the previous section, here’s the result:

aspnet5-example-xml-config

Using INI Configuration

ASP .NET 5 also supports a simple, medieval configuration format called INI files. Like with XML, these don’t come right out of the box, and you need to add the necessary NuGet package to your project.json‘s dependencies to support them:

  "dependencies": {
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.Xml": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.Ini": "1.0.0-rc1-final"
  },

To see this in action, we need an example INI file, which we will call appsettings.ini, and which will contain the following:

title=Another format!
subtitle=They never end

And as with XML, we need to slightly change our configuration code:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddIniFile("appsettings.ini");
            Configuration = configurationBuilder.Build();
        }

Once again, this works wonderfully:

aspnet5-example-ini-config

Environment Variables

Environment variables can also be used as a source for application settings. We can set things up to actually get our application settings from the environment variables:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddEnvironmentVariables();
            Configuration = configurationBuilder.Build();
        }

For demonstration purposes, we’ll use an existing environment variable. Adding new ones probably requires a restart. Let’s modify our serving code a little:

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                var dnxHome = this.Configuration["DNX_HOME"];
                string output = $"<p>{dnxHome}</p>";

                await context.Response.WriteAsync(output);
            });
        }

Here’s the output:

aspnet5-example-env-config-1

If you don’t want all your environment variables to be accessible to the application, you can specify a prefix that environment variables need to start with. For instance, if I specify “DNX_” as the prefix, then I should get access to “DNX_HOME”, but not to “TMP”. In this case, we specify the prefix in AddEnvironmentVariables(), but omit it when accessing the application setting:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddEnvironmentVariables("DNX_");
            Configuration = configurationBuilder.Build();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                var dnxHome = this.Configuration["HOME"];
                string output = $"<p>{dnxHome}</p>";

                await context.Response.WriteAsync(output);
            });
        }

The output is still the same as before:

aspnet5-example-env-config-2

But this time, the application doesn’t have access to all the environment variables in the system:

aspnet5-example-env-config-4

The contents of the above screenshot are a bit of a surprise, actually. On my system, “DNX_HOME” is the only environment variable starting with “DNX_”. I assume all the rest are created as part of the DNX runtime environment when the application is run.

In-Memory Configuration

At the time of writing this article, the official docs about ASP .NET 5 Configuration show a MemoryConfigurationSource class which can be used to get and set application settings on the fly in code. The page says it requires Microsoft.Framework.ConfigurationModel.

My guess is that the documentation is out of date, because the latest packages are all like Microsoft.Extensions.* and the latest version of Microsoft.Framework.ConfigurationModel is beta 4. I haven’t been able to locate the replacement package for this.

Update 10th January 2016: The ASP .NET documentation has been updated just a few days ago for RC1 (about time), and it turns out that what used to be MemoryConfigurationSource is now called MemoryConfigurationProvider. The rest of this section has been added in light of this.

It is possible to create configuration settings entirely in memory. For this, we create a MemoryConfigurationProvider, and either pass initial configuration data in the constructor or call its Set() method to add a key/value pair. Here’s a simple example:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();

            var memConfig = new MemoryConfigurationProvider();
            memConfig.Set("name", "Joe");

            configurationBuilder.Add(memConfig);
            Configuration = configurationBuilder.Build();
        }

We can test this as follows:

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync($"Hello {Configuration["name"]}!");
            });
        }

Here’s the result:

aspnet5-config-memory

Command-Line Arguments

ConfigurationBuilder provides a method which can be used to build configuration based on command-line arguments:

            configurationBuilder.AddCommandLine(args);

This is demonstrated in the ASP .NET 5 Configuration official documentation using a console application.

It is not clear how this would work for a web application. Whenever I try to run the web application, whether from VS2015 or using the command line tools, Main() does not get invoked, and control goes directly to ConfigureServices(), which knows nothing about the command line arguments.

Hierarchical Retrieval

One of the advantages of the new ASP .NET 5 Configuration model is that you can organize your application settings into hierarchies. If we go back to the JSON example and add back the default appsettings.json file generated by Visual Studio, we get this:

{
    "Data": {
        "DefaultConnection": {
            "ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;"
        }
    }
}

We can retrieve inner settings using a colon syntax such as this:

                var connStr = this.Configuration["Data:DefaultConnection:ConnectionString"];

Let’s change our Configure() code to use the new setting:

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                var connStr = this.Configuration["Data:DefaultConnection:ConnectionString"];
                string output = $"<pre>{connStr}</pre>";

                await context.Response.WriteAsync(output);
            });
        }

And here’s the result:aspnet5-example-hierarchical-config

Combining Configurations

So far we have seen one configuration source at a time to keep things simple. But as a matter of fact, you can specify multiple sources for your application settings. The order is important, because sources specified later will override settings also found in sources specified earlier. For example, let’s say we have:

        public void ConfigureServices(IServiceCollection services)
        {
            var configurationBuilder = new ConfigurationBuilder();
            configurationBuilder.AddIniFile("appsettings.ini")
                                .AddEnvironmentVariables("DNX_");
            Configuration = configurationBuilder.Build();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                var home = this.Configuration["HOME"];
                var work = this.Configuration["WORK"];
                string output = $"<p>Home: {home}</p><p>Work: {work}</p>";

                await context.Response.WriteAsync(output);
            });
        }

Our environment variables contain a “DNX_HOME”. As before, since we’re using a “DNX_” prefix, getting the “HOME” setting actually retrieves “DNX_HOME”. Now, let’s say our appsettings.ini file contains the following:

HOME=Where the heart is
WORK=Where the fun is

Here’s what we get:

aspnet5-configuration-combined-example

What happened here? The “HOME” setting taken from our environment variables has overwritten that in the INI file. However, the “WORK” setting was taken from the INI file because there is none specified in the environment variables.

Summary

In this article, we have seen how we can work with simple application settings in ASP .NET 5. JSON, XML, INI and environment variables are all viable configuration sources to use. In-memory configuration and command-line parameters are a bit more obscure at the time of writing this article.

Additionally, thanks to a more complex configuration model, we can retrieve settings from a hierarchy, and we can combine settings from various sources. Remember: the later ones take precedence!

In Part 2, we will go beyond simple setting retrieval, and learn more complex ways to work with settings in a real-world application.

Inconsistent Toggles in Windows 10 Taskbar Menu

There’s something I found really odd about the Windows 10 taskbar. There are two special buttons next to the Start button: the Search button, and the Task View button. You can toggle the visibility of each from the context menu that comes up when you right click on the taskbar.

We can toggle the Task View button by simply clicking on the “Show Task View button” item in the menu. When the Task View button is visible, this item is checked:

win10-show-task-view-on

…and when it’s not visible, the item is not checked:

win10-show-task-view-off

Simple, no? Let’s do the same for the Search button. Right now it’s on…

win10-show-search-on

So when I click “Show search icon”, following the same logic as with the Task View button, I would expect it to disappear, right?

Nope. Clicking that won’t do anything, because you instead have to select “Hidden”. Then, when Search is not visible, it looks like this instead:

win10-show-search-off

Okay, it’s easy to get used to this after tripping on it the first time. But why would anyone ever provide these kinds of confusing and inconsistent options?

Aside from this, that Search submenu is clearly overkill, given that they could have implemented a single toggle menu item as with Task View. This is exactly like using two checkboxes for the opposites of same thing and expecting them to be mutually exclusive. By way of analogy, can you imagine how stupid this would look?

win10-gender-analogy

This would tell you that the Male and Female options are unrelated; you could potentially pick both.

Update 24th December 2015: As pointed out in these comments on Reddit, apparently the reason for having a separate menu for the Search icon is that in regions where Cortana is enabled, there are actually three options. They could have at least used bullets instead of checkmarks though, which would have made them feel like radio buttons (making the mutual exclusion obvious) rather than checkboxes.

ASP .NET 5 Preview: Serving Static Files

One of the most basic features of just about any non-trivial web application is that of serving static files.  Typically, a browser will request all kinds of files: HTML documents, JavaScript files, images, etc.

In ASP .NET 5, the root of the website is (by default) a folder called wwwroot. Any files to be served by the web application should be placed within this folder. However, the ability to serve static files doesn’t come out of the box. To support static files, you need to add the Microsoft.AspNet.StaticFiles NuGet package to your project.json:

  "dependencies": {
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
  },

Then, in your Configure() method (Startup.cs), call UseStaticFiles():

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();
            
            app.UseStaticFiles();

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }

Rebuild and run your application:

dnu restore
dnu build
dnx web

…and you can now retrieve files:

aspnet5-staticfiles-text

If you go to the root of the URL, though, you’ll notice that your index.html doesn’t get retrieved unless you request it explicitly:

aspnet5-staticfiles-nodefault

That “Hello World” is coming from the end of the pipeline we defined in Configure(), because UseStaticFiles() doesn’t know what to return if we don’t specify a file that exists. We can sort this out by calling UseDefaultFiles():

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();
            
            app.UseDefaultFiles();
            app.UseStaticFiles();

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }

UseDefaultFiles() will look for typical default files such as index.html, default.html, etc. It must be declared before UseStaticFiles(), or it won’t work. We now get our default page:

aspnet5-staticfiles-withdefault

If you want to show a directory listing for folders with no such default files, call UseDefaultFiles() (note: again, order is important):

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();
            
            app.UseDefaultFiles();
            app.UseDirectoryBrowser();
            app.UseStaticFiles();

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }

Our root still serves the default index.html, but when navigating to the images folder, we are presented with a directory listing:

aspnet5-staticfiles-dirlisting

You can also achieve what we have done so far using the UseFileServer() method. Refer to the official documentation on static files to learn how to use UseFileServer(), and for additional configuration options provided by the features we have seen so far.

ASP .NET 5 Preview: Hello World with Yeoman

ASP.NET 5 (formerly known as ASP .NET vNext) is the next generation of ASP .NET, still in a prerelease state. At the time of writing, the current runtime version is 1.0.0-rc1-update1, and ASP .NET 5 is set to launch in Q1 2016. The APIs seen here may change in the time leading up to that release; in fact, this article is written precisely to address recent API changes.

ASP .NET 5 is a game changer, and everything we’ve learned in ASP .NET so far no longer applies. In this article, we’ll see how to do a basic “Hello World” with ASP .NET 5. This usually sounds like something easy, but given that things are changing pretty quickly (even fundamental things such as the IIS hosting model), it’s not. In fact, I would have liked to say you can create a new project in Visual Studio and select the “Empty” ASP .NET 5 Preview Template:

aspnet5-empty-preview-template

Unfortunately, however, these templates are so outdated that they no longer work. Starting with these and getting them to work is an exercise in frustration. Fortunately, however, there’s an alternative way to easily set up an ASP .NET 5 project. And, surprise surprise, it does not involve Visual Studio.

Update 27th December 2015: If you do want to use the latest Visual Studio templates, install Visual Studio 2015 Update 1 as well as the latest ASP .NET 5 Release Candidate.

Yeoman provides a tool called yo, which allows you to create a new web application from various different templates. Nowadays, with so many tools and technologies, it is sometimes difficult to piece things together. You can use yo and its generators to set up a web application with the bits and pieces you need without much effort. For example:

  • Want to create an AngularJS Single-Page App (SPA)? No problem, there’s a generator for that.
  • Want to create an ASP .NET MVC application? No problem, there’s a generator for that.
  • Want to create an ASP .NET 5 empty application? No problem, there’s a generator for that too.
  • Want a full rack of barbecue ribs with fries? I don’t think there’s a generator for that, but perhaps someone may write one someday.

Like various other web tools, yo and its generators require npm, the node.js package manager. You will first need to install node.js, and npm comes packaged with it. You can then install yo by running the following command from the command prompt:

npm install -g yo

In order to generate a web application template, yo relies on plugins, called generators. At the time of writing, there are several generators for ASP .NET 5, but generator-aspnet is the only one that’s up to date. Let’s also install it using the following command:

npm install -g generator-aspnet

With that done, we can now generate our ASP .NET project. You can either invoke yo and do it interactively:

yeoman-interactive-2

…or just invoke the following command:

yo aspnet

You will then be asked a few questions that allow you to configure your ASP .NET 5 project. For starters, we’ll create an Empty Application:

aspnet5-yeoman-application-type

You will then be asked for the name of your application, after which the web app skeleton will be generated, and you will be told the commands you need to build and run it:

aspnet5-yeoman-application-generated

Before we run these commands, let’s take a second to see what our project actually contains. The files we care about are Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;

namespace myapp
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }

        // Entry point for the application.
        public static void Main(string[] args) => Microsoft.AspNet.Hosting.WebApplication.Run<Startup>(args);
    }
}

…and project.json:

{
  "version": "1.0.0-*",
  "compilationOptions": {
    "emitEntryPoint": true
  },
  "tooling": {
    "defaultNamespace": "myapp"
  },

  "dependencies": {
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final"
  },

  "commands": {
    "web": "Microsoft.AspNet.Server.Kestrel"
  },

  "frameworks": {
    "dnx451": { },
    "dnxcore50": { }
  },

  "exclude": [
    "wwwroot",
    "node_modules"
  ],
  "publishExclude": [
    "**.user",
    "**.vspscc"
  ]
}

Now, in order to proceed, you need to have the DNX tools (dnu, dnvm and dnx). If you don’t have them, you can get them when you install Visual Studio 2015, or by following the instructions on the ASP .NET 5 Github page. You may also need to upgrade to the latest runtimes (use dnvm list to check what you’re using, dnvm upgrade to get the latest, and dnvm use <runtime> to switch to the latest) – learning to use the DNX tools is beyond the scope of this article.

Once you have DNX in place, you can run the commands suggested by the aspnet generator earlier. First, cd into the application directory:

cd myapp

Then, run the following command to restore packages (essentially works like NuGet):

dnu restore

You can now build the web application using the following command:

dnu build

Finally, the following command runs the application. You’ll notice that web is actually one of the commands defined in the project.json we saw earlier.

dnx web

aspnet5-dnx-web

As shown in the screenshot above, the web application is hosted at localhost:5000 by default. Indeed, we can confirm that this works by going there:

aspnet5-helloworld

The output we see comes from Startup.cs as we have seen earlier:

        public void Configure(IApplicationBuilder app)
        {
            app.UseIISPlatformHandler();

            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }

The Configure() method allows us to set up our web application pipeline. In here, we define any middleware we need. For example, if we want to use MVC, then we set it up here; but ASP .NET 5 does not assume that any such infrastructure is required by default. In this case, we are always giving a fixed response.

This is as far as I’m going to go with this little “Hello World” setup for ASP .NET 5. We haven’t even begun to see how different ASP .NET 5 is from the ASP .NET we have known so far. But hopefully, this article will save you a lot of frustration in setting things up until the tooling in Visual Studio 2015 catches up.