Interception in .NET

Vishvvas
Posted by Co Author(s): Shweta Haridas in Best Practices category on for Advance level | Points: 250 | Views : 10883 red flag
Rating: 5 out of 5  
 1 vote(s)

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<ICalculatorCalculator>();

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<ICalculatorCalculator>(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<IAdditionClassWithTransparentProxy>(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 { getset; }

}


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 ClassWithVirtualMethodInterceptionICalculator {

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_programming
http://msdn.microsoft.com/en-us/magazine/cc164165.aspx
Page copy protected against web site content infringement by Copyscape

About the Author

Vishvvas
Full Name: Vishwas Sutar
Member Level: HonoraryPlatinum
Member Status: Member,MVP
Member Since: 5/30/2011 2:13:10 AM
Country: India

http://www.dotnetfunda.com
Extensive and rich experience across gamut of technologies and programming languages like PB,VB,C++,VB.NET, C#, Classic ASP,ASP.NET, ASP.NET MVC.


About the Co-Author(s)


Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)