This article discusses about what interception (with little insights in AOP) is and how it can be implemented with Unity framework in .NET framework based software system.
Introduction
In the software
development paradigm, a phrase called “Crosscutting Concerns” is always
discussed among the architects and designers. For start-up programmers and
developers, this is the area they are not much aware of but they would want to
know about it. This term necessarily spells about the needs or functions which
are needed across the components of the software system and especially in the
enterprise software’s, this attains more importance.
In most of data
centric or other systems, hardly there are scenarios when one doesn’t need to
think of logging, validations, exception handling, caching, auditing and
performance monitoring, encryption, compression etc. Different programmers do
it different ways and may do it in place but from the perspective of best
practices and patterns, it is always pays off to have such modules pluggable or
injectable. In such cases the existing programs needs not be modified
(open/closed principles) and also those programs need not carry the
responsibility (single responsibility principle) for these functions.
This would also help
to achieve the maintainable code (understandable, changeable, extendible), code
reuse (avoid duplication of code), the business functionalities better be
segregated from the functions like logging.
Interception is one
of the techniques where such crosscutting concerns can be addressed in very
clean, efficient manner. This is one of the approaches (or design pattern) to
implement wire up which is necessary for AOP aspect oriented programming AOP is
related to handling of crosscutting concerns in any application. For
programmer, AOP can be said to a mechanism for wiring up the crosscutting
classes to business classes. It requires a dynamic mechanism to wire up.
When there is a need
to add new behaviors to the existing methods/functionality without changing the
existing source code, aspect oriented programming comes in picture. An aspect
describes reusable piece of code that can be injected in existing classes
without touching/modifying the source code of those classes.
For further details,
please visit http://en.wikipedia.org/wiki/Aspect-oriented_programming
This
article discusses the analysis of Interception, need for interception, types of
interception and scenarios of using interception.
Objective
To learn
about interception, need for interception and types of interceptors and how it
can be utilized to address the cross cutting concerns.
Description
Need for
interception: The classes that implement business behaviors should not be
responsible for cross cutting concerns such as logging or validation and
existing source code should not be modified when a support for new cross
cutting concern is added in your application. With AOP in action, one can have
classes in the application that handle core business logic and other classes
that handle cross cutting concerns.
A pattern
can be recognized when considering cross cutting concerns. Many of them happen
only at either the start or the end of a method.
·
Logging is done when a method is called.
·
Inputs are checked for validity before
processing.
·
Exceptions are handled after the method fails.
This
leads to a different approach to implementing cross-cutting concerns. You can
put some special handling before or after method calls to handle the
cross-cutting concerns, get the code out of the methods, and enhance its
maintainability which makes application loosely coupled. The Unity Interception
extension is a way by which this can be done.
Types of
interceptors:
There are
two types
- Instance Interceptor
- Type Interceptor
Instance interception with interface interceptor:
Instance
interceptors use a separate proxy object between your code and your target
object. Using interception, you make a call on the proxy object instead of
directly calling the target object.Interface
interceptors can be used to intercept calls on single interface. It is used to
intercept both virtual and non virtual methods.
Instance interception with Transparent Proxy interceptor:
The object must either implement an interface or inherit
from “System.MarshalByRefObject”. If the marshal by reference object is
not a base class, you can only proxy interface methods. The Transparent Proxy
process is much slower than a regular method call.
Type Interception with
Virtual method interceptor:
Type interceptors create a new type that inherits from the
target type. Type interception can intercept both public and protected virtual
methods. Interception only happens on virtual methods. You must set up
interception at object creation time and cannot intercept an existing object.
The implementation of different interceptions is demonstrated
with Unity framework.
Using the code
·
Step I: Install package “Microsoft.Practices.Unity”
using Package Manager Console.
·
Step II: Unity container by
default does not support interception so to add support for interception you
must add the Unity interception extension.
·
Step
III: Add the information about type to intercept and behaviors to add.
For the demonstration simplicity, a console application
is chosen for example.
1.
Main method:
This includes the hooking up of Unity
Container code. A support for interception needs to be added to Unity
Container.
This is followed by registration of classes
for interception. The methods called from the Main() are also demonstrated here.
// public static void Main(string[] args) {
IUnityContainer container = new UnityContainer();
container.RegisterType<ICalculator, Calculator>();
var calculator = ResolveContainer(container);
Console.WriteLine("/****** " + "No interception as Unity by default does not support interception" + "******/");
Console.WriteLine("/****** " + " Unity's extensions for Interception is not added to container " + "******/");
CallAddMethod(container, calculator);
container = new UnityContainer();
container.AddNewExtension<Interception>(); // To add support for interception.
Console.WriteLine("/****** " + "Interception begins" + "******/");
Console.WriteLine("/****** " + " Unity's extensions for Interception is added to container " + "******/");
container.RegisterType<ICalculator, Calculator>(new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<InterfaceInterceptor>()); //Register a type mapping with the container
Console.WriteLine("/****** " + "Interface interception" + "******/");
Console.WriteLine("/****** " + " Unity's extensions for Interception is registered for interface interceptor with InterfaceInterceptor" + "******/");
var proxy = ResolveContainer(container);
CallAddMethod(container, proxy);
Console.WriteLine("/****** " + "Virtual Method interception" + "******/");
Console.WriteLine("/****** " + " Unity's extensions for Interception is registered for virtual method with VirtualMethodInterceptor" + "******/");
container.RegisterType<ICalculator,ClassWithVirtualMethodInterception>(new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<VirtualMethodInterceptor>()); //Register a type mapping with the container
var virtualMethodProxy = ResolveContainer(container);
CallAddMethod(container, virtualMethodProxy);
Console.WriteLine("/****** " + "Transparent Proxy Interception" + "******/");
Console.WriteLine("/****** " + " Unity's extensions for Interception is registered for proxy with TransparentProxyInterceptor" + "******/");
container.RegisterType<IAddition, ClassWithTransparentProxy>(new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<TransparentProxyInterceptor>()); //Register a type mapping with the container
var transparentProxy = ResolveContainerWithTransparentProxy(container);
CallAddMethodWithTransparentProxyInterception(container, transparentProxy);
Console.ReadKey();
}
private static ICalculator ResolveContainer(IUnityContainer container) {
var calculator = container.Resolve<ICalculator>();
return calculator;
}
private static IAddition ResolveContainerWithTransparentProxy(IUnityContainer container) {
var addition = container.Resolve<IAddition>();
return addition;
}
private static void CallAddMethod(IUnityContainer container, ICalculator calculator) {
Console.WriteLine("/****** " + " Add method is called " + "******/");
Console.WriteLine("/****** " + " Multiply method is called in Add " + "******/");
Console.WriteLine("Outer type: " + calculator.GetType().ToString());
calculator.Add(1, 2);
Console.WriteLine();
}
private static void CallAddMethodWithTransparentProxyInterception(IUnityContainer container, IAddition proxy) {
Console.WriteLine("/****** " + " Add method is called with TransparentProxy Interception " + "******/");
Console.WriteLine("/****** " + " Multiply method is called in Add " + "******/");
Console.WriteLine("Outer type: " + proxy.GetType().ToString());
proxy.Add(3, 4);
((IMultiplication)proxy).Multiply(3, 4);
}
1.
Logger attribute and call handler:
internal class InterceptionLoggerAttribute : HandlerAttribute {
public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container ) {
return new InterceptionLoggerCallHandler (); }
}
internal class InterceptionLoggerCallHandler : IcallHandler {
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) {
IMethodReturn result = getNext()(input, getNext);
if (result.Exception != null)
{
Console.WriteLine("Exception occured: " + result.Exception.Message); // logic for logging the exceptions and method arguments is written
Console.WriteLine("Parameters:");
foreach (var parameter in input.Arguments)
{
Console.WriteLine(parameter.ToString());
}
Console.WriteLine();
Console.WriteLine("StackTrace:");
Console.WriteLine(Environment.StackTrace);
}
return result;
}
public int Order { get; set; }
}
Scenario 1: When there is a need to intercept
calls on only one interface, interface interception should be used. It can intercept both virtual and non- virtual
methods.
public interface Icalculator {
[InterceptionLogger]
void Add(int number1, int number2);
[InterceptionLogger]
void Multiply(int number1, int number2);
}
class Calculator:Icalculator {
public virtual void Add(int number1, int number2) {
int result = number1 + number2;
Console.WriteLine("In Add method");
Console.WriteLine("Result of addition:" + result);
Multiply(2, 4);
}
public virtual void Multiply(int number1, int number2) {
int result = number1 * number2;
Console.WriteLine("In multiply method");
Console.WriteLine("Result of multiplication:" + result);
}
}
}
Output of interface interception: The output
shows that with interface interception only Add() method got intercepted. Multiply()
method did not get intercepted as it is called internally

Fig#1
Scenario 2: When the
type to intercept is a “MarshalByRefObject” or when only methods from the
type's implemented interfaces need to be intercepted. It can intercept both
virtual and non-virtual methods. When the methods from more than one interface
needs to be intercepted then use transparent proxy interceptor.
public interface Iaddition {
[InterceptionLogger]
void Add(int number1, int number2);
}
public interface Imultiplication {
[InterceptionLogger]
void Multiply(int number1, int number2);
}
Here
the class implements methods from more than one interface.
class ClassWithTransparentProxy : IAddition,IMultiplication {
public void Add(int number1, int number2) {
int result = number1 + number2;
Console.WriteLine("In Add method");
Console.WriteLine("Result of addition:" + result); }
public void Multiply(int number1, int number2) {
int result = number1 * number2;
Console.WriteLine("In multiply method");
Console.WriteLine("Result of multiplication:" + result);
}
}
Output of transparent proxy interceptor:

Fig#2
Scenario 3: When virtual methods needs to be
intercepted and when you need to intercept
internal calls in that class that means when one method in a class invokes
another method in the same class then you need to use this interceptor as the
internal method will also be intercepted.
public interface ICalculator {
[InterceptionLogger]
void Add(int number1, int number2);
[InterceptionLogger]
void Multiply(int number1, int number2);
}
public class ClassWithVirtualMethodInterception: ICalculator {
public virtual void Add(int number1, int number2) {
int result = number1 + number2;
Console.WriteLine("In Add method");
Console.WriteLine("Result of addition:"+result);
Multiply(2,4); // Internal method also gets intercepted with virtual method interception.
}
public virtual void Multiply(int number1, int number2) {
int result = number1 * number2;
Console.WriteLine("In multiply method");
Console.WriteLine("Result of multiplication:"+result);
}
}
Output of virtual
method interception: The output below shows that internal methods also gets
intercepted with virtual method interception. The multiply method below is
internal method.

Fig#3
Summary and Conclusion
Type
|
Description
|
Use
|
Transparent
Proxy
Interceptor
|
An
instance interceptor. The proxy is created by using the
.NETTransparentProxy/RealProxy infrastructure.
|
1.When
the type to intercept is a MarshalByRefObject or when only methods from the
type's implemented interfaces need to be intercepted.
2.When
the methods from more than one interface needs to be intercepted then use
transparent proxy interceptor.
|
Interface
Interceptor
|
An
instance interceptor. It can proxy only one interface on the object. It uses
dynamic code generation to create the proxy class.
|
1.
When only methods in one interface needs to be intercepted.
|
Virtual
Method
Interceptor
|
When
resolving an interface mapped to a type.
|
1.When
only virtual methods need to be intercepted and when you need to intercept
internal calls in that class that means when one method in a class invokes
another method in the same class then you need to use this interceptor.
|
Reference
http://en.wikipedia.org/wiki/Aspect-oriented_programminghttp://msdn.microsoft.com/en-us/magazine/cc164165.aspx