31 Jul 2015 Comment

Autofac offers some good features for assembly scanning as well as support for registering open generic decorators.

In this post, I’ll demonstrate how these features can be extremely useful in composing a simple, extensible command pipeline for a CQRS-based architecture.

Commands and handlers

Our pipeline will consist of a set of commands - each its own class - and handlers. Each handler will be designed to deal with a single type of command by providing a closed-generic implementation of an IHandler<T> interface:

public interface IHandler<T>
{
    void Handle(T command);
}

public class FirePersonHandler : IHandler<FirePersonCommand>
{
    public void Handle(FirePersonCommand command)
    {
        Console.WriteLine("{0} was fired!", command.Name);
    }
}

If we have a number of these command/handler pairings, we can easily register them all with our IoC container in one go by using Autofac’s assembly scanning features:

builder.RegisterAssemblyTypes(someAssembly)
       .AsClosedTypesOf(typeof(IHandler<>));

At this stage, we already have a perfectly serviceable command pipeline. We can simply use constructor injection to inject an IHandler<FirePersonHandler> into any class in our application, call…

_handler.Handle(new FirePersonCommand { Name = "Frank" });

… and wave goodbye to Frank:

Frank was fired!

But what if we want to execute multiple different types of commands from within a single class? Injecting handlers for all of them will quickly bloat our constructors.

The command dispatcher

To better centralize the processing of our commands and allow us to execute different commands through a single dependency, let’s create a dispatcher. The dispatcher will receive a command - any command - and resolve the correct handler for us.

In order to achieve this, we’re going to need to create a class with a dependency on Autofac’s IComponentContext. So as not to couple the IoC container to the command dispatcher, I prefer to create an AutofacHandlerResolver which can be treated as part of the composition root (null checks excluded for brevity).

public class AutofacHandlerResolver : IHandlerResolver
{
    private readonly IComponentContext _context;

    public AutofacHandlerResolver(IComponentContext context)
    {
        _context = context;
    }

    public IHandler<T> Resolve<T>()
    {
        return _context.ResolveOptional<T>();
    }
}

Autofac will automatically resolve the IComponentContext dependency for us, so we don’t need to do any additional setup there.

Now we just need to create our command dispatcher, injecting the handler resolver…

public class CommandDispatcher : ICommandDispatcher
{
    private readonly IHandlerResolver _resolver;

    public CommandDispatcher(IHandlerResolver resolver)
    {
        _resolver = resolver;
    }

    public void Dispatch<T>(T command)
    {
        var handler = _resolver.Resolve<T>();
        if (handler != null)
        {
            handler.Handle(command);
        }
    }
}

… and, of course, register both components with the IoC container:

builder.RegisterType<AutofacHandlerResolver>()
                       .As<IHandlerResolver>();

builder.RegisterType<CommandDispatcher>().As<ICommandDispatcher>();

We can now inject an ICommandDispatcher - instead of individual command handlers - and easily execute any command without suffering from constructor bloat.

Adding some decorations

Now that our handlers are registered and our basic pipeline is in place, suppose we decide we want to log when any given command is handled.

We might decide to do this using the decorator pattern:

public class Logger<T> : IHandler<T>
{
    private readonly IHandler<T> _decorated;

    public Logger(IHandler<T> decorated)
    {
        _decorated = decorated;
    }

    public void Handle(T command)
    {
        Console.WriteLine("{0} executed.",
                          command.GetType().Name);

        _decorated.Handle(command);
    }
}

In order to register a decorator for a service, Autofac needs us to supply it with a key for the service to be decorated. Since all of our services were registered in one statement, we didn’t really get a good chance to assign keys to them.

We can work around this by taking over the type selection and explicitly mapping the resolved types to keyed services ourselves. Let’s update our handler registration.

builder.RegisterAssemblyTypes(someAssembly)
       .As(o => o.GetInterfaces()
                 .Where(i => i.IsClosedTypeOf(typeof(IHandler<>)))
                 .Select(i => new KeyedService("Handler", i)));

The As clause above works by retrieving - for each type in the scanned assembly - any closed generic implementations of our IHandler<T> interface and mapping each of them to a keyed service, where the key is "Handler". This is essentially the same as using the AsClosedTypesOf registration except the resulting registered services are keyed.

Let’s use Autofac’s built-in open generic decorator registration to add our decorator onto our handlers:

builder.RegisterGenericDecorator(typeof(Logger<>),
                                 typeof(IHandler<>),
                                 "Handler", "DecoratedHandler");

Now that we’re working with keyed services, we’ll also need to update our handler resolver to resolve by key.

public class AutofacHandlerResolver : IHandlerResolver
{
    private readonly IComponentContext _context;

    public AutofacHandlerResolver(IComponentContext context)
    {
        _context = context;
    }

    public IHandler<T> Resolve<T>()
    {
        return _context
            .ResolveOptionalKeyed<T>("DecoratedHandler");
    }
}

If we rehire Frank only to fire him again, we’ll now see:

FirePersonCommand executed.

Frank was fired!

We can also chain decorators as long as we ensure that the last one that we register is given the key that our handler resolver looks for:

// Decorate handlers with loggers
builder.RegisterGenericDecorator(typeof(Logger<>),
                                 typeof(IHandler<>),
                                 "Handler", "Logger");

// Decorate loggers with another decorator
builder.RegisterGenericDecorator(typeof(AnotherDecorator<>),
                                 typeof(IHandler<>),
                                 "Logger", "DecoratedHandler");                                     

Wrapping it up

All we need to do now is pull all of the registrations together to compose the full pipeline. Here’s how it might look as a custom module:

public class CommandModule : Module
{
    public override void Load(ContainerBuilder builder)
    {
        // Load the assembly containing the command handlers
        var assembly = Assembly.Load("CommandHandlers");

        // Scan the assembly and register keyed services
        builder.RegisterAssemblyTypes(assembly)
               .As(o => o.GetInterfaces()
               .Where(i => i.IsClosedTypeOf(typeof(IHandler<>)))
               .Select(i => new KeyedService("Handler", i)));

        // Decorate handlers with loggers
        builder.RegisterGenericDecorator(typeof(Logger<>),
                                         typeof(IHandler<>),
                                         "Handler", "Logger");

        // Register the handler resolver
        builder.RegisterType<AutofacHandlerResolver>()
               .As<IHandlerResolver>();

        // Register the command dispatcher
        builder.RegisterType<CommandDispatcher>()
               .As<ICommandDispatcher>();
    }
}

And there you have it - a simple, extensible command pipeline that can be easily augmented with decorators.