Aspect-Oriented Programming

The SOLID principles give us important guidance when it comes to writing maintainable software. The ‘O’ of the ‘SOLID’ acronym stands for the Open/closed Principle which states that classes should be open for extension, but closed for modification. Designing systems around the Open/closed principle means that new behavior can be plugged into the system, without the need to change any existing parts, making the chance of breaking existing code much smaller and prevent having to make sweeping changes throughout the code base. This way of working is often referred to as aspect-oriented programming.

Aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It allows new behavior to be plugged in or changed, without having to change or even recompile existing code. Simple Injector’s main support for AOP is by the use of decorators. Besides decorators, one can also plugin interception using a dynamic proxy framework.

This chapter discusses the following subjects:

Decoration

The best way to add new functionality (such as cross-cutting concerns) to classes is by the use of the decorator pattern. The decorator pattern can be used to extend (decorate) the functionality of a certain object at run-time. Especially when using generic interfaces, the concept of decorators gets really powerful. Take for instance the examples given in the Registration of open generic types section or for instance the use of an generic ICommandHandler<TCommand> interface.

Tip: This article describes an architecture based on the use of the ICommandHandler<TCommand> interface.

Take the plausible scenario where you want to validate all commands that get executed by an ICommandHandler<TCommand> implementation. The Open/Closed principle states that you want to do this without having to alter each and every implementation. You can achieve this using a (single) decorator:

public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
    private readonly IValidator validator;
    private readonly ICommandHandler<TCommand> decoratee;

    public ValidationCommandHandlerDecorator(
        IValidator validator, ICommandHandler<TCommand> decoratee)
    {
        this.validator = validator;
        this.decoratee = decoratee;
    }

    void ICommandHandler<TCommand>.Handle(TCommand command)
    {
        // validate the supplied command (throws when invalid).
        this.validator.ValidateObject(command);

        // forward the (valid) command to the real command handler.
        this.decoratee.Handle(command);
    }
}

The ValidationCommandHandlerDecorator<TCommand> class is an implementation of the ICommandHandler<TCommand> interface, but it also wraps / decorates an ICommandHandler<TCommand> instance. Instead of injecting the real implementation directly into a consumer, you can (let Simple Injector) inject a validator decorator that wraps the real implementation.

The ValidationCommandHandlerDecorator<TCommand> depends on an IValidator interface. An implementation that used Microsoft Data Annotations might look like this:

using System.ComponentModel.DataAnnotations;

public class DataAnnotationsValidator : IValidator
{
    void IValidator.ValidateObject(object instance)
    {
        var context = new ValidationContext(instance, null, null);

        // Throws an exception when instance is invalid.
        Validator.ValidateObject(instance, context, validateAllProperties: true);
    }
}

The implementations of the ICommandHandler<T> interface can be registered using the Register method overload that takes in a list of assemblies:

container.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);

By using the following method, you can wrap the ValidationCommandHandlerDecorator<TCommand> around each and every ICommandHandler<TCommand> implementation:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ValidationCommandHandlerDecorator<>));

Multiple decorators can be wrapped by calling the RegisterDecorator method multiple times, as the following registration shows:

container.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>));

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(DeadlockRetryCommandHandlerDecorator<>));

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ValidationCommandHandlerDecorator<>));

The decorators are applied in the order in which they are registered, which means that the first decorator (TransactionCommandHandlerDecorator<T> in this case) wraps the real instance, the second decorator (DeadlockRetryCommandHandlerDecorator<T> in this case) wraps the first decorator, and so on.

Tip: Are the previous three decorators applied in the correct order? This GitHub issue gives more insights into this.

Applying Decorators conditionally

There’s an overload of the RegisterDecorator available that allows you to supply a predicate to determine whether that decorator should be applied to a specific service type. Using a given context you can determine whether the decorator should be applied. Here is an example:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AccessValidationCommandHandlerDecorator<>),
    context => typeof(IAccessRestricted).IsAssignableFrom(
        context.ServiceType.GetGenericArguments()[0]));

The given context contains several properties that allows you to analyze whether a decorator should be applied to a given service type, such as the current closed-generic service type (using the ServiceType property) and the concrete type that will be created (using the ImplementationType property). The predicate will (under normal circumstances) be called only once per closed-generic type, so there is no performance penalty for using it.

Applying Decorators conditionally using type constraints

The previous example shows the conditional registration of the AccessValidationCommandHandlerDecorator<T> decorator. It is applied in case the closed TCommand type (of ICommandHandler<TCommand>) implements the IAccessRestricted interface.

Simple Injector will automatically apply decorators conditionally based on defined generic type constraints. You can, therefore, define the AccessValidationCommandHandlerDecorator<T> with a generic type constraint:

class AccessValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
    where TCommand : IAccessRestricted
{
    private readonly ICommandHandler<TCommand> decoratee;

    public AccessValidationCommandHandlerDecorator(ICommandHandler<TCommand> decoratee)
    {
        this.decoratee = decoratee;
    }

    void ICommandHandler<TCommand>.Handle(TCommand command)
    {
        // Do access validation
        this.decoratee.Handle(command);
    }
}

Because Simple Injector natively understands generic type constraints, you can reduce the previous registration to the following:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AccessValidationCommandHandlerDecorator<>));

The use of generic type constraints has many advantages:

  • It allows constraints to be specified exactly once, in the place it often makes most obvious, i.e. the decorator itself.

  • It allows constraints to be specified in the syntax you are used to the most, i.e. C#.

  • It allows constraints to be specified in a very succinct manner compared to the verbose, error prone and often hard to read syntax of the reflection API (the previous examples already shown this).

  • It allows decorator to be simplified, because of the added compile time support.

Obviously there are cases where these conditions can’t or shouldn’t be defined using generic type constraints. The following code example shows a registration that can’t be expressed using generic type constraints:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AccessValidationCommandHandlerDecorator<>),
    c => c.ImplementationType.GetCustomAttributes(typeof(AccessAttribute)).Any());

This registration applies the decorator conditionally based on an attribute on the (initially) decorated handler type. There is obviously no way to express this using generic type constraints, so you will have to fallback to the predicate syntax.

Decorators with Func<T> decoratee factories

There are certain scenarios where it is necessary to postpone the building of part of an object graph. For instance when a service needs to control the lifetime of a dependency, needs multiple instances, when instances need to be executed on a different thread, or when instances need to be created within a certain scope or context (e.g. security).

You can easily delay the building of part of the graph by depending on a factory; the factory allows building that part of the object graph to be postponed until the moment the type is actually required. However, when working with decorators, injecting a factory to postpone the creation of the decorated instance will not work. This is best demonstrated with an example.

Take for instance an AsyncCommandHandlerDecorator<T> that executes a command handler on a different thread. You could let the AsyncCommandHandlerDecorator<T> depend on a CommandHandlerFactory<T>, and let this factory call back into the container to retrieve a new ICommandHandler<T> but this would fail, because requesting an ICommandHandler<T> would again wrap the new instance with a AsyncCommandHandlerDecorator<T> and you’d end up recursively creating the same instance type again and again resulting in an endless loop.

This particular scenario is really hard to solve without library support and as such Simple Injector allows injecting a Func<T> delegate into registered decorators. This delegate functions as a factory for the creation of the decorated instance and avoids the recursive decoration explained above.

Taking the same AsyncCommandHandlerDecorator<T> as an example, it could be implemented as follows:

public class AsyncCommandHandlerDecorator<T> : ICommandHandler<T>
{
    private readonly Func<ICommandHandler<T>> decorateeFactory;

    public AsyncCommandHandlerDecorator(Func<ICommandHandler<T>> decorateeFactory)
    {
        this.decorateeFactory = decorateeFactory;
    }

    public void Handle(T command)
    {
        // Execute on different thread.
        ThreadPool.QueueUserWorkItem(state =>
        {
            try
            {
                // Create new handler in this thread.
                ICommandHandler<T> handler = this.decorateeFactory.Invoke();
                handler.Handle(command);
            }
            catch (Exception ex)
            {
                // log the exception
            }
        });
    }
}

This special decorator is registered just as any other decorator:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AsyncCommandHandlerDecorator<>),
    c => c.ImplementationType.Name.StartsWith("Async"));

The AsyncCommandHandlerDecorator<T> however, has only singleton dependencies (the Func<T> is a singleton) and the Func<ICommandHandler<T>> factory always calls back into the container to register a decorated instance conforming the decoratee’s lifestyle, each time it’s called. If, for instance, the decoratee is registered as transient, each call to the factory will result in a new instance. It is, therefore, safe to register this decorator as a singleton:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AsyncCommandHandlerDecorator<>),
    Lifestyle.Singleton,
    c => c.ImplementationType.Name.StartsWith("Async"));

When mixing this decorator with other (synchronous) decorators, you’ll get an extremely powerful and pluggable system:

container.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>));

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(DeadlockRetryCommandHandlerDecorator<>));

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AsyncCommandHandlerDecorator<>),
    Lifestyle.Singleton,
    c => c.ImplementationType.Name.StartsWith("Async"));

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ValidationCommandHandlerDecorator<>));

This configuration has an interesting mix of decorator registrations.

  1. The registration of the AsyncCommandHandlerDecorator<T> allows (a subset of) command handlers to be executed in the background (while any command handler with a name that does not start with ‘Async’ will execute synchronously)

  2. Prior to this point all commands are validated synchronously (to allow communicating validation errors to the caller)

  3. All handlers (sync and async) are executed in a transaction and the operation is retried when the database rolled back because of a deadlock

Warning: Please note that the previous example is just meant for educational purposes. In practice, you don’t want your commands to be processed this way, because it could lead to message loss. Instead you want to use a durable queue.

Another useful application for Func<T> decoratee factories is when a command needs to be executed in an isolated fashion, e.g. to prevent sharing the unit of work with the request that triggered the execution of that command. This can be achieved by creating a proxy that starts a new operation-specific scope, as follows:

using SimpleInjector.Lifestyles;

public class ScopedCommandHandlerProxy<T> : ICommandHandler<T>
{
    private readonly Container container;
    private readonly Func<ICommandHandler<T>> decorateeFactory;

    public ScopedCommandHandlerProxy(
        Container container, Func<ICommandHandler<T>> decorateeFactory)
    {
        this.container = container;
        this.decorateeFactory = decorateeFactory;
    }

    public void Handle(T command)
    {
        // Start a new scope.
        using (AsyncScopedLifestyle.BeginScope(container))
        {
            // Create the decorateeFactory within the scope.
            ICommandHandler<T> handler = this.decorateeFactory.Invoke();
            handler.Handle(command);
        };
    }
}

This proxy class starts a new async-scoped lifestyle and resolves the decoratee within that new scope using the factory. The use of the factory ensures that the decoratee is resolved according to its lifestyle, independent of the lifestyle of the proxy class. The proxy can be registered as follows:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ScopedCommandHandlerProxy<>),
    Lifestyle.Singleton);

Note: Because the ScopedCommandHandlerProxy<T> only depends on two singletons (both the Container and the Func<ICommandHandler<T>> are singletons), it too can safely be registered as singleton.

If you run (part of) your commands on a background thread and also use registrations with a scoped lifestyle you will have a use both the ScopedCommandHandlerProxy<T> and AsyncCommandHandlerDecorator<T> together which can be seen in the following configuration:

container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

container.Register<IUnitOfWork, DbUnitOfWork>(Lifestyle.Scoped);
container.Register<IRepository<User>, UserRepository>(Lifestyle.Scoped);

container.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ScopedCommandHandlerProxy<>),
    Lifestyle.Singleton);

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AsyncCommandHandlerDecorator<>),
    Lifestyle.Singleton,
    c => c.ImplementationType.Name.StartsWith("Async"));

With this configuration all commands are executed in an isolated context and some are also executed on a background thread.

Decorated collections

When registering a decorator, Simple Injector will automatically decorate any collection with elements of that service type:

container.Collection.Register<IEventHandler<CustomerMovedEvent>>(
    typeof(CustomerMovedEventHandler),
    typeof(NotifyStaffWhenCustomerMovedEventHandler));

container.RegisterDecorator(
    typeof(IEventHandler<>),
    typeof(TransactionEventHandlerDecorator<>),
    c => SomeCondition);

The previous registration registers a collection of IEventHandler<CustomerMovedEvent> services. Those services are decorated with a TransactionEventHandlerDecorator<TEvent> when the supplied predicate holds.

Note: Collections in Simple Injector behave as streams. Please see the section about collection types for more information.

For collections of elements that are created by the container (container controlled), the predicate is checked for each element in the collection. For collections of uncontrolled elements (a list of items that is not created by the container), the predicate is checked once for the whole collection. This means that only controlled collections can be partially decorated. Taking the previous example for instance, you could let the CustomerMovedEventHandler be decorated, while leaving the NotifyStaffWhenCustomerMovedEventHandler undecorated (determined by the supplied predicate).

When a collection is uncontrolled, it means that the lifetime of its elements are unknown to the container. The following registration is an example of an uncontrolled collection:

IEnumerable<IEventHandler<CustomerMovedEvent>> handlers =
    new IEventHandler<CustomerMovedEvent>[]
    {
        new CustomerMovedEventHandler(),
        new NotifyStaffWhenCustomerMovedEventHandler(),
    };

container.Collection.Register<IEventHandler<CustomerMovedEvent>>(handlers);

Although this registration contains a list of singletons, the container has no way of knowing this. The collection could easily have been a dynamic (an ever changing) collection. In this case, the container calls the registered predicate once (and supplies the predicate with the IEventHandler<CusotmerMovedEvent> type) and if the predicate returns true, each element in the collection is decorated with a decorator instance.

Warning: In general you should prevent registering uncontrolled collections. The container knows nothing about them, and can’t help you in doing diagnostics. With the lifetime of those items unknown, the container will be unable to wrap a decorator with a lifestyle other than transient. Best practice is to register container-controlled collections which is done by using one of the Collection.Register overloads that take a collection of System.Type instances.

Using contextual information inside decorators

As we shown before, you can apply a decorator conditionally based on a predicate you can supply to the RegisterDecorator overloads:

container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AsyncCommandHandlerDecorator<>),
    c => c.ImplementationType.Name.StartsWith("Async"));

Sometimes, however, you might want to apply a decorator unconditionally, but let the decorator act at runtime based on this contextual information. You can do this by injecting a DecoratorContext into the decorator’s constructor as can be seem in the following example:

public class TransactionCommandHandlerDecorator<T> : ICommandHandler<T>
{
    private readonly ITransactionBuilder builder;
    private readonly ICommandHandler<T> decoratee;
    private readonly TransactionType transactionType;

    public TransactionCommandHandlerDecorator(
        DecoratorContext decoratorContext,
        ITransactionBuilder builder,
        ICommandHandler<T> decoratee)
    {
        this.builder = builder;
        this.decoratee = decoratee;
        this.transactionType = decoratorContext.ImplementationType
            .GetCustomAttribute<TransactionAttribute>()
            .TransactionType;
    }

    public void Handle(T command)
    {
        using (var ta = this.builder.BeginTransaction(this.transactionType))
        {
            this.decoratee.Handle(command);
            ta.Complete();
        }
    }
}

The previous code snippet shows a decorator that applies a transaction behavior to command handlers. The decorator is injected with the DecoratorContext class which supplies the decorator with contextual information about the other decorators in the chain and the actual implementation type. In this example the decorator expects a TransactionAttribute to be applied to the wrapped command handler implementation and it starts the correct transaction type based on this information. The following code snippet shows a possible command handler implementation:

[Transaction(TransactionType.ReadCommitted)]
public class ShipOrderHandler : ICommandHandler<ShipOrder>
{
    public void Handle(ShipOrder command)
    {
        // Business logic here
    }
}

If the attribute was applied to the command class instead of the command handler, this decorator would been able to gather this information without the use of the DecoratorContext. This would, however, leak implementation details into the command—which type of transaction a handler should run is an implementation detail and is of no concern to the consumers of that command. Placing that attribute on the handler instead of the command is therefore a much more reasonable thing to do.

The decorator would also be able to get the attribute by using the injected decoratee, but this would only work if the decorator would directly wrap the handler. This would make the system quite fragile, as it would break once you start placing other decorator in between this decorator and the handler, which is a likely thing to happen.

Applying decorators conditionally based on consumer

The previous examples showed how to apply a decorator conditionally based on information about its dependencies, such as the decorators that it wraps and the wrapped real implementation. Another option is to make decisions based on the consuming components; the components the decorator is injected into.

Although the RegisterDecorator methods don’t have any built-in support for this, this behavior can be achieved by using the RegisterConditional methods. For instance:

container.RegisterConditional<IMailSender, AsyncMailSenderDecorator>(
    c => c.Consumer.ImplementationType == typeof(UserController));
container.RegisterConditional<IMailSender, BufferedMailSenderDecorator>(
    c => c.Consumer.ImplementationType == typeof(EmailBatchProcessor));

container.RegisterConditional<IMailSender, SmtpMailSender>(c => !c.Handled);

Here you use RegisterConditional to register two decorators. Both decorator will wrap the SmtpMailSender that is registered last. The AsyncMailSenderDecorator is wrapped around the SmtpMailSender in case it is injected into the UserController, while the BufferedMailSenderDecorator is wrapped when injected into the EmailBatchProcessor. Note that the SmtpMailSender is registered as conditional as well, and is registered as fallback registration using !c.Handled. This basically means that in case no other registration applies, that registration is used.

Decorator registration factories

In some advanced scenarios, it can be useful to depend the actual decorator type based on some contextual information. There is a RegisterDecorator overload that accepts a factory delegate that allows building the exact decorator type based on the actual type being decorated.

Take the following registration for instance:

container.RegisterDecorator(
    typeof(IEventHandler<>),
    factoryContext => typeof(LoggingEventHandlerDecorator<,>).MakeGenericType(
        typeof(LoggingEventHandler<,>).GetGenericArguments().First(),
        factoryContext.ImplementationType),
    Lifestyle.Transient,
    predicateContext => true);

In this example you register the LoggingEventHandlerDecorator<TEvent, TLogTarget> decorator for the IEventHandler<TEvent> abstraction. The supplied factory delegate builds up a partially closed generic type by filling in the TLogTarget argument, where the TEvent is left ‘open’. This is done by requesting the first generic type argument (the TEvent) from the open-generic LoggingEventHandler<,> type itself and using the ImplementationType as second argument. This means that when this decorator is wrapped around a type called CustomerMovedEventHandler, the factory method will create the type LoggingEventHandler<TEvent, CustomerMovedEventHandler>. In other words, the second argument is a concrete type (and thus closed), while the first argument is still a blank. When a closed version of IEventHandler<TEvent> is requested later on, Simple Injector will know how to fill in the blank with the correct type for this TEvent argument.

Tip: Simple Injector doesn’t care in which order you define your generic type arguments, nor how you name them—it will be able to figure out the correct type to build any way.

Note: The type factory delegate is typically called once per closed type and the result is burned in the compiled object graph. You can’t use this delegate to make runtime decisions.

Applying lifestyles to Decorators

Just as with any other registration, lifestyles can be applied to decorators. The following code snippet demonstrates this:

container.Register<IMessageSender, SmtpMessageSender>(Lifestyle.Singleton);

container.RegisterDecorator<IMessageSender, AsyncMessageSenderDecorator>(
    Lifestyle.Singleton);

The following code listing shows the definitions of SmtpMessageSender and AsyncMessageSenderDecorator:

class SmtpMessageSender : IMessageSender
{
    public void Send(string message) { ... }
}

class AsyncMessageSenderDecorator : IMessageSender
{
    private readonly IMessageSender decoratee;

    public AsyncMessageSenderDecorator(IMessageSender decoratee)
    {
        this.decoratee = decoratee;
    }

    public void Send(string message) { ... }
}

In this example, when IMessageSender is resolved, Simple Injector ensures that the same AsyncMessageSenderDecorator instance is always returned, which will reference the SmtpMessageSender instance. But Simple Injector does not always guarantee that a Singleton decorator will only have one instance—and for good reason, which we’ll explain below.

Warning: Lifestyles applied to decorators do not have the same uniqueness characteristics as with normal registrations. Lifestyles are applied to the decorator in combination with the wrapped service.

Consider the following variation of the previous code sample, but where there is not one IMessageSender, but instead a collection of IMessageSender components:

container.Collection.Append<IMessageSender, SmtpMessageSender>(Lifestyle.Singleton);
container.Collection.Append<IMessageSender, SmsMessageSender>(Lifestyle.Singleton);

container.RegisterDecorator<IMessageSender, AsyncMailSenderDecorator>(
    Lifestyle.Singleton);

In this case, the two implementations SmtpMessageSender and SmsMessageSender are registered as part of a collection of IMessageSender services. In this case, even though AsyncMailSenderDecorator is registered as Singleton, two decorator instances will exist: one that wraps SmtpMessageSender and one that wraps SmsMessageSender.

Consider what would have happened if Simple Injector would guarantee that only one AsyncMailSenderDecorator was ever created. As one AsyncMailSenderDecorator instance could only reference one single IMessageSender, Simple Injector would have to choose whether to inject SmtpMessageSender or SmsMessageSender, neither which is correct, because that would remove the other service from the collection. Making AsyncMailSenderDecorator truly unique would, therefore, cause Simple Injector to return a collection that would be shaped as follows:

var decorator = new AsyncMailSenderDecorator(new SmtpMessageSender());

// Two elements in the collection, so decorator should be returned twice.
return IMessageSender[] { decorator, decorator };

Instead, you would expect the collection to be shaped as follows (which is what Simple Injector actually does):

var decorator1 = new AsyncMailSenderDecorator(new SmtpMessageSender());
var decorator2 = new AsyncMailSenderDecorator(new SmsMessageSender());

return IMessageSender[] { decorator1, decorator2 };

What this means is that Simple Injector will guarantee uniqueness of a decorator, but this uniqueness is not global, but rather local to a specific registration.

Interception using Dynamic Proxies

Interception is the ability to intercept a call from a consumer to a service, and add or change behavior. The decorator pattern describes a form of interception, but when it comes to applying cross-cutting concerns, you might end up writing decorators for many service interfaces, but with the exact same code. If this is happening, it’s time to take a close look at your design. If, for what ever reason, it’s impossible for you to make the required improvements to your design, your second best bet is to explore the possibilities of Dynamic Interception through dynamic proxies.

Warning: Simple Injector has no out-of-the-box support for interception because the use of interception is an indication of a sub-optimal design and we are keen on pushing developers into best practices. Whenever possible, choose to improve your design to make decoration possible.

Using the Interception extensions code snippets, you can add the ability to do dynamic interception with Simple Injector. Using the given code, you can for instance define a MonitoringInterceptor that allows logging the execution time of the called service method:

private class MonitoringInterceptor : IInterceptor
{
    private readonly ILogger logger;

    // Using constructor injection on the interceptor
    public MonitoringInterceptor(ILogger logger)
    {
        this.logger = logger;
    }

    public void Intercept(IInvocation invocation)
    {
        var watch = Stopwatch.StartNew();

        // Calls the decorated instance.
        invocation.Proceed();

        var decoratedType = invocation.InvocationTarget.GetType();

        this.logger.Log(string.Format("{0} executed in {1} ms.",
            decoratedType.Name, watch.ElapsedMiliseconds));
    }
}

This interceptor can be registered to be wrapped around a concrete implementation. Using the given extension methods, this can be done as follows:

container.InterceptWith<MonitoringInterceptor>(type => type == typeof(IUserRepository));

This registration ensures that every time an IUserRepository interface is requested, a proxy is returned that wraps that instance and uses the MonitoringInterceptor to extend the behavior.

The current example doesn’t add much compared to simply using a decorator. When having many interface service types that need to be decorated with the same behavior however, it gets different:

container.InterceptWith<MonitoringInterceptor>(t => t.Name.EndsWith("Repository"));

Note: The Interception extensions code snippets use .NET’s System.Runtime.Remoting.Proxies.RealProxy class to generate interception proxies. The RealProxy only allows to proxy interfaces.

Note: the interfaces in the given Interception extensions code snippets are a simplified version of the Castle Project interception facility. If you need to create lots different interceptors, you might benefit from using the interception abilities of the Castle Project. Also please note that the given snippets use dynamic proxies to do the interception, while Castle uses lightweight code generation (LCG). LCG allows much better performance than the use of dynamic proxies. Please see this stackoverflow q/a for an implementation for Castle Windsor.

Note: Don’t use dynamic interception for intercepting types that all implement the same generic interface, such as ICommandHandler<T> or IValidator<T>. Try using decorator classes instead, as shown in the Decoration section on this page.