On strongly typed application settings with Castle DictionaryAdapter

Every non-trivial .NET application ends up using configuration file for its settings. It’s the standard mechanism that’s fairly well adopted across the community. That doesn’t mean however, that it’s simple to deal with.

There have been many various approaches to dealing with the problem, including some from Microsoft. There are a few open source ones, including one from my colleague, Andrew.

Yet another (not even original) approach

This brings us to Castle DictionaryAdapter. Part of the Castle project that never got much traction, partially to poor (read non-existent) documentation. Somewhat similar to DynamicProxy, DictionaryAdapter concentrates on dynamically generating strongly typed wrappers around dictionaries or XML. The idea of using it for wrapping configuration values is not new. Ben blogged about it a few years ago, and I always liked the simplicity and readability of the approach, and how little effort it required.

I started working on a project recently, that has a whole bunch of different sets of config values, which led me to adding some small improvements to the approach.

Not just one big Config God Object

One common mistake (regardless of the approach) is that all the unrelated settings end up in a single massive configuration God Object. There is nothing inherent about the DictionaryAdapter approach forcing you to go down that path. You can split your configuration logically across a few configuration interfaces

public interface SmtpConfiguration
{
    string Name { get; set; }
    int Port { get; set; }
}

public interface SomeOtherConfig
{
    //stuff
}

// and in the config file:
<appSettings>
    <add key="name" value="value" />
    <add key="port" value="25"/>
    <!--  stuff -->
</appSettings>

Taking it a bit further, we might explicitly partition the values using prefixes:

<appSettings>
    <add key="smtp:name" value="value" />
    <add key="smtp:port" value="25"/>
    <add key="stuff:something" value="bla"/>
    <!--  other stuff -->
</appSettings>

DictionaryAdapter knows how to properly resolve prefixed values using KeyPrefixAttribute.

[KeyPrefix("smtp:")]
public interface SmtpConfiguration
{
    string Name { get; set; }
    int Port { get; set; }
}

Fail fast

One other missing big, is shortening the feedback loop. We don’t want to learn we have an invalid or missing value at some later point in the application’s lifecycle when we try to read it for the first time. We want to know about it as soon as possible. Preferably, when the application starts up (and in a test).

The first problem, we could solve with FetchAttribute Which forces a property to be read when the adapter is constructed, therefore forcing exception in cases where, for example, your property is of type TimeSpan but your config value is not a valid representation of time span.

To solve the other problem we need a little bit of code. In fact, to simplify things, we can merge that with what KeyPrefixAttribute and FetchAttribute provide, to have all the functionality we need in a single type.

public class AppSettingsAttribute : KeyPrefixAttribute, IDictionaryPropertyGetter, IPropertyDescriptorInitializer
{
    public AppSettingsAttribute(string keyPrefix) : base(keyPrefix)
    {
    }

    public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, object storedValue,
        PropertyDescriptor property, bool ifExists)
    {
        if (storedValue == null && IsRequired(ifExists))
        {
            throw new ArgumentException("No valid value for '" + key + "' found");
        }
        return storedValue;
    }

    public void Initialize(PropertyDescriptor propertyDescriptor, object[] behaviors)
    {
        propertyDescriptor.Fetch = true;
    }

    private static bool IsRequired(bool ifExists)
    {
        return ifExists == false;
    }
}

Now our configuration interface changes to:

[AppSettings("smtp:")]
public interface SmtpConfiguration
{
    string Name { get; set; }
    int Port { get; set; }
}

Not only do we get a nice, readable, testable strongly typed access to our settings, that can easily be put in an IoC container. We also are going to get an early exception if we put an invalid value in the config, or we forget about doing it at all.

The full code is on github.