Sunday, February 07, 2010

This trick follows on nicely from trick number 9, ‘Configuring fluently registered components with XML’. Sometimes you might want a configuration value other than a simple string or integer. Windsor provides the ITypeConverter interface that you can implement to supply complex configuration for your components.

As an example, let’s imagine we have a class, HealthMonitor, that pings a series to endpoints and checks that a particular string is returned before a timeout. We want to configure HealthMonitor with an array of HealthEnpoints that specify a URL, an expected string value and a timeout in seconds. Something like this:

Note that we want to use the standard Windsor configuration to say that the ‘healthEndpoints’ constructor parameter is made up of an array and each element of that array is described by ‘item’. We get that without doing anything special.

However, we do need some way of telling Windsor that when a component has a HealthMonitor dependency it should read a ‘url’, ‘expect’ and ‘timeoutSeconds’ value from the configuration and then construct a HealthEndpoint. We do that with a type converter.

We implement AbstractTypeConverter which provides us with some plumbing and implement three methods: ‘CanHandleType’ which tells Windsor which type(s) we are interested in; and two overloads of ‘PerformConversion’, one that takes a string and a target type and one that takes the current configuration section and a target type. Since we want to interpret the current configuration of each ‘item’ we’ll implement the second ‘PerformConversion’ method.

I’ve got a simple internal class ‘Converter’ that keeps track of child nodes of the ‘item’ node and the current context. It simply looks up each required property and converts it to a target type. Once we have our ‘url’, ‘expect’ and ‘timeoutSeconds’ values we construct and return a new HealthEndpoint. Note that we use Windsor’s built-in type converters for the simple target types: ‘context.Composition.PerformConversion’.

Wiring the type converter with Windsor is not obvious. You have to grab Windsor’s ConversionManager sub-system and add the new type converter to that. You could wrap that step with a facility, but there’s also a nice extension point, IWindsorInstaller, that you can also use to wrap up complex setup pieces:

This is pretty simple example, but it’s possible to use type converters for some sophisticated configuration setups. Say you wanted to take some string value and parse it into a configuration class or maybe provide some kind of polymorphic configuration, all this can be done with a type converter.

OK, so that was trick 10, but don’t go away I’ve still got plenty more in the bag. Perhaps I should have used Scott Hanselman’s ‘… of an infinite series’ formula, but I quite like the fact that from now I’ll be over-delivering :)

Actually you can get the HealthEndpoints property initialized without writing and registering custom type converter at all - just mark HealthEndpoint with [Convertible] attribute. The built-in ArrayConverter will nicely initialize your property even if it's an array of objects.

Tested on Windsor 3.2.1, so it may be just a new feature added after you wrote the post...

Code Rant

Notepad, thoughts out loud, learning in public, misunderstandings, mistakes. undiluted opinions. I'm Mike Hadlow, an itinerant developer. I live (and try to work in) Brighton on the south coast of England. Please don't mistake me for an expert in anything. I love technology and programming, but make no claims to be any good at it. Much of what you read here may be poorly thought out, wrong, or just plain dangerous.