Adam Ralph

Software, tea, and snowboarding

Decoupling Apps from Config with ConfigR

ConfigR is a NuGet package based on scriptcs and Roslyn which allows writing configuration files in C# instead of XML.

For example, the stringy XML soup:

	<?xml version="1.0"?>
	<!-- app.config or web.config -->
	<configuration>
	  <appSettings>
	    <add key="Uri" value="http://tempuri.org/myservice"/>
		<add key="Timeout" value ="10000"/>
	  <appSettings>
	</configuration>

can become

// MyApp.exe.csx or Web.csx 
Add("Uri", new Uri("http://tempuri.org/myservice"));
Add("Timeout", 10000);

In the real world configuration is often more complex than this, e.g. multiple dev, test and production environments, per machine configuration, etc.

In their great book, Continuous Delivery*, Jez Humble and David Farley describe how such configuration can be injected into your application at build time, packaging time, deployment time and run time.

Run Time Configuration

The most flexible of these strategies is run time configuration which allows identical building, packaging and deployment of your application in all environments by deferring all configuration decisions until run time. This is easy to achieve using ConfigR since the configuration script is executed at runtime and allows any C# you like, as long as it can be executed by scriptcs**.

First, let’s see what the application has to do to retrieve one of the configuration values:

var uri = Configurator.Get<Uri>("Uri");

In the simple case above, we chose to hardcode our URI into the configuration script. Later, we may choose to look up the URI from a database based on the current machine name:

// MyApp.exe.csx or Web.csx
using System.Data.SqlClient;
using(var connection = new SqlConnection("..."))
{
	connection.Open();
	using(var command = connection.CreateCommand())
	{
		command.CommandText =
            "select Uri from Uris where Machine = '{@Machine}'";
		
		command.Parameters.AddWithValue(
			"Machine", Environment.MachineName);
		
		Add("Uri", new Uri(command.ExecuteScalar().ToString()));
	}
}

Let’s see how the application code has to change in order to support this:

var uri = Configurator.Get<Uri>("Uri");

The application code hasn’t changed at all. This because the application is completely decoupled from the choice of configuration strategy.

Later, we may wish to fetch our configuration from the file system or from an HTTP endpoint, perhaps based not only on the machine name but the current application version, or the current user. We may invent other weird and wonderful configuration strategies.

By implementing your configuration strategy in a ConfigR configuration script, the application code never needs to change.

Among other features, ConfigR allows loading of config scripts from custom file locations or over HTTP and nested loading of scripts from within scripts. The project is under active development and plenty more features are planned. For more information see the quickstart, samples, wiki and issues. Keep an eye out for further ConfigR blog posts by subscribing to the feed. ConfigR is available at NuGet and can be forked at GitHub.

* Humble, J. & Farley D. (2011). Continuous Delivery. Boston: Pearson Education, Inc.

** At the time of writing, scriptcs will run any valid C# with the exception of async/await and dynamic due to limitations in the current release of Roslyn.