Advanced Castle Windsor: custom registration conventions for partially closed types

Jimmy published very interesting post about generic registration of certain partially closed types in StructureMap container. Go read the entire post first, it’s really worth it.

You’re back? OK. Jimmy uses StructureMap container in his sample, and after I saw it I immediately thought about doing the same thing in Windsor. That’s what this post is all about – how to make the following test pass:

Test

 

[Test]
public void Should_connect_delete_handler()
{
    var container = new WindsorContainer();
    container.AddFacility<HandlerFacility>();
    container.Register(AllTypes.FromAssemblyContaining<DeleteCustomerCommand>()
                        .BasedOn<IEntity>()
                        .BasedOn(typeof(IHandler<>)).WithService.Base()); // [a]
 
    var handler = container.Resolve<IHandler<DeleteEntityCommand<Customer>>>();
    Assert.IsInstanceOf<DeleteEntityCommandHandler<Customer>>(handler);
}

Solution

The line marked with [a] registers types implementing IHandler<>. It will register DeleteEntityCommandHandler<> with IHandler<>.  This is the equivalent of StructureMap’s ConnectImplementationToTypesClosing in Windsor.

As you can see I also registered a facility – HandlerFacility which does the actual magic, and is unsurprisingly quite similar to Jimmy’s DeleteCommandRegistrationConvention.

public class HandlerFacility : AbstractFacility
{
    private static readonly Type openDeleteCommandType = typeof(DeleteEntityCommand<>);
    private static readonly Type openHandlerInterfaceType = typeof(IHandler<>);
    private static readonly Type openDeleteCommandHandlerType = typeof(DeleteEntityCommandHandler<>);
 
    protected override void Init()
    {
        Kernel.HandlerRegistered += OnHandlerRegistered;
    }
 
    private void OnHandlerRegistered(IHandler handler, ref bool statechanged)
    {
        var type = handler.ComponentModel.Implementation;
        if (type.IsAbstract || typeof(IEntity).IsAssignableFrom(type) == false)
        {
            return;
        }
 
        var closedDeleteCommandType = openDeleteCommandType.MakeGenericType(type);
        var closedHandlerInterfaceType = openHandlerInterfaceType.MakeGenericType(closedDeleteCommandType);
        var closedDeleteCommandHandlerType = openDeleteCommandHandlerType.MakeGenericType(type);
 
        Kernel.Register(
            Component.For(closedHandlerInterfaceType)
                .ImplementedBy(closedDeleteCommandHandlerType)
                .LifeStyle.Transient);
    }
}

Just to set the record straight - you don’t really need a facility for that .You could hook an anonymous delegate to container kernel’s event and do that work inline. Having a facility is however my preferred solution since it encapsulates the work nicely, and gives you access to configuration, provided you’d ever want to externalize some part of the facility.

That’s all we needed to make the test pass:

sshot-1


Posted 01-07-2010 7:51 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)