20 May 2010

Using custom .Net configuration files in both applications and websites

There will be times when you want a greater level of control over .Net configuration files, particularly when you are trying to manage settings across a large and complex set of environments.

There are a number of ways you can go about this, from creating your own configuration provider to re-mapping the configuration manager to a remote location. However, it’s easy to over-engineer configuration solutions and run into unexpected behavior with settings or performance issues when reading configuration.

The .Net Configuration namespace has been optimised for local, disc-based configuration files and offers nothing to let you extend or change this behavior. This is deliberate, as custom configuration solutions can quickly become a quagmire. Ideally, if you want centralised control over configuration then you need a way of binding the base configuration file to another local disc location that you can supply from a central database.

This re-binding can be done by manipulating the AppDomain settings as shown below:

public static void BindConfiguration(string filename) 
{
    //* Fetch the current configuration parth
    string path = Path.GetDirectoryName(AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString());
    //* Set the new path
    AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE"Path.Combine(path, filename));
}

This code should be executed right at the start of any application. This is usually enough to ensure that new file location used by the  configuration system, but not for web applications where the ConfigurationManager is normally set up by the time you get as far as the application’s Start event.

The code below shows how to use a little bit of reflection in re-setting the configuration system so it is automatically re-initialised the next time any configuration values are required. The newly re-set ConfigurationManager will read from your newly bound configuration path.

private static void ResetConfiguration()
{
    typeof(ConfigurationManager)
        .GetField("s_initState"BindingFlags.NonPublic | BindingFlags.Static)
        .SetValue(null, 0);

    typeof(ConfigurationManager)
        .GetField("s_configSystem"BindingFlags.NonPublic | BindingFlags.Static)
        .SetValue(nullnull);

    typeof(ConfigurationManager)
        .Assembly.GetTypes()
        .Where(x => x.FullName == "System.Configuration.ClientConfigPaths")
        .First()
        .GetField("s_current"BindingFlags.NonPublic | BindingFlags.Static)
        .SetValue(nullnull);
}

Filed under ASP.NET, C#, Net Framework.