Published by breki on 11 Jul 2010 at 04:54 pm
Windsor Castle: Auto-Wiring Using Parameter Names
NOTE: this is probably only one way of doing things in Windsor Castle. If you know of any other, don’t hesitate to write a comment.
A design problem I was trying to solve yesterday: I have a component which depends on two implementations of the same interface:
public class HelpCommand (
ICommandDescriptor oneLinerDescriptor,
ICommandDescriptor detailedDescriptor)
{
...
}
HelpCommand prints out human-readable descriptions of various commands in Maperitive. If the user specifies the exact command, HelpCommand prints out a detailed description. On the other hand, if the command parameter is not specified, HelpCommand lists all of the commands and prints a one-liner description for each of them. So there are two implementations of the ICommandDescriptor interface: OneLinerDescriptor and DetailedDescriptor classes.
The problem I was having with this design is that all of my *Command components are registered in one go, using the convention like
container.Register (AllTypes.Of<ICommand>().FromAssembly (typeof(ICommand).Assembly) .Configure (c => c.Named (c.Implementation.Name).LifeStyle.Transient));
so I’m letting Windsor do all the wiring magic without me being able to provide any custom registration logic for individual commands like HelpCommand. So how do I tell Windsor which component to use for oneLinerDescriptor and which for detailedDescriptor?
Bad Solution
Of course, I could simply specify the concrete implementations in HelpCommand’s constructor:
public class HelpCommand (
OneLinerDescriptor oneLinerDescriptor,
DetailedDescriptor detailedDescriptor)
{
...
}
But this couples the three classes together and goes against the “rely on abstractions, not implementations” mantra. It also makes unit testing of HelpCommand more difficult, since I have to drag the two descriptor classes around (and they could have their own dependencies to satisfy, which further bloats the unit testing code).
Factories?
I could use a factory to get the implementations I need, but that would be wasteful: a simple constructor dependency is much slicker and it doesn’t introduce an additional component (factory) into the picture. Also, factories are more suited for components which are created later, on-demand. In my case I want the descriptors to be available right at the beginning of HelpCommand’s lifecycle.
Resolving By Name
So I got an idea: why not use the name of the constructor parameter as an indicator of what kind of implementation I need?
This requires writing a custom subresolver:
public class SubDependencyResolverByName : ISubDependencyResolver
{
public SubDependencyResolverByName(IKernel kernel, string componentPrefix)
{
this.kernel = kernel;
this.componentPrefix = componentPrefix;
}
public bool CanResolve(
CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
if (dependency.IsOptional)
return false;
return FindCandidateComponent(dependency.DependencyKey, dependency.TargetType) != null;
}
public object Resolve(
CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
ComponentModel dependencyResolvingComponent = FindCandidateComponent (dependency.DependencyKey, dependency.TargetType);
return kernel.Resolve(dependencyResolvingComponent.Name, dependency.TargetType);
}
protected ComponentModel FindCandidateComponent (string dependencyKey, Type targetType)
{
foreach (GraphNode node in kernel.GraphNodes)
{
ComponentModel visitedComponent = (ComponentModel) node;
if (visitedComponent.Service != targetType)
continue;
if (componentPrefix == null)
{
if (0 == string.Compare(visitedComponent.Name, dependencyKey, StringComparison.InvariantCultureIgnoreCase))
return visitedComponent;
}
else
{
if (false == visitedComponent.Name.StartsWith(componentPrefix, StringComparison.InvariantCultureIgnoreCase))
continue;
string nameWithoutPrefix = visitedComponent.Name.Substring(componentPrefix.Length);
if (0 == string.Compare (nameWithoutPrefix, dependencyKey, StringComparison.InvariantCultureIgnoreCase))
return visitedComponent;
}
}
return null;
}
private readonly IKernel kernel;
private readonly string componentPrefix;
}
…and attaching it to the container:
container.Kernel.Resolver.AddSubResolver ( new SubDependencyResolverByName (container.Kernel, "auto_"));
Results
Initially I had problems with this new resolver: it tried to be too smart and it messed with the existing (non-problematic) component wiring. So I decided to limit its scope only on dependency components which have a container ID starting with a certain prefix (in my case “auto_”). So if I want OneLinerDescriptor and DetailedDescriptor to be auto-detected by the resolver, I need to register them as “auto_OneLinerDescriptor” and “auto_DetailedDescriptor” in the Windsor container (casing is ignored). The resolver is currently limited to constructor dependencies only, but I see no reason it shouldn’t work for property injections too.
Is name-matching a good approach to auto-wiring components? I don’t know, time will tell. I certainly feel there’s something missing in how Windsor resolves dependencies by the default: type-matching is fine for simple scenarios, but as soon as you have more than one implementation of the same service interface, you need to specify service overrides or rely on "black magic” to wire things for you.


Krzysztof Ko?mic on 13 Jul 2010 at 23:25 #
I created similar experiment some time ago, also using subresolver: (the implementation is really bad and has few bugs so don’t look at it
)
http://kozmic.pl/archive/0001/01/01/convention-based-dependency-injection-with-castle-microkernelwindsor.aspx
There are the following information you have:
The only thing I would change from your registration, is I’d not mess with the name, but instead put a piece of metadata in ExtendedProperties.
If you think that’s a good thing to have, submit a patch to Windsor
breki on 14 Jul 2010 at 9:54 #
@Krzysztof,
Your code looks fine to me
. Although I’m not that familiar with Castle’s inner tubing (I have to do some reading on IHandlers, for example).
I’ve also found your other article which discusses using extended properties for component resolution: http://kozmic.pl/archive/2009/12/07/overriding-generic-componentrsquos-resolution-in-castle-windsor.aspx . So this seems to be a good staring point for implementing a better resolver.
I’m not sure custom attributes are the good approach though – I think developers would wish to keep their core assemblies Castle-agnostic. Unless the attributes themselves are Castle-agnostic.
I’ll make another post if/when I implement an improved mechanism, although I cannot promise any patches (I wouldn’t be able to test .NET 4.0 version, anyway).
Krzysztof Ko?mic on 14 Jul 2010 at 10:10 #
Igor,
Yes – the idea was that these would be domain custom attributes (Castle agnostic). I like the idea of using ExtendedProperties better anyway.
My implementation has one fatal flaw – it does not guard you against cyclic dependencies, which means you’d easily go into situation ending with StackOverflowException.
Chris Carter on 29 Jul 2010 at 2:24 #
Woo hoo! 3 hours later I finally found this post. Copy. Paste. Test. Done. THANK YOU!