Autofac 2.4 is just around the corner, with beta builds now available via the project site (the short list of changes since 2.3 is available here.) One of the enhancements coming with this release is improved support for wiring up components in the Decorator Pattern.

Circa Autofac 2.2 we introduced container support for the Adapter Pattern. An Adapter takes a service and exposes its functionality through a different interface. While it has always been possible to implement adapters in Autofac using the basic APIs, adding container support for “bottom-up” composition makes it easier to implement adaptation reliably on all implementations of an adapted service.

Decorators are a similar story. Given an implementation of a service, a decorator takes that implementation and modifies its functionality, exposing the same interface.

interface ICommandHandler { }

class CommandHandler : ICommandHandler { }

class TransactedCommandHandler : ICommandHandler {
    public TransactedCommandHandler(
        ICommandHandler decorated,
        ISession session) { }
}

Here the TransactedCommandHandler is a decorator for the ICommandHandler service, that adds transaction management via a persistence session. The CommandHandler component provides the actual implementation of the service.

Decorator structure

Decorator structure

Decorators by Hand

In Autofac the components for this scenario can be registered without any special decorator support:

var builder = new ContainerBuilder();

builder.RegisterType<CommandHandler>()
    .Named<ICommandHandler>("implementor");

builder.Register(c => new TransactedCommandHandler(
        c.ResolveNamed<ICommandHandler>("implementor"),
        c.Resolve<ISession>())
    .As<ICommandHandler>();

This takes advantage of a named service to identify the implementor, and thus link it up to its decorator which is registered to provide the service type (not named.)

Clean and straightforward – and recommended if your scenario is as simple as the one above. If you have more than one component that you’d like decorated, or want to use decorators with open generics, then things can get more complicated rather quickly.

Drawing on a lot of inspiration from the design philosophy of MEF, Autofac has good support for handling n things like this. In 2.4, we use that support to automate some of the process of configuring decorators.

IoC Design Tip: When you’re looking for abstractions to use as services in an application, prefer those that describe a set of related things. Zero-or-more type relationships are less brittle in the face of change than exactly one or zero-or-one relationships.

RegisterDecorator() and RegisterGenericDecorator()

There are two new registration methods for decorators in Autofac 2.4 – a non-generic and a generic version.

The non-generic version, when applied to the scenario above, looks like:

var builder = new ContainerBuilder();

builder.RegisterType<CommandHandler>()
    .Named<ICommandHandler>("implementor");

builder.RegisterDecorator<ICommandHandler>(
        (c, inner) => new TransactedCommandHandler(inner, c.Resolve<ISession>()),
        fromKey: "implementor");

The first thing you’re probably thinking is “hey, this isn’t any less code than the old way!” That’s very likely true, but reducing the amount of code involved wasn’t a goal here.

The difference between this code, using RegisterDecorator and the first example is that this version decorates all implementations of ICommandHandler, so if additional command handlers are registered (using the “implementor” name) then they will each get their own decorator.

There are some diagrams in the adapter article previously linked that describe the object graph structure; reading that article will shed some light on what I’m talking about here if the details are a bit foggy.

RegisterDecorator() works a lot like Autofac’s typical delegate-based component registration methods. The things to note are:

  • The generic parameter (here ICommandHandler) is the service that is being decorated.
  • The method accepts a delegate that, given the context c and the implementation of the service being decorated inner, produces an instance of the decorator.
  • The final pair of parameters are fromKey and toKey (optional) that describe where this decorator sits in the chain from implementation up to the topmost decorator. This works the same way as in the decoration-by-hand example earlier.

RegisterGenericDecorator() is similar to its non-generic counterpart, but deals with cases where the decorated service is an open generic one. Given a generic alternative to the earlier example:

interface ICommandHandler<TCommand> { }

class CommandHandler<TCommand> : ICommandHandler<TCommand> { }

class TransactedCommandHandler<TCommand> : ICommandHandler<TCommand> {
    public TransactedCommandHandler(
        ICommandHandler<TCommand> decorated,
        ISession session) { }
}

Setting up the same decorator structure is done using:

var builder = new ContainerBuilder();

builder.RegisterGeneric(typeof(CommandHandler<>))
    .Named("implementor", typeof(ICommandHandler<>));

builder.RegisterGenericDecorator(
        typeof(TransactedCommandHandler<>),
        typeof(ICommandHandler<>),
        fromKey: "implementor");

It is worth noting that while the decorator is an open generic type, the decorated components don’t have to be. So, if there are concrete command handler types:

builder.RegisterType<AddCommandHandler()
    .Named<ICommandHandler<AddCommand>>("implementor");

The generic decorator will be applied to each concrete implementation as expected.

There are other ways of implementing decorator support and different choices that can be made about how the APIs should work. There are certainly some big trade-offs made in this implementation; in most of them, simplicity and orthogonality trumped concision or ‘magic.’ A discussion of these decisions almost made it into this article, but I worried about this obscuring the more useful and concrete content. If you have any questions about why things are done this way please do post a comment!