Using ConfigR as a Configuration Source in ASP.NET vNext

ยท 1067 words ยท 6 minutes to read

One of the cool things about ASP.NET vNext is that it introudces a configuration abstraction, Microsoft.Framework.ConfigurationModel over your application’s configuration.

This is going to replace the old school, limiting approach of forcing you to work with XML configuration only through the System.Configuration classes.

Louis DeJardin has blogged about the ideas behind the isolation of Configuration in his blog post. In the meantime, let’s have a look at how we could enable a ConfigR-based configuration too.

Introducing ConfigR ๐Ÿ”—

ConfigR is a terrific project from Adam Ralph, and is based on the scriptcs project. In short, ConfigR allows you to use CSX files (C# scripts) to write your project’s configuration.

You get three benefits:

ย ย 1. your configuration can be strongly typed, as you are no longer constrained by the limits of serialization; you simply write your config file with C#

ย ย 2. configuration is no longer purely static. It can now make logical decisions and reason about configuration settings itself, as it can run C# code. This is profoundly important as it allows you to completely decouple the configuration from the application. Configuration, since it’s C# driven, can inspect the runtime and, for example, decide on proper config settings based on the versions of the assemblies currently loaded into the AppDomain.

ย ย 3. ConfigR, out of the box, supports loading configuration over the network, so you can configure a large number of your applications, distributed across different machines or platforms, from a single place

ASP.NET vNext configuration source ๐Ÿ”—

ASP.NET vNext has built-in support for specific configuration sources already, such as JSON files or INI files. Aside from that, ASP.NET vNext allows you to plug in your own custom
configuration source, in the form of IConfigurationSource.

Potential examples of custom configuration source might be one that reads values from a database or over HTTP. By the way, Fredrik has an entire post dedicated to config sources.

The interface is shown below.

[AssemblyNeutral]  
public interface IConfigurationSource  
{  
void Load();  
IEnumerable<string> ProduceSubKeys(IEnumerable<string> earlierKeys, string prefix, string delimiter);  
void Set(string key, string value);  
bool TryGet(string key, out string value);  
}  

As you can see, ASP.NET vNext is very simple - string keys, string values. This is a bit constraining for ConfigR, since it could support any type. The reason behind this decision is that the configuration abstraction is intended to support any source, so it was simplified accordingly, as explained by David.

Consequently, with ConfigR, we’d lose benefit 1. mentioned earlier but it’s still worthy to implement it to, to take advantage of other of its benefits (mainly, being able to run code in the configuration, perhaps even remotely).

ConfigR as configuration source ๐Ÿ”—

To run ConfigR as ASP.NET vNext configuration source you need to add references to Microsoft.Framework.ConfigurationModel and ConfigR nuget package. Additionally, we’ll store our configuration in a file called “config.csx”, so let’s exclude it from the project.

Here’s the basic outline of project.json.

{  
"dependencies": {  
"Microsoft.Framework.ConfigurationModel": "1.0.0-alpha4",  
"ConfigR": "0.11.0"  
},  
"exclude": "config.csx",  
"frameworks": {  
"aspnet50": {  
},  
"aspnetcore50": {  
"dependencies": {  
"System.Console": "4.0.0.0"  
}  
}  
}  
}  

Once references are added, we can expand them to indeed verify that ConfigR is going to run scriptcs internally.

Now we need to wrap ConfigR with a class implementing IConfigurationSource. Note that in the Load method we load our config.csx file. We could load it from the network too.

Configuration source also supports a notion of nesting keys, which is done by delimiting them with a colon. This is represented by the ProduceSubKeys method, which in our case will be the same as in the default config implementation.

public class ConfigRSource : IConfigurationSource  
{  
private readonly string _filename;

public ConfigRSource() : this("config.csx")  
{  
}

public ConfigRSource(string filename)  
{  
_filename = filename;  
}

public void Load()  
{  
Config.Global.LoadScriptFile(_filename);  
}

public void Set(string key, string value)  
{  
Config.Global[key] = value;  
}

public bool TryGet(string key, out string value)  
{  
if (Config.Global.ContainsKey(key))  
{  
value = Config.Global.Get<string>(key);  
return true;  
}  
else  
{  
value = null;  
}

return false;  
}

public IEnumerable<string> ProduceSubKeys(IEnumerable<string> earlierKeys, string prefix, string delimiter)  
{  
return Config.Global  
.Where(kv => kv.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))  
.Select(kv =>  
{  
var indexOf = kv.Key.IndexOf(delimiter, prefix.Length, StringComparison.OrdinalIgnoreCase);  
return indexOf < 0 ? kv.Key.Substring(prefix.Length) : kv.Key.Substring(prefix.Length, indexOf - prefix.Length); }) .Concat(earlierKeys); } }

You can now put all your config code in config.csx. If you need help understanding how you’d work with ConfigR, I recommend having a look at their wiki.

For example, we might have something like that:

using System.Reflection;  
using System.Diagnostics;

Add("value1", "hi");  
Add("value2", "world");  
Add("value3:nested", "yay!");

Add("klr", Process.GetCurrentProcess().MainModule.FileName);  
Add("machineName", Environment.MachineName);  

As you can see we can not only add static strings, but also use C# properly and access runtime information such as (but not limited to) Process, AppDomain or Environment info. Obviously, this is proper scripted C# so it’s perfectly reasonable to i.e. retrieve a version of some assembly or machine name, and set some value based on that in an if statement. Or based on some other condition, load some config values from a remote data storage. An example is below.

using System.Diagnostics;

if (Environment.MachineName != "production")  
{  
Add("debug", "true");  
}  

Ultimately the point is that your configuration is completely decoupled from the application, also when it comes to making logical decisions about configuration. Adam has a great post about ConfigR explaining this reasoning in detail.

What is really cool is that because scriptcs (which runs under the hood of ConfigR) supports debugging, you can even debug and step through your configuration file by simply putting a breaking point in it!

Screenshot 2014-10-28 15.03.16

Using custom configuration source ๐Ÿ”—

Once you have created the custom configuration source, you can use by simply adding it to the Configuration class (which itself is an IEnumerable) at some point around your application startup. This is shown below:

var config = new Configuration().Add(new ConfigRSource());

//now you can access keys  
Console.WriteLine(config["value1"]);  
Console.WriteLine(config["value2"]);  
Console.WriteLine(config["klr"]);  
Console.WriteLine(config["machineName"]);  

Using the ASP.NET vNext dependency injection you can inject the configuration into any class and your custom configuration source will be dragged along.

To make things prettier and to conform to the approach vNext has taken of adding config sources using extension methods, you can do the same here too.

public static class ConfigurationSourceContainerExtensions  
{  
public static IConfigurationSourceContainer AddConfigR(this IConfigurationSourceContainer configuration)  
{  
configuration.Add(new ConfigRSource());  
return configuration;  
}

public static IConfigurationSourceContainer AddConfigR(this IConfigurationSourceContainer configuration, string filename)  
{  
configuration.Add(new ConfigRSource(filename));  
return configuration;  
}  
}  

Now you can register ConfigR using the fluent API, and easily combine with other ASP.NET vNext config sources.

var config = new Configuration().AddConfigR().AddEnvironmentVariables();  

About


Hi! I'm Filip W., a software architect from Zรผrich ๐Ÿ‡จ๐Ÿ‡ญ. I like Toronto Maple Leafs ๐Ÿ‡จ๐Ÿ‡ฆ, Rancid and quantum computing. Oh, and I love the Lowlands ๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP