Here’s part nine of (at least) 10 Advanced Windsor Tricks.
Did you know that you can mix fluent and XML configuration for the same component. I’m not the only one who thinks XML component registration is a verbose pit of failure. But there are some things you really do not want to hard code into your application. Things like connection strings, the location of resources on the network and other deployment specific settings. Windsor provides a very nice story for setting property values on your components using an XML file without having to fall back on the awful appSettings or defining your own custom ConfigurationSection. Here’s how it’s done:
Let’s say we have a class ConfigurationThing with some string properties for configuring a database connection:
public interface IConfigurationThing { string Server { get; set; } string Database { get; set; } string User { get; set; } string Password { get; set; } } public class ConfigurationThing : IConfigurationThing { public string Server { get; set; } public string Database { get; set; } public string User { get; set; } public string Password { get; set; } }
We can fluently register it as normal:
var container = new WindsorContainer() .Install(Configuration.FromXmlFile("windsor.config")) .Register( Component .For<IConfigurationThing>() .ImplementedBy<ConfigurationThing>() .Named("configuration") );
Notice that we’re also including registration configuration from the file windsor.config. Also note that we give our IConfigurationThing service a name: ‘configuration’. Now in the windsor.config file we can configure the properties of ‘configuration’ by referencing it’s name – except that in the config file it’s confusingly called ‘id’:
<configuration> <components> <component id="configuration"> <parameters> <Server>db.suteki.co.uk</Server> <Database>sutekishop</Database> <User>thingApp</User> <Password>1am_th3th1ng</Password> </parameters> </component> </components> </configuration>
This is exactly the same as the standard XML component registration, except that we don’t specify the ‘service’ and ‘type’ attributes of the component. Windsor simply looks for a component registered with the same ‘id’… or rather ‘name’.
Now when we resolve our IConfigurationThing its properties are set to the values we specified in windsor.config:
var configuration = container.Resolve<IConfigurationThing>(); Console.Out.WriteLine("configuration.Server = {0}", configuration.Server); Console.Out.WriteLine("configuration.Database = {0}", configuration.Database); Console.Out.WriteLine("configuration.User = {0}", configuration.User); Console.Out.WriteLine("configuration.Password = {0}", configuration.Password);
Which outputs:
configuration.Server = db.suteki.co.uk configuration.Database = sutekishop configuration.User = thingApp configuration.Password = 1am_th3th1ng
Because Server, Database, User and Password are properties rather than constructor arguments, the component resolution will not fail if they are not supplied, instead they will all be null. This can be a nice feature if you want to supply default arguments that can be overridden by configuration.
I use this technique a lot. Configuration is one of those unexpected benefits of using Windsor.
That's very cool. I've always been a fan of a configuration class for complex services or repositories. I should look into doing this with Unity.
ReplyDeleteThat is really useful, thanks for sharing.
ReplyDeleteDon't stop at trick number 10!