One of my favorite design pattern is the Decorator pattern. It's an elegant way to compose behavior without changing existing code. It's non-intrusive and makes the separation of concerns very clear between each class. Everything is then very easy to test and reuse.

So what's the problem?

The pain point I always have with this pattern is to create a long chain of decorator in a clean and simple way. It always ends up looking like this or even worst:

new LoggerDecorator(new ErrorHandlerDecorator(new CacheDecorator(new MyService())));

Moreover, this needs to be repeated every time I need MyService.


Hopefully, there are some solutions out there to tackle this specific problem. One of them is to use a DI framework like Autofac. Autofac already provides out of the box a nice construct to register decorators in your container and will make sure to resolve your decorator chain at runtime.

Extract from Autofac's documentation

var builder = new ContainerBuilder();

// Register the services to be decorated. You have to
// name them rather than register them As<ICommandHandler>()
// so the *decorator* can be the As<ICommandHandler>() registration.

// Then register the decorator. The decorator uses the
// named registrations to get the items to wrap.
    (c, inner) => new CommandHandlerDecorator(inner),
    fromKey: "handler");

var container = builder.Build();

// The resolved set of commands will have two items
// in it, both of which will be wrapped in a CommandHandlerDecorator.
var handlers = container.Resolve<IEnumerable<ICommandHandler>>();

Well... this is a bit better as we only have to register our chain of decorator once. However, the registration part is still hard to understand. Nesting a few builder.RegisterDecorator gets complex real fast.

The simplified approach

What I would like is a simple interface to get rid of most of the boiler plate Autofac code lines required for the builder.RegisterDecorator.
Something like this

builder.RegisterTypeWithDecorator<IMyService, MyService>()

Haaaaa, it feels much better and cleaner. Now let's try to implement this.

NOTE: The next part will be complicated, but it's ok. The goal is to abstract that complexity away, so we can use the nice methods above.


public interface IRegistrationDecoratorBuilder<TInterface, TImplementation>
    IRegistrationDecoratorBuilder<TInterface, TImplementation> WithDecorator<TDecorator>()
        where TDecorator : TInterface;

    // The return type is quite ugly, but expected by Autofac
    IRegistrationBuilder<TInterface, LightweightAdapterActivatorData, DynamicRegistrationStyle> CompleteDecoratorRegistration();


internal class RegistrationDecoratorBuilder<TInterface, TImplementation>
        : IRegistrationDecoratorBuilder<TInterface, TImplementation>
    private readonly ContainerBuilder _builder;
    private readonly IList<Type> _decoratorTypes = new List<Type>();

    public RegistrationDecoratorBuilder(ContainerBuilder builder)
        this._builder = builder;

    public IRegistrationDecoratorBuilder<TInterface, TImplementation> WithDecorator<TDecorator>()
        where TDecorator : TInterface

        return this;

    public IRegistrationBuilder<TInterface, LightweightAdapterActivatorData, DynamicRegistrationStyle>
        var registrationNameToDecorate = this.RegisterConcreteImplementationToDecorate();
        registrationNameToDecorate = this.GetDecoratorTypeExceptTheTopMost()
                (current, decoratorType) => this.RegisterDecorator(decoratorType, current));

        return this.RegisterTopMostDecorator(registrationNameToDecorate);

    private IEnumerable<Type> GetDecoratorTypeExceptTheTopMost()
        return this._decoratorTypes.Take(this._decoratorTypes.Count - 1);

    private string RegisterConcreteImplementationToDecorate()
        var registrationNameToDecorate = nameof(TImplementation);
        return registrationNameToDecorate;

    private string RegisterDecorator(Type decoratorType, string registrationNameToDecorate)
        var decoratorTypeName = decoratorType.Name;
        this._builder.RegisterType(decoratorType).Keyed(decoratorTypeName, decoratorType);
            (context, inner) => (TInterface)context.ResolveKeyed(
                new TypedParameter(typeof(TInterface), inner)),
        registrationNameToDecorate = decoratorTypeName;
        return registrationNameToDecorate;

    private IRegistrationBuilder<TInterface, LightweightAdapterActivatorData, DynamicRegistrationStyle>
        RegisterTopMostDecorator(string registrationNameToDecorate)
        var lastDecoratorType = this._decoratorTypes.Last();
        this._builder.RegisterType(lastDecoratorType).Keyed(lastDecoratorType.Name, lastDecoratorType);
        return this._builder.RegisterDecorator<TInterface>(
            (context, inner) => (TInterface)context.ResolveKeyed(
                new TypedParameter(typeof(TInterface), inner)),

Extension method

public static IRegistrationDecoratorBuilder<TInterface, TImplementation> RegisterTypeWithDecorator<TInterface,
        TImplementation>(this ContainerBuilder builder)
        where TImplementation : TInterface
    return new RegistrationDecoratorBuilder<TInterface, TImplementation>(builder);


Voilà! We abstracted all the complexity away with the magic of c# extension methods, so our new decorator builder adds up seamlessly to the Autofac container builder.