AOP - Interception with Unity 2.0

 
9/26/2010
.NET, C#
10 Comments

Unity is a well known dependency injection container. Custom extensions can be created to extend its functionality. The download of Unity contains an extension for interception.
In this post I will show you, how interception can be used for separation of cross-cutting concerns.

Introduction

Interception is one possibility to support Aspect-oriented programming (AOP). It is useful to keep your business classes clean from other concerns like logging or caching.
There are several possibilities to use AOP in .NET. One option is to use a post-compiler like PostSharp. PostSharp modifies the IL code after compilation and injects aspects into the code.
In contrary to that, interception is performed at runtime, which implicates some limitations. Depending on the interceptor the following restrictions apply:

  • Transparent Proxy Interceptor: requires interface or needs to inherit from MarshalByRefObject
  • Interface Interceptor: requires interface
  • Virtual Method Interceptor: only on virtual methods

How does interception work?

When you request the target object from the Unity container, you won't get an instance of the class you have configured. In fact you will get a dynamically generated proxy object or a derived class.

Interception

If you call a method on the proxy object you have the possibility to execute code before and after the method call is delegated to the 'real' object instance. Your custom code has to be placed in a class/behavior that implements the ICallHandler interface. Within the behavior you have access to the arguments of the method call, you are able to swallow exceptions or return custom exceptions.

By the way: It is also possible to use Unity interception without an Unity container.

Example: Logging of exceptions and method arguments

In the following example we will create two custom behaviors, which both implement the ICallHandler interface:

  • LoggerCallHandler: Logs method arguments
  • ExceptionLoggerCallHandler: Logs method arguments and stacktrace when an exception occurs

The ExceptionLoggerCallHandler:

internal class ExceptionLoggerCallHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
      IMethodReturn result = getNext()(input, getNext);
      if (result.Exception != null)
      {
        Console.WriteLine("Exception occured: " + result.Exception.Message);
    Console.WriteLine("Parameters:");
    foreach (var parameter in input.Arguments)
    {
      Console.WriteLine(parameter.ToString());
    }

    Console.WriteLine("StackTrace:");
    Console.WriteLine(Environment.StackTrace);
  }

  return result;
}

public int Order { get; set; }

}

To apply a behavior to a method, you have to create a corresponding HandlerAttribute which creates an instance of the behavior:

internal class ExceptionLoggerAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
      return new ExceptionLoggerCallHandler();
    }
}

In this example we want to create a simple calculator. To use Interface Interception we have to create a interface were we can apply the behaviors:

public interface ICalculator
{
  [Logger]
  int Add(int first, int second);

  [ExceptionLogger]
  int Multiply(int first, int second);
}

The implementation of the calculator stays the same. Now we have to setup the Unity container:

IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<ICalculator, Calculator>()
  .Configure<Interception>()
  .SetInterceptorFor<ICalculator>(new InterfaceInterceptor());

// Resolve
ICalculator calc = container.Resolve<ICalculator>();

// Call method
calc.Add(1, 2);

When you call the Resolve method on the container you will not get an instance of the Calculator class, you will get an proxy class. Its name will be something like:
'DynamicModule.ns.Wrapped_ICalculator_50fa0b711518484a9ca19e731132c334'.
When you call one of the methods on the wrapper class, the CallHandlers get executed.

Conclusion

Unity does not provide a full AOP framework, since you have several limitation. Nevertheless interception can be really useful to fulfill basic AOP requirements.

Downloads

Feedly Feedly Tweet


Related posts


Comments


İLHAN

İLHAN

11/9/2014

thanks . simple and helpful article


Siva

Siva

3/3/2014

Should I call all methods like this ? if I create an object of the class which was implemented Icalculator interface and call the methods then it is not working. // Resolve ICalculator calc = container.Resolve<ICalculator>(); // Call method calc.Add(1, 2); --Sorry for the poor English.


Pankaj

Pankaj

5/19/2011

Thanks Daniel for your valuable feedback. It seems at the moment i will go ahead with implementing the AOP on DAL, as it seems to be pretty straight forward. The reason i wanted to go with AOP for logging as well coz i hate to add logging calls @start and end of each method. :( Thanks again.


Daniel

Daniel

5/17/2011

@Pankaj: Exception handling should be no problem. Since the DAL is a separate layer it can be easily instantiated and intercepted through unity. Logging through out the app is different. Since logging is usually used allover the application, you should not do this with AOP through Unity: 1) You have to resolve all instances of your objects through Unity. You should only resolve root objects from unity. 2) All your classes need interfaces/virtual methods to enable interception. 3) Performance will be not very good, if you use interception everywhere. I would only use AOP through unity for components, that are retrieved from the container anyway. If you want logging everywhere in your app, consider using Postsharp. Postsharp runs at compile time and doesn't force you to introduce interfaces where you actually don't need them.


Pankaj

Pankaj

5/17/2011

Thanks a ton for you response.. I had the same notion, thanks again to confirm the same. Just for my own knowledge. i am designing an app and planning to use Aop through unity for logging (through out the app) and exception handing ( at DAL).. is there any thing (from your exp) i should watch out for ?


Daniel

Daniel

5/16/2011

@Pankaj: Thanks for your feedback. When you call the outer method, it is called on the proxy and can get logged. The inner call indeed is executed directly on the target object, so no logging can take place. Take a look at the call stack: --this.Add() // this is the target object -calculator.Add(...) // This is the proxy SomeClass.DoSomething()


Pankaj

Pankaj

5/16/2011

Hi Palme, Thanks for this very usefull post, gets the message in a crisp and clear fashion. I however struggling with a scenario where say Add(int num1) calls to Add(int num,5) and both methods are decorated with [Logger] attribute. All i get is logging for call to outer Add(int num). I am planning to use AoP for logging and i belive this is a very common scenario. Any help is highly appreciated.


Adrien Constant

Adrien Constant

5/2/2011
http://twitter.com/AdrienConstant

Hi, and thanks for the nice article. AOP using Unity (eventually cooupled with EntLib) works great in those scenarii. However, the negative performance impact can be high, depending on the interception method used, and its frequency. There is the temptation to use AOP for every call (ie: logging the method parameters in a data access layer automatically). However, this should generally be disabled in a production ready environement.


Nigel Tyalor

Nigel Tyalor

4/20/2011

Kudos man. a) The demo works out of the box. b) It's very minimal and gets the point across. c) I haven't sen this explained adequately elsewhere. Thanks!


Kayvan shn

Kayvan shn

10/17/2010

Hi Palme, This is excellent post. I appreciate your work. Thanks for putting valuable information here.