Dynamic Method Interception with Autofac

WTF?

Dynamic Interception is a facet of AOP, in which by means of some magic, a call to a target object is intercepted by a proxy which can do things before and after the actual target invocation takes place. It’s some pretty awesome shite. We can use it to handle things like intrumentation and authentication etc; cross-cutting concerns which are a noisy otherwise. Note that AOP does bring with it some complexity and “magic” which would normally see me running for the hills; but I feel that the wins here are potentially so great that it’s worth knowing that you can do this.

How do you do it?

Everyone uses the Castle DynamicProxy to do it, because Krzysztof is insanely smart and it just works. My IOC container of choice is Autofac.

The first thing you need to do is create an Interceptor, which inherits from Castle.DynamicProxy.IInterceptor:

[sourcecode language=”csharp”]

public class InstrumentationInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var correlationId = Guid.NewGuid();
DateTime startDate = DateTime.Now;
UltimaTrace.TraceInformation("{0} {1} – {3}.{2} started", startDate, correlationId, invocation.Method.Name, invocation.TargetType.Name);
UltimaEventSource.Log.Message2("{0} {1} – {3}.{2} started", startDate, correlationId, invocation.Method.Name, invocation.TargetType.Name);

invocation.Proceed();

DateTime endDate = DateTime.Now;
UltimaTrace.TraceInformation("{0} {1} – {3}.{2} ended ({4}ms elapsed)", endDate, correlationId, invocation.Method.Name, invocation.TargetType.Name, (endDate – startDate).TotalMilliseconds);
UltimaEventSource.Log.Message2("{0} {1} – {3}.{2} ended ({4}ms elapsed)", endDate, correlationId, invocation.Method.Name, invocation.TargetType.Name, (endDate – startDate).TotalMilliseconds);
}
}

[/sourcecode]

In the code above, the interceptor, aptly named InstrumentationInterceptor, times the call to the target. The call to invocation.Proceed(); is where control is forwarded onto the original target object. I am simply recording the time taken to make the call.

Next, you need to wire up the interceptor:

[sourcecode language=”csharp”]

public class SharedModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new InstrumentationInterceptor())
.Named<IInterceptor>("instrumentation-interceptor");
}
}

[/sourcecode]

The code above is of an Autofac Module, which is registering the component and naming it, so that we can refer to it later by name.

Now we need to get interception taking place for the components we care about instrumenting:

[sourcecode language=”csharp”]

public class DomainModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<OrderDispatcher>().As<IOrderDispatcher>()
.SingleInstance()
.EnableInterfaceInterceptors()
.InterceptedBy("instrumentation-interceptor");

builder.RegisterType<OrderBook>().As<IOrderBook>();
}
}

[/sourcecode]

When we register the OrderDispatcher above, first we turn on interception with the call to EnableInterfaceInterceptors(), and we supply the interceptor to use by the name we provided before. You can skip doing this here and attribute the classes you want to intercept instead with the [Intercept(“instrumentation-interceptor”)] attribute.

I now have instrumentation tracing at the information level available available whenever I need to pay attention to it. Pretty damn awesome.

To complex for you?

An alternative would be to use the Decorator Pattern to decorate whatever you wanted to instrument with an “InstrumentationDecorator” or some such thing. I’ll blog that some other time.