The bare bones of Unity interceptions

The Enterprise Library 4.1 was released together with Unity 1.2 in which a whole interception mechanism was added as part of the aspect-oriented approach to coding and a merge of the policy injection ideas. This little note is just a stepping stone if you wish to play with the new interception namespace.

The Enterprise Library 4.1 was released together with Unity 1.2 in which a whole interception mechanism was added as part of the aspect-oriented approach to coding and a merge of the policy injection ideas. This little note is just a stepping stone if you wish to play with the new interception namespace.

Interceptions through attributes on interfaces

In order to intercept things through attributes you need to define your own attributes based on the HandlerAttribute class, like this for instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class WatchAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new WatchHandler();
    }
}
public class WatchHandler : ICallHandler
{
    public int Order { get; set; }
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        Debug.WriteLine(string.Format("Method '{0}' on object '{1}' was invoked.", input.MethodBase.Name, input.Target.GetType()));
        return getNext()(input, getNext);
 
    }
 
}

Nothing extraordinary here except maybe the Order property on which more below. Next, you can put this attribute either on interface members or on the members of a class. Let’s use an interface first:

1
2
3
4
5
6
7
8
9
10
11
12
public interface IAction
{
    [Watch]
    void Run();
}
public class SomeAction : IAction
{
    public void Run()
    {
        //whatever
    }
}

The interception consists of ’something’ happening when the ‘Run’ method is called on any class implementing the IAction interface. This is quite a powerful feature; by defining an attribute and putting it on whatever interface member you can propagate some action to a wide set of classes. This gives a centralized handler across your all API, which is usually referred to as cross-cutting code in aspect-oriented terms.

Of course, in order to let things happen you need to weave it into a Unity container:

1
2
3
4
5
IUnityContainer container = new UnityContainer();
container.AddNewExtension< Interception>();
container.RegisterType< IAction, SomeAction>().Configure< Interception>().SetInterceptorFor< IAction>(new InterfaceInterceptor());
IAction action = container.Resolve< IAction>();
action.Run();

Notice the InterfaceInterceptor instance through which you tell the container to watch interceptions defined on an interface type.

On running the code you will see something like

Method ‘Run’ on object ‘DynamicModule.ns.Wrapped_IAction_7f6d32c1ea784597a6b488b524f25b0f’ was invoked.

in which you can see that some wrapping occured under the cap of Unity and a proxy was created to intercept the ‘Run’ calls.

Interceptions through attributes on virtual methods

The necessary code to intercept virtual methods is really the same as before except that now you need to use the VirtualMethodInterceptor rather than the InterfaceInterceptor:

1
container.Configure< Interception>().SetInterceptorFor< SomeAction>(new VirtualMethodInterceptor());

and instead of putting the Watch attribute on the interface you need to set it on a virtual method

1
2
3
4
5
6
7
8
public class SomeAction
{
    [Watch]
    public virtual void Run()
    {
        //whatever
    }
}

Interceptions through rules

The alternative to attribute based interceptions is to filter out the stuff you want to intercept through a rule, say like the following:

1
2
3
4
5
6
7
public class MyRule : IMatchingRule
{
    public bool Matches(MethodBase member)
    {
        return member.Name == "DoIt";
    }
}

The MethodBase gives you information on the member being part of some class and you could inject at this place some security code to check access to the member. This rule is baked into the container through the configuration of the Interception block:

1
2
3
4
5
6
7
8
9
10
11
IUnityContainer container = new UnityContainer();
container.AddNewExtension< Interception>();
container.RegisterType< MyClass>();
container.Configure<interception>()
    .AddPolicy("TheNameYouLike")
    .AddMatchingRule(new MyRule())
    .AddCallHandler(new WatchHandler());
container.Configure< Interception>().SetInterceptorFor< MyClass>(new TransparentProxyInterceptor());
MyClass c = container.Resolve< MyClass>();
c.DoIt();
</interception>

You can add multiple handlers to a rule but there is a catch here: the class you wish to intercept needs to inherit from MarshalByRefObject. While it doesn’t harm to let one of your classes inherit from it, it does represent a constraint in general.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyClass : MarshalByRefObject
{
    public virtual void DoIt()
    {
        //whatever you like
        return;
    }
    [InjectionConstructor]
    public MyClass()
    {
 
    }
}

If you scan the inheritance list of MarshalByRefObject you’ll not see many classes you use in mainstream code and, in fact, the MarshalByRefObject seems to me more a remnant of the remoting era. So, for practical purposes this could be a problem.

Order please

The ICallHandler has an Order property which allows you to organize handler if multiple have been assigned. As an experiment, define the following handlers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class WatchHandler : ICallHandler
{
    public int Order { get; set; }
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        Debug.WriteLine(string.Format("First watch: Method '{0}' on object '{1}' was invoked and caught in order {2}.", input.MethodBase.Name, input.Target.GetType(), Order));
        return getNext()(input, getNext);
 
    }
 
}
public class WatchHandler2 : ICallHandler
{
    public int Order { get; set; }
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        Debug.WriteLine(string.Format("Second watch: Method '{0}' on object '{1}' was invoked  and caught in order {2}.", input.MethodBase.Name, input.Target.GetType(),Order));
        return getNext()(input, getNext);
 
    }
 
}

and assign them like this

1
2
3
4
5
6
7
WatchHandler w1 = new WatchHandler { Order = 1};
WatchHandler2 w2 = new WatchHandler2 { Order = 2};
container.Configure< Interception>()
    .AddPolicy("TheNameYouLike")
    .AddMatchingRule(new MyRule())
    .AddCallHandler(w2)
    .AddCallHandler(w1);

Now switch the last two line of code and you will notice that it doesn’t matter in which order they are put there. This is because the Order property is called to organize them and we assigned a higher rank to the second handler. Not a formidable feature but you never know.

Tagged with:
 

2 Responses to “The bare bones of Unity interceptions”

  1. Vladimir Kofman says:

    Thanks for this article! Exactly what I’ve been looking for.

  2. Jeremy Regan says:

    This was helpful. The MSDN documentation leaves a lot to be desired for working examples such as you have provided. My only wish is that you had also provided the corresponding XML configuration for the policies that you used.

    To note, this interception mechanism leaves a lot to be desired in terms of implementation details. The .NET type system is not smart enough to know if you injected one type if it is inherited by another object registered in the container which is subject to interception. This is not a convolved example either; consider the case of a service layer with a base interface as the constructor argument. Even if multiple child interfaces inherit from it, each must register its policy to be subject to interception. Compared to Spring or Castle AOP, this is immature and aggravating to use. I suspect over time it will become better but it is lacking and shows how Microsoft cannot truly innovate, and still lag behind on some modern enterprise concepts that have been in use for years.

Leave a Reply