Providing configuration data with Windsor
Posted by Davy Brion on May 2nd, 2008
Some classes need configuration data to function properly. This configuration data could be a database connection string, a path, a hostname, a network port, whatever. You typically deal with this by putting the configuration data in your app.config or web.config… either through a Settings file or in the AppSettings or maybe you’ve created your own configuration section or whatever. And in most cases, when a class needs this data, it simply retrieves it from the Configuration class or the class that was created through your Settings class.
By doing this, you actually create a strong dependency between your class, and the object that provides the configuration data. But you’re not really dependent on the object providing the data, since you really only need a bit of data to function. So why not treat the data itself as a dependency?
Let’s use our previous example. The OrderDataAccessor class will retrieve Orders from a database. In order to do that, it needs a connection string. Instead of letting the OrderDataAccessor class retrieve that connection string from a config file itself, we’ll modify the constructor so that each instance retrieves the connection string when it is created:
private readonly string _connectionString;
public OrderDataAccessor(string connectionString)
{
_connectionString = connectionString;
}
If the container now needs to create an OrderDataAccessor instance, we get the following exception:
Castle.MicroKernel.Resolvers.DependencyResolverException : Could not resolve non-optional dependency for 'Components.OrderDataAccessor' (Components.OrderDataAccessor). Parameter 'connectionString' type 'System.String'
Which makes sense, since we haven’t told the container about this ‘dependency’ yet. Since we’re dealing with configuration data now, it’s probably better to move our Windsor configuration to a config file as well. First we’ll define the castle configuration section in our app.config:
<configSections>
<section name=“castle“ type=“Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor“ />
</configSections>
Then we configure our components:
<castle>
<components>
<component id=“IOrderDataAccessor“
service=“Components.IOrderDataAccessor, Components“
type=“Components.OrderDataAccessor, Components“>
<parameters>
<connectionString>myConnectionString</connectionString>
</parameters>
</component>
<component id=“IOrderRepository“
service=“Components.IOrderRepository, Components“
type=“Components.OrderRepository, Components“ />
</components>
</castle>
And that’s it… Whenever the container instantiates an OrderDataAccessor instance, it will pass ‘myConnectionString’ to the connectionString parameter.
There’s one issue with this though… In a real system, you’d have more than one DataAccessor class, and having to specify the connectionString for each one of them would be a prime example of suckage. So let’s modify our config file a little bit:
<castle>
<properties>
<connectionString>myConnectionString</connectionString>
</properties>
<components>
<component id=“IOrderDataAccessor“
service=“Components.IOrderDataAccessor, Components“
type=“Components.OrderDataAccessor, Components“>
<parameters>
<connectionString>#{connectionString}</connectionString>
</parameters>
</component>
<component id=“IOrderRepository“
service=“Components.IOrderRepository, Components“
type=“Components.OrderRepository, Components“ />
</components>
</castle>
That’s better… Now we can just refer to the connectionString whenever we need it so we’d only have to modify it in one place.
Keep in mind that if you put the Windsor configuration in your app.config/web.config file, you need to instantiate the container like this:
_container = new WindsorContainer(new XmlInterpreter());
So as you can see, you can also use the IoC container to keep dependencies on configuration-providing-classes completely out of your code by ‘promoting’ the required configuration data to actual dependencies of your components.