Convention based Dependency Injection with Castle MicroKernel/Windsor

Quiz

Consider the following piece of code (it shows Castle MicroKernel, but since Windsor is built on top of MicroKernel, it works the same way):

IKernel kernel = new DefaultKernel();
kernel.AddComponent("sms", typeof(IAlarmSender), typeof(SmsSender));
kernel.AddComponent("email", typeof(IAlarmSender), typeof(EmailSender));
 
kernel.AddComponent("generator", typeof(AlarmGenerator));
 
AlarmGenerator gen = (AlarmGenerator) kernel["generator"];

Considering AlarmGenerator has a dependency on IAlarmSender, which one of two registered components will it get?

The answer is: the first one.

In this case we registered SmsSender first, so it will get injected. If we switched the order of registration, EmailSender would get injected. It does not matter if you specify a name when registering or not.

I don’t know how other containers handle this problem, but this approach in general is as good as any (and by any I mean any other than ‘throw new IDontKnowWhatToDoException()’).

That was easy, wasn’t it?

Now, let’s get to another one. We have a class:

public class Person
{
 public Person( IClock leftHandClock )
 {
  this.LeftHandClock = leftHandClock;
 }
 
 public IClock LeftHandClock { get; private set; }
 public IClock RightHandClock { get; set; }
}

An interface, and two implementing types:

public interface IClock{}
public class IsraelClock : IClock{}
public class WorldClock : IClock{}

Then, if we register these like this:

IWindsorContainer container = new WindsorContainer().
    AddComponent<IClock, WorldClock>( "leftHandClock" ).
    AddComponent<IClock, IsraelClock>( "rightHandClock" ).
    AddComponent<Person>();
var joe = container.Resolve<Person>();
 

What watches will our Joe wear on each hand?

The answer is: the first one. Again.

So in this case Joe will have a WorldClock on both wrists (the same instance to be exact since components in MicroKernel are singletons by default, but that’s besides the point).

Idea

That’s not that intuitive is it? I mean, you could certainly make it work that way, but that would require you to configure the container for it. This however seems like a perfect place to utilize a Convention Over Configuration approach.

I got this idea yesterday and decided to try to implement it in MicroKernel. I also tweeted about it, and Philip Laureano (author of LinFu, and recently Hiro) and Nate Kohari (author of NInject… and recently NInject2) seem to like that idea.

So here’s my initial naive take at it.

Code

Luckily, thanks to wonderful extensibility of Castle you don’t have to modify the container itself. All you need to do is to extend it, with custom SubDependencyResolver. Here’s my initial naive implementation, which I did in couple of minutes, as a proof of concept.

public class ConventionBasedResolver : ISubDependencyResolver
{
    private IKernel _kernel;
    private IDictionary<DependencyModel, string> _knownDependencies = new Dictionary<DependencyModel, string>();
 
    public ConventionBasedResolver( IKernel kernel )
    {
        if( kernel == null )
        {
            throw new ArgumentNullException( "kernel" );
        }
        this._kernel = kernel;
    }
 
    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
    {
        string componentName;
        if (!this._knownDependencies.TryGetValue(dependency, out componentName))
        {
            componentName = dependency.DependencyKey;
        }
        return _kernel.Resolve(componentName, dependency.TargetType);
    }
 
    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
    {
        if (this._knownDependencies.ContainsKey(dependency))
            return true;
 
        var handlers = this._kernel.GetHandlers(dependency.TargetType );
 
        //if there's just one, we're not interested.
        if(handlers.Length<2)
            return false;
        foreach( var handler in handlers )
        {
            if( IsMatch( handler.ComponentModel, dependency ) && handler.CurrentState == HandlerState.Valid )
            {
                if( !handler.ComponentModel.Name.Equals( dependency.DependencyKey, StringComparison.Ordinal ) )
                {
                    this._knownDependencies.Add( dependency, handler.ComponentModel.Name );
                }
                return true;
            }
        }
        return false;
    }
 
    private bool IsMatch( ComponentModel model, DependencyModel dependency )
    {
        return dependency.DependencyKey.Equals( model.Name, StringComparison.OrdinalIgnoreCase );
    }
}

Now, we need to add the sub resolver to the container:

container.Kernel.Resolver.AddSubResolver( new ConventionBasedResolver( container.Kernel ) );

And we’re done.

Wrapping up

We now have basic convention based injection of both properties as well as constructor parameters. With a little bit of work we might extend it a further to provide pluggable conventions.

For example matching by namespace (prefer close neighbors), by name (for service IFoo, first try to find if Foo is available, then try DefaultFoo, then FooImpl) or any other. The possibilities are endless.

If you have any ideas on how to extend or best use this approach, leave a comment.

Comments

Hey Krzysztof, believe or not, I was trying exactly the same thing yesterday evening. This is something I absolutely need for a very big project (or we might drop Windsor in favor of Ninject). I can give you feedback on some real-world use cases if you want.

Sure I want. My sample is just a proof of concept. If you have some real life scenarios for it, this would be far more interesting as a guide for how to implement it in the framework itself.