Skip to main content

Interception with Unity

I've already written about this here but this is such a obscure topic that it really doesn't hurt with some more examples. In this example we have a bookstore with two repositories defined as below.

public interface IBookRepository
{
    IList<Book> GetAll();
}

public interface IAuthorRepository { IList<Author> GetAuthorsForBook(string isbn); }

I would like to measure how long these calls take, but I don't want to change the implementation. This can be done with AOP and interception.

ICallHandler

We create a class that implements ICallHandler. This is the code that will intercept the calls.

public class MeasureLatencyCallHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        var watch = new Stopwatch();
        Debug.WriteLine("Begin: {0}", new[] { input.MethodBase.Name });

    watch.Start();
    var result = getNext()(input, getNext);
    watch.Stop();

    Debug.WriteLine(&quot;End: {0} ({1} ms, {2} ticks)&quot;, input.MethodBase.Name, watch.ElapsedMilliseconds, watch.ElapsedTicks);
    return result;
}

public int Order { get; set; }

}

The strange call getNext()(input, getNext) is the actual call to the method that is intercepted. The Order property controls the inner order of interceptions.

IMatchingRule

Interception is done by putting a proxy class on top of the class/interface that should be intercepted. But how do we control that only some methods on that class/interface should be interrupted? We implement a IMatchingRule.

public class AnyMatchingRule : IMatchingRule
{
    public bool Matches(MethodBase member)
    {
        return true;
    }
}

This matching rule always returns true, which means that we want to intercept everything on that class/interface. Otherwise we could use the MethodBase argument to return true or false.

Container configuration

Last, but not least, we have to tell the Unity container to intercept these interfaces with out MeasureLatencyCallHandler filtering the methods with our AnyMatchingRule.

container.AddNewExtension<Interception>();

container.RegisterType<IMatchingRule, AnyMatchingRule>("AnyMatchingRule"); container.RegisterType<ICallHandler, MeasureLatencyCallHandler>("MeasureLatencyCallHandler");

container.Configure<Interception>().AddPolicy("TracePolicy") .AddMatchingRule("AnyMatchingRule") .AddCallHandler("MeasureLatencyCallHandler");

container.Configure<Interception>().SetInterceptorFor(typeof(IBookRepository), new InterfaceInterceptor()); container.Configure<Interception>().SetInterceptorFor(typeof(IAuthorRepository), new InterfaceInterceptor());

example output

That's it! You will find the source here, or you can download as a zip archive.

comments powered by Disqus