CHAPTER 4
Aspect-Oriented Programming (AOP) is about the ability to inject cross-cutting behavior (aspects) in existing code so as to do useful yet somewhat lateral operations transparently. This is called, in Unity terms, interception. Some examples include:
Other examples exist, of course. Aspects are applied to target code in a totally transparent way; that is, you just call your methods in the usual way and interception occurs magically. For now, let’s understand how Unity helps us applying aspects.
Interception in .NET can be implemented in one of the following five ways:
Some of these techniques can be applied to existing instances (instance interception) or to Unity-created ones (type interception). In any case, they only apply to instance, not static methods. The following table lists just that:
Table 2: Interception kinds and targets
Interception | Kind | Target | What Can Be Intercepted |
Virtual method | Type | Non-sealed classes with virtual methods. | All virtual methods, properties, and event add and remove handlers. |
Interface | Instance | Existing classes implementing an interface. | All interface methods, properties, and event add and remove handlers. |
Transparent proxy | Instance | Existing classes implementing an interface or inheriting from MarshalByRefObject. | All interface methods, properties, and event add and remove handlers (in the case of interfaces) or all virtual methods, properties, and event add and remove handlers (for MarshalByRefObject-derived classes). |
Interception, if enabled, is applied automatically. But before we can use it, we need to configure what interceptor to use per registration. Unity includes the following interceptors, which cover the most typical scenarios:
The base interfaces that specify the interception kinds, IInstanceInterceptor and ITypeInterceptor, expose a small number of methods. Worthy of note are two methods that both interfaces inherit from IInterceptor:
Depending on the registration key, we need to set the proper interceptor; this is the one that will build our interception proxy for the target instance or type. Before we look at how to configure it, let’s understand how interception is implemented. But, even before that, let’s get EnterpriseLibrary.PolicyInjection, a required package from NuGet. This is where all interception-related classes are defined and is a prerequisite for this chapter.

Figure 9: Installing Policy Injection as a NuGet package
We can also add one or more interfaces to the generated proxy. In this case, we will need to implement—either in a behavior or in a call handler (see the next sections)—all of its methods and properties. We shall see an example later on.
Interception means that all calls to a method, property, event add, or remove handler are diverged to custom code. In it, we decide what to do before or after (or instead of) the call to the original code.
In Unity, the atomic unit by which we can perform interception is the ICallHandler interface. Its interface is very simple:
public interface ICallHandler { IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext); int Order { get; set; } } |
The Invoke method is the one to where the action actually goes. It receives the execution context—the instance where the method invocation was made and any method parameters—as well as a delegate for the next handler.
The Order property tells Unity how to sort all call handlers that are applied to the same target.
Let’s see an example that measures the time that it took a method to execute:
public class MeasureCallHandler : ICallHandler { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { var watch = Stopwatch.StartNew(); var result = getNext()(input, getNext); var time = watch.ElapsedMilliseconds; var logger = ServiceLocator.Current.GetInstance<ILogger>(); logger.Log(String.Format( "Method {0} took {1} milliseconds to complete", input.MethodBase, time)); return (result); } public int Order { get; set; } } |
The call to getNext()(input, getNext) is normally always present in a call handler, and it tells Unity to execute the target method or property that the call handler is intercepting. Its result is a value suitable for returning from Invoke and contains the actual returned value from the intercepted method if it is not void.
The MethodBase property contains a reference to the intercepted method. If you want to see if this method is a property getter or setter, you can use:
if (input.MethodBase.IsSpecialName && ( input.MethodBase.Name.StartsWith("get_") || input.MethodBase.Name.StartsWith("set_"))) { } |
Or an event handler add or remove method:
if (input.MethodBase.IsSpecialName && ( input.MethodBase.Name.StartsWith("add_") || input.MethodBase.Name .StartsWith("remove_"))) { } |
Target is the targeted object instance that contains the intercepted method.
Arguments contains a collection of all method parameters, if any.
InvocationContext is a general-purpose dictionary indexed by string and storing objects, where call handlers targeting the same method or property can share data.
After calling the base implementation, we get a result from which we can obtain the actual returned value, if the method was not void (ReturnValue) and did not return an exception or the exception that was thrown (Exception).
If we want to return a value without actually executing the intercepted method, we can use the CreateMethodReturn method. In its simplest form, it just takes a value to return for non-void methods which, of course, must match the method’s expected return type:
public class NullCallHandler : ICallHandler { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { return (input.CreateMethodReturn(null)); } public int Order { get; set; } } |
And, if we want to return an exception instead, we call CreateExceptionMethodReturn:
public class ExceptionCallHandler : ICallHandler { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { return (input.CreateExceptionMethodReturn(new NotImplementedException())); } public int Order { get; set; } } |
If we have two call handlers configured for the same method, we can pass values from the first to the second:
public class MessagingCallHandler : ICallHandler { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { if (input.InvocationContext.ContainsKey("message") == true) { //someone got here first... } else { input.InvocationContext["message"] = "I was here first"; } return (getNext()(input, getNext)); } public int Order { get; set; } } |
A call handler only applies to a single interception target (a method or property). Unity offers another construction for intercepting all calls to all interceptable members of a class, called an interception behavior.
An interception behavior is a class that implements IInterceptionBehavior. Again, it is a simple interface although slightly more complex than ICallHandler. Its contract is this:
public interface IInterceptionBehavior { IEnumerable<Type> GetRequiredInterfaces(); IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext); bool WillExecute { get; } } |
Method GetRequiredInterfaces is a way developers can use to force the behavior to only run if the target class implements one or more specific interfaces. In most cases, we just return an empty collection.
Invoke is exactly the same as in ICallHandler so there’s no point in discussing it again.
Property WillExecute is used to tell Unity if the behavior should be applied or not. If it returns false, method Invoke will not run.
Note: Since WillExecute receives no context, it is hard to use. Most of the time we just return true.
Note: The difference between call handlers and behaviors is that behaviors intercept all interceptable methods in a class whereas call handlers intercept just one.
A simple interception behavior:
public class MyInterceptionBehavior : IInterceptionBehavior { IEnumerable<Type> IInterceptionBehavior.GetRequiredInterfaces() { return (Type.EmptyTypes); }
IMethodReturn IInterceptionBehavior.Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { //before base call Console.WriteLine("About to call method {0}", input.MethodBase); var result = getNext().Invoke(input, getNext); if (result.Exception != null) { Console.WriteLine("Method {0} returned {1}", input.MethodBase, result.ReturnValue); } else { Console.WriteLine("Method {0} threw {1}", input.MethodBase, result.Exception); } //after base call return (result); }
bool IInterceptionBehavior.WillExecute { get { return (true); } } } |
We configure interception on an interceptable property or method by applying a HandlerAttribute that returns an instance of an ICallHandler. For example, imagine you have an implementation of ICallHandler called CachingHandler, you could write a host attribute for it as this:
[Serializable] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class CachingHandlerAttribute : HandlerAttribute { public CachingHandlerAttribute(int hours, int minutes, int seconds) { this.Duration = new TimeSpan(hours, minutes, seconds); } public TimeSpan Duration { get; public set; } public override ICallHandler CreateHandler() { return (new CachingHandler(this.Duration) { Order = this.Order }); } } |
After we have our attribute, it’s just a matter of applying it to a method. When Unity resolves the containing class, it will recognize it:
[CachingHandler(1, 0, 0)] //1 hour, 0 minutes, 0 seconds void DoLongOperation(int someParameter, int anotherParameter); |
See chapter Chapter 5 Extending Unity for a full implementation.
Note: Interception attributes can be applied to either the key or the component type.
First, we need to tell Unity to use the Interception extension:
unity.AddNewExtension<Interception>().Configure<Interception>(); |
We have two basic options:
Interception behaviors are injected at registration time using the RegisterType method, like in the following example in which we add a MyInterceptionBehavior to the FileLogger:
unity.RegisterType<ILogger, FileLogger>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<MyInterceptionBehavior>()); |
Note: You can add several interception behaviors; all will be applied in sequence.
Notice how we define the interceptor to use (InterfaceInterceptor); it is also possible to configure it as the default for a type:
unity.Configure<Interception>().Configure<Interception>() .SetDefaultInterceptorFor<ILogger>(new InterfaceInterceptor()); |
And this is it. Every time you ask for a FileLogger instance, you will get a proxy that includes the MyInterceptionBehavior.
Call handlers are a bit trickier to apply because we need to define to which member or members they will apply. For that, we add call handler types (AddCallHandler or AddCallHandler<T>) or instances (AddCallHandler) to a policy (AddPolicy) and a set of rules (AddMatchingRule):
unity.Configure<Interception>().Configure<Interception>() .AddPolicy("Add MeasureCallHandler to FileLogger.Log") .AddMatchingRule(new TypeMatchingRule(typeof(FileLogger))) .AddMatchingRule(new MemberNameMatchingRule("Log")) .AddCallHandler<MeasureCallHandler>(); |
Tip: You should add a call handler instance instead of its type if the call handler requires special configuration (like setting its execution order or if it doesn’t have a public, parameterless constructor).
This example has two rules:
Tip: The call handler is only applied if all rules match.
Tip: You can add any number of call handlers; they will be processed and sorted by their Order property.
A rule must implement IMatchingRule, which exposes a very simple interface:
public interface IMatchingRule { bool Matches(MethodBase member); } |
There are several rules included out of the box:
You can easily implement your own rules; see an example in Policy Rules.
Note: All rules that take names accept regular expressions.
When we register a type for interception, we can add additional interfaces that Unity will add to the generated proxy. The injection member classes used for this purpose are AdditionalInterface and AdditionalInterface<T>. Here is one example of its usage:
unity.RegisterType<ILogger, FileLogger>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<DisposableBehavior>(), new AdditionalInterface<IDisposable>() ); |
This tells Unity to add interface IDisposable to all proxies to FileLogger and to apply a DisposableBehavior. The result of calling Resolve will then implement the IDisposable interface and the Dispose method is available for invocation. Of course, because this method was not implemented by the FileLogger class, it is up to the DisposableBehavior to make sure that, if the method is called, something happens.
If you add some interface to a class, you have to implement all of the interface’s methods and properties. A common example is adding support for INotifyPropertyChanged, which is a very useful interface that is somewhat cumbersome to implement when there are many properties. Let’s see how we can do it automatically with an interception behavior.
First, the registration; this is where we add the INotifyPropertyChanged, set the interceptor (VirtualMethodInterceptor in this case), and set the interceptor class:
unity.RegisterType<MyComponent, MyComponent>( new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<NotifyPropertyChangedInterceptionBehavior>(), new AdditionalInterface<INotifyPropertyChanged>() ); |
The NotifyPropertyChangedInterceptionBehavior class:
public class NotifyPropertyChangedInterceptionBehavior : IInterceptionBehavior { private event PropertyChangedEventHandler handlers = delegate { }; public IEnumerable<Type> GetRequiredInterfaces() { yield return (typeof(INotifyPropertyChanged)); } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { var result = null as IMethodReturn; if (input.MethodBase.IsSpecialName == true) { if (input.MethodBase.Name.StartsWith("set_") == true) { result = getNext()(input, getNext); this.handlers(input.Target, new PropertyChangedEventArgs (input.MethodBase.Name.Substring(4))); } else if (input.MethodBase.Name == "add_PropertyChanged") { this.handlers += (input.Arguments[0] as PropertyChangedEventHandler); result = input.CreateMethodReturn(null, input.Arguments); } else if (input.MethodBase.Name == "remove_PropertyChanged") { this.handlers -= (input.Arguments[0] as PropertyChangedEventHandler); result = input.CreateMethodReturn(null, input.Arguments); } } return (result); } public Boolean WillExecute { get { return(true); } } } |
And a sample usage:
var component = unity.Resolve<Component>(); var npc = component as INotifyPropertyChanged; npc.PropertyChanged += delegate(Object source, PropertyChangedEventArgs args) { //raised }; component.Property = "Some Value"; //raise PropertyChanged event |
When using XML configuration, we usually register the Unity extension (Interception) for applying the interception functionality and a section extension (InterceptionConfigurationExtension) that allows the configuration of it in XML:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension .Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /> <container> <extension type="Microsoft.Practices.Unity.InterceptionExtension .Interception, Microsoft.Practices.Unity.Interception" /> </container> </unity> |
Behaviors are configured inside the register declaration, in an interceptionBehavior element:
<register type="Succinctly.ILogger, Succinctly" mapTo="Succinctly. ConsoleLogger, Succinctly"> <interceptor type="InterfaceInterceptor"/> <interceptionBehavior type="Succinctly.MyBehavior, Succinctly"/> </register> |
The interceptionBehavior allows three attributes:
Call handlers are, as you know, slightly more complicated because of the matching rules:
<container> <register type="Succinctly.ILogger, Succinctly" mapTo="Succinctly.FileLogger, Succinctly"> <interceptor type="InterfaceInterceptor"/> </register> <interception> <policy name="Add MeasureCallHandler to FileLogger.Log"> <matchingRule name="type" type="TypeMatchingRule"> <constructor> <param name="typeName" value="Succinctly.FileLogger" /> </constructor> </matchingRule> <matchingRule name="type" type="MemberNameMatchingRule"> <constructor> <param name="nameToMatch" value="Log" /> </constructor> </matchingRule> <callHandler name="MeasureCallHandler" type="Succinctly .MeasureCallHandler, Succinctly" /> </policy> </interception> </container> |
I believe that the new sections interceptors, default, policy, matchingRule, and callHandler are self-explanatory so there’s really nothing to add here. Do notice the interceptor declaration inside register; this is required so that Unity knows what interceptor to use.
This is all it takes to add a new element, addInterface, to the register declaration:
<register type="Succinctly.ILogger, Succinctly" mapTo="Succinctly. ConsoleLogger, Succinctly"> <interceptor type="InterfaceInterceptor"/> <addInterface type="System.IDisposable, mscorlib"/> </register> |
An alternative approach to resolving an intercepted component from Unity is to generate a runtime proxy through an interface to an existing instance. In the process, we can add a number of interception behaviors and even interfaces. We do that by calling one of the ThroughProxy overloads:
var logger = new FileLogger("output.log"); var loggerProxy = Intercept.ThroughProxy<ILogger>(logger, new InterfaceInterceptor(), new AddInterface<IDisposable>(), new IInterceptionBehavior[] { new MyInterceptionBehavior() }); var disposableLogger = loggerProxy as IDisposable; |
Do note that this only works through interfaces and that the existing instance is left untouched.
The Enterprise Library—of which Unity is a part—includes a number of call handlers that you can use in your code:
Call Handler | Purpose |
Logging Method Invocation and Property Access LogCallHandler Microsoft.Practices.EnterpriseLibrary.Logging.dll | |
Handling Exceptions in a Structured Manner ExceptionCallHandler Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll | |
Validating Parameter Values ValidationCallHandler Microsoft.Practices.EnterpriseLibrary.Validation.dll | |
Authorizing Method and Property Requests AuthorizationCallHandler Microsoft.Practices.EnterpriseLibrary.Security.dll | |
Measuring Target Method Performance PerformanceCounterCallHandler Microsoft.Practices.EnterpriseLibrary.PolicyInjection.dll | |
Note: Some of these call handlers require a specific installation procedure. Don’t forget to read their documentation.