Thursday, 10 June 2010

Configuration ignorance

A good friend of mine, Stephen Oakman, did a post on how to hide your dependencies on a particular configuration implementation (Using a configuration provider). I wanted to touch on the basics of the post and show how that can be achieved with a complex implementation of a configuration structure using the System.Configuration namespace objects and builds on my original post of Generic configuration element collections.

If you are not very familiar with the System.Configuration library you should checkout these very good articles by Jon Rista:

The basic premise of Steve’s article is to hide how you retrieve your configuration object behind a configuration provider interface. The implementation behind then goes off and does the nasty work of getting the configuration out of the application settings in the application configuration if you are felling particularly unclean and dirty. I want to show how this can be done using the cleaner approach of using ConfigurationSection and ConfigurationElement implementations whilst not exposing the dependencies of the System.Configuration namespace.

A basic configuration section implementation

Let’s start by looking at a basic implementation of the configuration section.

public class BasicConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty("SomeValue")]
    public string SomeValue
    {
        get { return (string)this["SomeValue"]; }
    }
}

Assuming that this is correctly configured in the application configuration (I won’t go into how this should be done as there are already many posts that do this) we can retrieve it using the following:

(BasicConfigurationSection)ConfigurationManager.GetSection("Our/Xml/Structure/BasicConfiguration");

As you can see any component that needs to use the configuration object will be dependent on the System.Configuration namespace and know how to retrieve the object from the ConfigurationManager. Now you could just inject your configuration in which means you only need to retrieve it at least once but you are still dependent on any module that uses the code being dependent on the System.Configuration namespace which will be dragged in as a reference.

Enter the provider

To offset the responsibility of retrieving the configuration to another component we can introduce Steve’s configuration provider.

public interface IConfigurationProvider<TConfiguration>
{
    TConfiguration GetConfiguration();
}
 
public class BasicConfigurationProvider : IConfigurationProvider<BasicConfigurationSection>
{
    public BasicConfigurationSection GetConfiguration()
    {
        return (BasicConfigurationSection)ConfigurationManager.GetSection("Our/Xml/Structure/BasicConfiguration");
    }
}

Now we can inject our configuration provider implementation into our objects removing the need for consuming code to know where our configuration comes from.

Hiding behind interfaces

Whilst we have hidden how we retrieve the configuration we have not remove the dependency on the ConfigurationSection base class as the consuming code has access to the base class methods. To remove this dependency we can simply hide our configuration section object behind an interface.

public interface IBasicConfiguration
{
    string SomeValue { get; }
}
 
public BasicConfigurationSection : ConfigurationSection, IBasicConfiguration
{
    ...
}
 
public class BasicConfigurationProvider : IConfigurationProvider<IBasicConfiguration>
{
    public IBasicConfiguration GetConfiguration()
    {
        ...
    }
}

Now the only thing that is aware of our configuration implementation is our configuration provider, we can safely inject our provider into our objects without worrying about being dependent on the System.Configuration namespace.

Handling more complicated configuration sections

The previous code handles a basic flat configuration structure but what happens when we want to use a more complicated three dimensional structure with child ConfigurationElements, ConfigurationCollections or even a ConfigurationGroup.  Take the following example where we have a ConfigurationSection which contains a single ConfigurationElement A and a collection of ConfigurationElement Bs.

public class ComplicatedConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty("ConfigurationA")]
    public ConfigurationElementA ConfigurationA { get { ... } }
 
    [ConfigurationProperty("ConfigurationB")]
    public ConfigurationElementBCollection { get { ... } }
}
 
public class ConfigurationElementA : ConfigurationElement { ... }
 
public class ConfigurationElementB : ConfigurationElement { ... }
 
public class ConfigurationElementBCollection : ConfigurationCollection { ... }

Now we have sub elements which inherit from the ConfigurationElement and ConfigurationCollection base classes. To remove the dependency we will need to put each of the configuration elements behind an interface and use one of the collection interfaces for the collection. If you have used something similar to my post on Generic configuration element collections you can use one of the generic collection interfaces.

public interface IComplicatedConfiguration
{
    IConfigurationA ConfigurationA { get; }
 
    IList<IConfigurationB { get; }
}
 
public interface ConfigurationElementA { ... }
 
public interface ConfigurationElementB { ... }

If you do this though you cannot simply change the return types of your configuration properties to be that of your interfaces otherwise you will get a ConfigurationErrorsException : Property 'ConfigurationA' is not a configurationElement. This is because the ConfigurationProperty attribute is binding to the return type of your configuration which is an interface and does not inherit from the ConfigurationElement base class. Instead you will need to wire up your configuration properties for the more complicated types in the configuration section or elements constructor.

public class ComplicatedConfigurationSection : ConfigurationSection, IComplecatedConfiguration
{
    public ComplicatedConfigurationSection()
    {
        Properties.Add(new ConfigurationProperty(
                "ConfigurationA",
                typeof(ConfigurationElementA),
                null));
        Properties.Add(new ConfigurationProperty(
                "ConfigurationB",
                typeof(ConfigurationElementBCollection),
                new ConfigurationElementBCollection()));
    }
 
    public IConfigurationA ConfigurationA { get { ... } }
 
    public IList<IConfigurationB> { get { ... } }
}
 
public class ConfigurationElementA : ConfigurationElement, IConfigurationA { ... }
 
public class ConfigurationElementB : ConfigurationElement, IConfigurationB { ... }
 
public class ConfigurationElementBCollection : ConfigurationElementCollectionBase<ConfigurationElementB, string> { ... }

Finishing touches

The one thing that clutters up this approach is having to inject the configuration provider into the consuming classes, it would be more preferable inject just the configurations themselves. Obviously you could just new up all of your providers at the start and get the configuration objects and add them to your IoC container which is fine but a little messy. If however you are lucky enough to be using Windsor you can make use of the FactorySupportFacility which would  simplify your wiring up of your components.

Was it worth it

So after that what do we have, well we have twice as many objects with all the new interfaces and the configuration sections are a little more complicated but was it all worth it? In my opinion yes otherwise I wouldn’t have bothered posting this. Whilst the implementation is more complicated your consuming code is kept clean and you have the ability to rip out your configuration implementation and replace it with something else without effecting the existing code that consumes the configuration.

No comments:

Post a Comment