Hello again everybody! Dusting off the blog dns name and giving it a facelift.

Jumping right in to the topic for today - the new ASP.NET vNext platform we're creating at http://github.com/aspnet has a lot of interesting subsystems. I thought I'd start with something small by talking about one of them which lives more or less in isolation, namely Configuration.

tl;dr you can paste this into a cmd prompt (alt-space E P)

:: From a folder where you clone projects
git clone https://github.com/loudej/WheresLouSamples  
cd WheresLouSamples  
kvm install 0.1-alpha-build-0453

cd 01.Configuration  
kpm restore --source https://www.myget.org/F/aspnetvnext/api/v2/

type Program.cs

k run

k run --display:font:color Purple

set DISPLAY:FONT:SIZE=24pt  
k run

::done

If you're reading this you're not new to C# and you're very familiar with web.config and System.Configuration namespace. That's something we took into account very seriously thinking this space. There were two really big factors that fed into the early conversations about vNext and the existing System.Configuration.

One factor is that we wanted our new systems to run the same on a Cloud Optimized (tm) CLR as well as the full Desktop CLR. This meant right away means we needed to have something lightweight that works everywhere, or we need to add a fully compatible System.Configuration (which is big) to Core CLR, or we needed to expect people to #ifdef. Between those we were leaned towards something lightweight that works everywhere.

The other factor is that a lot of new systems are designed to be instantiated. So if you're using a subsystem "X" (like Mvc, Identity, or Razor) you can new it up more than once in an AppDomain. If that subsystem "X" looked for the config section by calling into a static, singleton configuraton API, then that causes a problem. You can't configure each instance of "X" differently...

Given that - we started with the idea that the config itself can be instantiated and initialized by the application. Then you pass that to frameworks you're using as appropriate. As an extra bonus, it's up to you as the application author where your settings come from - and you can decide if the sources should be different when the application is running in production, development, or staging environments.

Simply put:

using Microsoft.Framework.ConfigurationModel;  
...
var config = new Configuration();  
config.AddXxxFile("app.config");  

Or fluently put:

IConfiguration config =  
    new Configuration()
      .AddXxxFile("config.xxx")
      .AddYyyFile("config.yyy")
      .AddZzzFile("config.zzz");

The two question you should be thinking now are, "Hey, Lou, what kind of files or sources can I add to this thing?" and "Okay, but how do I get my setting out now?"

What kind of files or sources can I add to this thing?

The three kinds of file formats we're thinking of pulling in to start with are json, ini, and xml. The .AddIniFile(...) extension method is available right from the Microsoft.Framework.ConfigurationModel nuget package. The other .AddJsonFile(...) and .AddXmlFile(...) extensions are added by the Microsoft.Framework.ConfigurationModel.Json and Microsoft.Framework.ConfigurationModel.Xml nuget packages. They're layered out because they also drag in dependencies on additional parser.

Three other sources we're planning to have are environment variables, command line arguments, and in-memory. And of course you can add multiple configuration sources to a Configuration instance. If you do they are from least to greatest priority. So for example an in-memory source can be added first to provide "defaults" or last to provide "overrides".

How do I get my setting out of this thing now?

That's something in particular we wanted to keep as simple as possible. Once you have your IConfiguration config, and you've added all the sources you want, the API to call is string value = config.Get("thekey").

For example:

Console.WriteLine(  
    "size:{0} color:{1} background:{2}",
    config.Get("Display:Font:Size"),
    config.Get("Display:Font:Color"),
    config.Get("Display:Font:Background")
);

We're also planning on adding indexer support, so expect that to also work like:

Console.WriteLine(  
    "size:{0} color:{1} background:{2}",
    config["Display:Font:Size"],
    config["Display:Font:Color"],
    config["Display:Font:Background"]
);

Case shouldn't matter, so when you have a setting you should be able to use casing that's appropriate for your file format.

Let's bring those together

project.json

{
    "dependencies":{
        "Microsoft.Framework.ConfigurationModel": "0.1-*",
        "Microsoft.Framework.ConfigurationModel.Json": "0.1-*",
        "Microsoft.Framework.ConfigurationModel.Xml": "0.1-*"
    }
}

Program.cs

using System;  
using Microsoft.Framework.ConfigurationModel;

public class Program  
{
    public void Main(string[] args) 
    {
        var config = new Configuration()
            .AddIniFile("App_Data\\config.ini")
            .AddJsonFile("App_Data\\config.json")
            .AddXmlFile("App_Data\\config.xml");

        Console.WriteLine(
            "size:{0} color:{1} background:{2}",
            config.Get("Display:Font:Size"),
            config.Get("Display:Font:Color"),
            config.Get("Display:Font:Background")
        );
    }
}

App_Data\config.json

{
    "display":{
        "font":{
            "color": "Yellow"
        }
    }
}

App_Data\config.xml

<config>  
    <display>
        <font background="Blue"/>
    </display>
</config>  

App_Data\config.ini

[Display]
Font:Size = 9pt  

And running it gives me this:

>k run
size:9pt color:Yellow background:Blue  

Adding the other sources in

Let's go a step further and add the other sources in

var config = new Configuration()  
    .AddIniFile("App_Data\\config.ini")
    .AddJsonFile("App_Data\\config.json")
    .AddXmlFile("App_Data\\config.xml")
    .AddEnvironmentVariables()
    .AddCommandLine(args);

And now we can take advantage of those as well:

>k run
size:9pt color:Yellow background:Blue

>k run --display:font:color Purple
size:9pt color:Purple background:Blue

>set DISPLAY:FONT:SIZE=24pt

>k run --display:font:color Purple
size:24pt color:Purple background:Blue  

Environment variables might seem like an odd way to pass information, but they can be a powerful option to have. Azure Web Sites, for example, do offer a way to set environment variables in your web application's process - so this can be a way to keep production and staging configuration information out of source control.

Expect to see more developments on this subsystem as we iron out some more new ideas. One thing that's especially interesting is what it means if you have a simple "Model Binding" feature available. That way you could choose to declare a plain old class in your code, like an AppSettings, which would have it's properties filled in automatically, no strings attached. (Sorry!)

But in any case, hope you like the work so far and let us know if you have suggestions.