msdnmagazine.com February 2014 73
crosscutting concerns. The Unity container instantiates objects
of the derived type at run time. Instance interception can only
intercept public instance methods. Type interception can intercept
both public and protected virtual methods. Keep in mind that,
due to platform constraints, Unity interception does not support
Windows Phone and Windows Store app development, though
the core Unity container does.
For a primer on Unity, see “Dependency Injection with Unity”
(Microsoft patterns & practices, 2013) at amzn.to/16rfy0B. For more
information about interception in the Unity container, see the
MSDN Library article, “Interception using Unity,” at bit.ly/1cWCnwM.
Intercepting Task-Based Asynchronous Pattern
(TAP) Asynchronous Methods
Th e interception mechanism is simple enough, but what happens
if the intercepted method represents an asynchronous operation
that returns a Task object? In a way, nothing really changes: A
method is invoked and returns a value (the Task object) or throws
an exception, so it can be intercepted just like any other method.
But you’re probably interested in dealing with the actual outcome
of the asynchronous operation rather than the Task representing
it. For example, you might want to log the Task’s return value, or
handle any exception the Task might produce.
Fortunately, having an actual object representing the out-
come of the operation makes interception of this asynchro-
nous pattern relatively simple. Other asynchronous patterns
are quite a bit more diffi cult to intercept: In the Asynchronous
Programming Model (bit.ly/ICl8aH) two methods represent
a single asynchronous operation, while in the Event-based
Asynchronous Pattern (bit.ly/19VdUWu) asynchronous opera-
tions are represented by a method to initiate the operation
and an associated event to signal its completion.
In order to accomplish the interception of the
asynchronous TAP operation, you can replace the Task
returned by the method with a new Task that performs
the necessary post-processing after the original Task
completes. Callers of the intercepted method will receive the new
Task matching the method’s signature, and will observe the result
of the intercepted method’s implementation, plus whatever extra
processing the interception behavior performs.
We’ll develop a sample implementation of the basic approach to
intercept TAP asynchronous operations in which we want to log the
completion of asynchronous operations. You can adapt this sample to
create your own behaviors that can intercept asynchronous operations.
Simple Case
Let’s start with a simple case: intercepting asynchronous methods
that return a non-generic Task. We need to be able to detect that
the intercepted method returns a Task and replace that Task with
a new one that performs the appropriate logging.
Return
Value
Return
Value
Invoke
Object
Client
Proxy Object or
Derived Class
Target Object or
Original Class
Method
Behavior Behavior Behavior
Behaviors Pipeline
Invoke
GetNextHandlerDelegate
Message
Figure 1 Unity Interception Mechanism
public class LoggingAsynchronousOperationInterceptionBehavior : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input,
GetNextInterceptionBehaviorDelegate getNext)
{
// Execute the rest of the pipeline and get the return value
IMethodReturn value = getNext()(input, getNext);
return value;
}
#region additional interception behavior methods
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute
{
get { return true; }
}
#endregion
}
Figure 2 Simple Interception
public IMethodReturn Invoke(IMethodInvocation input,
GetNextInterceptionBehaviorDelegate getNext)
{
// Execute the rest of the pipeline and get the return value
IMethodReturn value = getNext()(input, getNext);
// Deal with tasks, if needed
var method = input.MethodBase as MethodInfo;
if (value.ReturnValue != null
&& method != null
&& typeof(Task) == method.ReturnType)
{
// If this method returns a Task, override the original return value
var task = (Task)value.ReturnValue;
return input.CreateMethodReturn(this.CreateWrapperTask(task, input),
value.Outputs);
}
return value;
}
Figure 3 Returning a Task
Fortunately, having an actual
object representing the
outcome of the operation makes
interception of this asynchronous
pattern relatively simple.