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.

  • Artur Dorochowicz

    Interesting. The thing with NSB is that it does handler discovery and registration by itself, so I think one would need to reconfigure message handlers in container with interceptor after NSB does its configuration. Something with Kernel.GetHandlers?, is this a good direction?

  • Well I was actually thinking about it as solution in NServiceBus Castle provider’s code.

    From Castle’s perspective I’d rather use IModelInterceptorSelector and inject ReleasingInterceptor for all MessageHandlers you resolve. This way is the most transparent to the rest of the code.

  • Artur Dorochowicz

    This is brilliant.

    I guess, I will never stop getting amazed by Windsor’s awesomeness.

  • John Simons

    Not sure if you want to add ".WithService.Base()", because if you do, then classes that do not implement Handler<> directly do not get intercepted!
    Also, I like more Handles<> instead of Handler<> 🙂

  • @John,

    Can you give me an example of the scenario you mentioned?

    public class SubHandlerImpl : UpdateClientCorrespondenceAddressHandler
    {
    public SubHandlerImpl(Repository<Client> clientRepository) : base(clientRepository)
    {
    }
    }

    this class does not impl Handler<> directly, and it will be properly resolved, called, intercepted and realeased.

  • Does it handle forwarded types, though? An nServiceBus saga would handle a lot of different messages.

    I’m going to have to get my head around these improvements… after I finish the build work.

  • John Simons

    Hmmm, that is interesting because I have similar code to yours and when I added ".WithService.Base()" in the registration, I couldn’t resolve Handlers that were not directly implementing interface.
    So to fix it I removed that, and everything worked again.
    Anyway, this is an area that is quite difficult to understand:
    .WithService.Base() vs .WithService.FromInterface() vs nothing

  • @Julian

    in v2.1.1 (and later) I’m pretty sure it does.
    in v2.0 it didn’t due to a bug.

  • Krzysztof,

    I’ve been using a similar thing for some time now (I got the idea from Jeremy D. Miller’s EventAggregator postings). But in my case the handlers are long-running objects (like forms or controls), so I’m not doing any releasing immediately after the invocation.

    What happens if you Release a singleton like you did in the interceptor?

  • @Igor

    Nothing happens. Or more precisely – nothing you wouldn’t expect. Singleton (if it implemented IDisposable) would be disposed when the container gets disposed, regardless of whether you Release it or not.

  • Krzysztof, please help & look at this question:
    stackoverflow.com/…/circular-interfaces-depen…

    probably it’s easy for you.

    [Polish:On].. i pomóż jak rodak rodakowi 🙂 … [Polish:Off]

  • John Simons

    Krzysztof,

    Why did you marked the interceptor class as Transient?
    You don’t have any state in that class.

    Cheers
    John

  • John,

    There are two parts to the answer here.

    1. I had the state in my first take at it, but factored it out.
    2. Interceptors should be transient. You should have really good reason to make it otherwise.