One of the most relevant issue in software architecture is how to separate the implementation of cross-cutting concerns from the implementation of the core-concerns.
A cross-cutting concern is a concern that affects multiple components in a system, such as logging, security, and exception handling.
Microsoft's Unity Application Block (Unity for short), that is part of the Microsoft Enterprise Library 5.0, enable you to effectively capture calls to objects and add additional functionality to the target object.
The interception mechanism captures the call to an object at invocation time and provides the full implementation of the object. Unity uses the Interceptor class to specify the interception mechanism to be used, how interception happens, and the InterceptionBehavior class to describe what to do when an object is intercepted. Unity interception is designed to have its behaviors performed on the entire object and all of its methods. Interceptors play a role only at proxy (or derived type) creation time. Once the proxy, or derived type, is created, the interceptor has provided any required components for the intercepted object and incorporated them into the proxy's processing. The proxy can then complete its processing with no further input from the interceptor.
Unity interception uses a single behaviors pipeline encompassing all of the behaviors for processing interception. The pipeline consists of an essentially fixed series of elements, the behaviors that you have set up, that perform pre- and/or post-processing logic on the object. If so dictated by the behavior element logic, each behavior element in the pipeline can end the invocations, and subsequent pipeline elements will not execute. The last executed element in the pipeline exits the pipeline and invokes the implementation of the intercepted object, thus enabling run-time processing. In post processing the process is reversed.

 

For more information see the MSDN article at: http://msdn.microsoft.com/en-us/library/ff660891%28v=PandP.20%29.aspx

Behaviors

Interception is based on a behavior or series of behaviors in the behaviors pipeline that describe what to do when an object is intercepted.
You can create your own custom behaviors by implementing the IInterceptionBehavior interface. The interception behaviors are added to a pipeline and are called for each invocation of that pipeline.
You must provide an implementation of the two IInterceptionBehavior interface methods, Invoke and GetRequiredInterfaces, and set the WillExecute property.
The WillExecute property indicate if the behavior perform any operation when invoked. The GetRequiredInterfaces method returns the interfaces required by the behavior for the intercepted objects. The Invoke method execute the behavior processing.
The Invoke method has two parameters: input and getNext. The input parameter rapresents the current call to the original method, the getNext parameter is a delegate to execute to get the next delegate in the behavior chain.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace Interceptor
{
    class MyBehavior : IInterceptionBehavior
    {

        /// <summary>
        /// Returns the interfaces required by the behavior for the objects it intercepts.
        /// </summary>
        /// <returns>
        /// The required interfaces.
        /// </returns>
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        /// <summary>
        /// Implement this method to execute your behavior processing.
        /// </summary>
        /// <param name="input">Inputs to the current call to the target.</param>
        /// <param name="getNext">Delegate to execute to get the next delegate
        /// in the behavior chain</param>
        /// <returns>
        /// Return value from the target.
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("Before method execution");
            IMethodReturn msg = getNext()(input, getNext);
            Console.WriteLine("After method execution");
            return msg;
        }

        /// <summary>
        /// Optimization hint for proxy generation - will this behavior actually
        /// perform any operations when invoked?
        /// </summary>
        public bool WillExecute
        {
            get { return true; }
        }

    }
}

 

Configuring the container

Once you have defined you custom behavior, you can use the Dipendency Injection Container of Unity to apply the Interception Behavior.
The container can be configured by using a configuration file or at run time by using the API.


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
      <section
         name="unity"
         type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
               Microsoft.Practices.Unity.Configuration"
/>
    </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
   
    <alias alias="ICalculator" type="Interceptor.ICalculator, Interceptor"/>
    <alias alias="Calculator" type="Interceptor.Calculator, Interceptor"/>
    <alias alias="MyBehavior" type="Interceptor.MyBehavior, Interceptor" />

    <sectionExtension
       type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension,  
             Microsoft.Practices.Unity.Interception.Configuration"
/>
    
    <container>
      <extension type="Interception"/>
      <register type="ICalculator" mapTo="Calculator">
        <interceptor type="InterfaceInterceptor" />
        <interceptionBehavior type="MyBehavior"/>
      </register>
    </container>   
  </unity>
</configuration>

The configuration file above configure the D.I. container as follows:

  • map the ICalculator interface with the Calculator class;
  • define an interceptor of the type "InterfaceInterceptor";
  • apply the "MyBehavior" interceptionBehavior.

The ICalculator interface is defined as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Interceptor
{
    public interface ICalculator
    {
        int Add(int value1, int value2);
    }
}

The Calculator class is defined as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Interceptor
{
    public class Calculator : ICalculator
    {

        public int Add(int value1, int value2)
        {
            int res = value1 + value2;
            Console.WriteLine("The result is: " + res.ToString());
            return res;
        }

    }
}"font-size: x-small;">

 

The Sample Program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace Interceptor
{
    class Program
    {
        static void Main(string[] args)
        {
            // Loads the container
            IUnityContainer container = new UnityContainer ();
            container = Microsoft.Practices.Unity.Configuration.UnityContainerExtensions.LoadConfiguration (container);
 
            // Resolve the proxy-sample
            ICalculator calc = Microsoft.Practices.Unity.UnityContainerExtensions.Resolve<ICalculator>(container);       

            int res = calc.Add(3, 5);

            Console.WriteLine("Press <ENTER> to quit.");
            Console.ReadLine();
        }
    }
}

 

Running the example above the result appears like this:

Before method execution
The result is: 8
After method execution
Press <ENTER> to quit.

You can see that the Add(3, 5) method execution is wrapped between the instruction Console.WriteLine("Before method execution") and Console.WriteLine("After method execution") defined in the Invoke method of the MyBehavior class.

To run the example you must install the Microsoft Enterprise Library 5.0 and add a reference to the following assemblies:

  • Microsoft.Practices.Unity.dll
  • Microsoft.Practices.Unity.Configuration.dll
  • Microsoft.Practices.Unity.Interception.dll
  • Microsoft.Practices.Unity.Interception.Configuration.dll