Advanced Castle Windsor – generic typed factories, auto-release and more

This post is a playground for me, to try out some ideas I want to include in my talk about Windsor at KGD.NET meeting later this month.

Scenario

We have a messaging application built around two interfaces:

public interface Command
{
}
 
public interface Handler
{
    void Execute();
}
 
public interface Handler<T> : Handler where T : Command
{
    T Command { get; set; }
}

Hopefully I don’t have to explain how they work. The idea is, application receives commands from somewhere, then it pulls all handlers registered for this command and let them handle the command. Split of Handler interface into generic and non-generic part is there to make up for lack of co/contra-variance in .NET 3.5.

Commands and Handlers

Handlers are quite simple classes implementing closed version of Handler<> interface. For example to change client’s address we’d have the following command

[Serializable]
public class UpdateClientCorrespondenceAddressCommand : Command
{
    private readonly AddressDto address;
    private readonly Guid clientId;
 
    public UpdateClientCorrespondenceAddressCommand(Guid clientId, AddressDto address)
    {
        this.clientId = clientId;
        this.address = address;
    }
 
    public AddressDto Address
    {
        get { return address; }
    }
 
    public Guid ClientId
    {
        get { return clientId; }
    }
}

and its handler:

public class UpdateClientCorrespondenceAddressHandler : Handler<UpdateClientCorrespondenceAddressCommand>
{
    private readonly Repository<Client> clientRepository;
 
    public UpdateClientCorrespondenceAddressHandler(Repository<Client> clientRepository)
    {
        this.clientRepository = clientRepository;
    }
 
    public UpdateClientCorrespondenceAddressCommand Command { get; set; }
 
    public void Execute()
    {
        var command = Command;
        if (command == null) return;
 
        var client = clientRepository.Get(command.ClientId);
        client.ChangeCorrespondenceAddress(command.Address);
        clientRepository.Update(client);
    }
}

Nothing earth shattering here. We would have similar set up for other business events in the application. We assume we can have more than one handler for single command (for example another handler would update shipping costs and promotions available for the new address of the client).

The ability to pull multiple services from the container via typed factory is not available in Windsor 2.1.1 – you need the trunk version to take advantage of it.

Registration

To register the code we create an installer:

public class Installer : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<TypedFactoryFacility>()
            .Register(
                Component.For<ITypedFactoryComponentSelector>().ImplementedBy<HandlerSelector>(),
                Component.For<AutoReleaseHandlerInterceptor>(),
                AllTypes.FromAssemblyContaining<Program>()
                    .BasedOn(typeof(Repository<>))
                    .WithService.Base()
                    .Configure(c => c.LifeStyle.Singleton)
                    .BasedOn(typeof(Handler<>))
                    .WithService.Base()
                    .Configure(c => c.LifeStyle.Is(LifestyleType.Transient)
                                        .Interceptors<AutoReleaseHandlerInterceptor>()),
                Component.For<HandlerFactory>().AsFactory());
    }
}

There are a couple interesting things here. First we register typed factory facility, which we’ll use later on to pull handlers for commands we receive. Then we register custom selector for typed factory (discussed below), and an interceptor (discussed below). Then we  register all repositories and all handlers from given assembly, configuring handlers with transient lifestyle and with the interceptor we registered above. Lastly we also register typed factory for handlers:

public interface HandlerFactory
{
    Handler[] GetHandlersForCommand(Command command);
}

Typed factory selector

The handler factory has to do quite a lot of work for us. Given an instance of a command, it has to pull from the container all the handlers for the command’s type. To do this we need to use a custom selector (and trunk version of Windsor).

public class HandlerSelector:ITypedFactoryComponentSelector
{
    public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments)
    {
        Debug.Assert(arguments.Length == 1);
        var message = arguments[0];
        var handlerType = typeof(Handler<>).MakeGenericType(message.GetType());
        return new TypedFactoryComponentCollection(handlerType.MakeArrayType(), new Arguments(arguments));
    }
}

Based on the command’s type we create closed Handler<> type and return TypedFactoryComponentCollection (new type that pulls all components for given service) passing down the command as typed argument to the resolution.

Putting it all together

We can now use the code like this:

private static void Main()
{
    using(var container = new WindsorContainer().Install(new Installer()))
    {
        var factory = container.Resolve<HandlerFactory>();
 
        DoActualWork(factory);
        Console.ReadKey(true);
    }
}
 
private static void DoActualWork(HandlerFactory factory)
{
    var command = ImmitateCommandArrived();
 
    var handlers = factory.GetHandlersForCommand(command);
    foreach (var handler in handlers)
    {
        handler.Execute();
    }
}
 
private static Command ImmitateCommandArrived()
{
    return new UpdateClientCorrespondenceAddressCommand(Guid.NewGuid(), GetSomeAddress());
}

Notice how simple the calling code is. It has no knowledge of the (quite complex) process that takes place behind the scenes to create strongly typed instances of appropriate classes. It does not even know what actual type of command it got.

What about releasing transient handlers?

Isn’t this code too simple though? It resolves handlers, which are transient components and it does not release them. And we all know transient components need to be released in Windsor, right?

Well – it does release them actually, it just doesn’t do it explicitly. Remember we registered an interceptor with all handlers. Here’s how that interceptor looks like:

[Transient]
public class AutoReleaseHandlerInterceptor : IInterceptor
{
    private static readonly MethodInfo Execute = typeof(Handler).GetMethod("Execute");
    private readonly IKernel kernel;
 
    public AutoReleaseHandlerInterceptor(IKernel kernel)
    {
        this.kernel = kernel;
    }
 
    public void Intercept(IInvocation invocation)
    {
        if(invocation.Method!=Execute)
        {
            invocation.Proceed();
            return;
        }
 
        try
        {
            invocation.Proceed();
        }
        finally
        {
            kernel.ReleaseComponent(invocation.Proxy);
        }
    }
}

The interceptor releases the component after the call to Execute for us. Thanks to this we take the burden (no pun intended) of releasing the components from the callers, and we make sure our handlers won’t leak memory. This is quite a useful trick actually, and while I have precisely zero knowledge of NServiceBus, I think it could be used to fix the issue Davy discussed, without having to mess with release policy.


Posted 03-11-2010 9:13 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

Udi Dahan wrote re: Advanced Castle Windsor – generic typed factories, auto-release and more
on 03-13-2010 9:44 AM

Krzysztof,

The thing with NServiceBus is that handler invocation needs to be ordered as specified by the application developer. Thus we can't let the container resolve based on the generic type - we need to resolve the specific type.

Andy wrote re: Advanced Castle Windsor – generic typed factories, auto-release and more
on 04-12-2012 6:10 AM

Hi, I'm having trouble getting this to work in .Net 4 using Windsor 3.0. I thought I could do it using just the generic Handler interface, but I don't know what the return type should be from the HandlerFactory (Handlers<>[] clearly isn't possible).

Also, Visual Studio cannot resolve the types TypedFactoryComponent and TypedFactoryComponentCollection. Where are these?

OutOFTouch wrote re: Advanced Castle Windsor – generic typed factories, auto-release and more
on 11-29-2012 9:58 AM

I am confused a little by this statement

"It does not even know what actual type of command it got."  

Didn't the code explicitly create a specific command of type UpdateClientCorrespondenceAddressCommand?

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)