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.