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.

One thought on “ASP .NET 5 Application Configuration, Part 1”

Leave a Reply

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