Enterprise Library 6, Unity 3 InterfaceInterceptor with MVC 4, Part 4

This post continues on from the previous post. Part 3 Enterprise Library 6, Unity 3 and MVC 4, Registration by Convention Part 3

Microsoft.Practices.Unity.Interception
Unity provides both instance and type interception, and enables interception with either objects you resolve through the container, or by using the stand-alone API to explicitly invoke interception on a known instance.

In this post we want to add a decorator class using unity interception which can be used to log the diagnosis messages. No diagnosis logs are required in the business class.

Unity Inception has 3 different types of interception:

  1. Transparent Proxy Interceptor
  2. Interface Interceptor
  3. Virtual Method Interceptor

We use the Interface Interceptor in this example.
Description (Taken from unity doc) An instance interceptor. It can proxy only one interface on the object. It uses dynamic code generation to create the proxy class. The InterfaceInterceptor can only be used to intercept a single interface.

Lets begin:
Get Microsoft.Practices.Unity.Interception packages from nuget:
NugetInterception

Create a EventSource for the diagnosis:

using System.Diagnostics.Tracing;

namespace MvcUnityBootstrapperTest.Logging
{
    [EventSource(Name = "DiagnosisEvents")]
    public class DiagnosisEvents : EventSource
    {
        public static readonly DiagnosisEvents Log = new DiagnosisEvents();

        private const int methodEnterEventId = 1;
        private const int methodLeaveEventId = 2;
        private const int logVerboseMessageEventId = 3;
        private const int logInfoMessageEventId = 4;
        
        [Event(methodEnterEventId, Message = "Method Enter: {0}", Level = EventLevel.Verbose)]
        public void MethodEnter(string message)
        {
            if (IsEnabled()) WriteEvent(methodEnterEventId, message);
        }

        [Event(methodLeaveEventId, Message = "Method Leave: {0}", Level = EventLevel.Verbose)]
        public void MethodLeave(string message)
        {
            if (IsEnabled()) WriteEvent(methodLeaveEventId, message);
        }

        [Event(logVerboseMessageEventId, Message = "{0}", Level = EventLevel.Verbose)]
        public void LogVerboseMessage(string message)
        {
            if (IsEnabled()) WriteEvent(logVerboseMessageEventId, message);
        }

        [Event(logInfoMessageEventId, Message = "{0}", Level = EventLevel.Informational)]
        public void LogInfoMessage(string message)
        {
            if (IsEnabled()) WriteEvent(logInfoMessageEventId, message);
        }
    }
}

Now this event source can be used in the DiagnosisBehaviour : IInterceptionBehavior class

using System;
using System.Collections.Generic;
using Microsoft.Practices.Unity.InterceptionExtension;
using MvcUnityBootstrapperTest.Logging;

namespace MvcUnityBootstrapperTest.UnityExtensions
{
    public class DiagnosisBehaviour : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            DiagnosisEvents.Log.MethodEnter(String.Format("[{0}:{1}]", this.GetType().Name, "Invoke"));
            DiagnosisEvents.Log.LogVerboseMessage(String.Format("{0} {1}", input.MethodBase.ToString(), input.Target.ToString()));

            var methodReturn = getNext().Invoke(input, getNext);

            if (methodReturn.Exception == null)
            {
                 DiagnosisEvents.Log.MethodLeave(String.Format("Successfully finished {0} {1}", input.MethodBase.ToString(), input.Target.ToString()));
            }
            else
            {
                DiagnosisEvents.Log.MethodLeave(String.Format("Finished {0} with exception {1}: {2}", input.MethodBase.ToString(), methodReturn.Exception.GetType().Name, methodReturn.Exception.Message));
            }

            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}

And now the InterfaceInterceptor can be added to the UnityConfig

using System;
using Microsoft.Practices.Unity;
using MvcUnityBootstrapperTest.UnityExtensions;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace MvcUnityBootstrapperTest.App_Start
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        public static void RegisterTypes(IUnityContainer container)
        {
            container.AddNewExtension<Interception>();
            container.RegisterTypes(UnityHelpers.GetTypesWithCustomAttribute<UnityIoCPerRequestLifetimeAttribute>(AppDomain.CurrentDomain.GetAssemblies()),
                                    WithMappings.FromMatchingInterface,
                                    WithName.Default,
                                    PerRequest,
                                    getInjectionMembers: t => new InjectionMember[]
                                    {
                                        new Interceptor<InterfaceInterceptor>(),
                                        new InterceptionBehavior<MvcUnityBootstrapperTest.UnityExtensions.DiagnosisBehaviour>()
                                    })
                     .RegisterTypes(UnityHelpers.GetTypesWithCustomAttribute<UnityIoCTransientLifetimeAttribute>(AppDomain.CurrentDomain.GetAssemblies()),
                                    WithMappings.FromMatchingInterface,
                                    WithName.Default,
                                    WithLifetime.Transient
                                );
        }

        public static Func<System.Type, Microsoft.Practices.Unity.LifetimeManager> PerRequest = (x) => new PerRequestLifetimeManager();
    }
}

Required are the code snippets as shown below.

container.AddNewExtension<Interception>();

getInjectionMembers: t => new InjectionMember[]
                                    {
                                        new Interceptor<InterfaceInterceptor>(),
                                        new InterceptionBehavior<MvcUnityBootstrapperTest.UnityExtensions.DiagnosisBehaviour>()
                                    })

Now all classes with the UnityIoCPerRequestLifetimeAttribute attribute will be intercepted using the InterfaceInterceptor

You can see from the log results that the business classes have been intercepted:
LogsInterception

code: https://github.com/damienbod/MvcUnityInterfaceInterception.git

Part 1 Enterprise Library 6, Unity 3 with ASP.NET MVC 4
Part 2 Enterprise Library 6, Unity 3 and MVC 4, LifetimeManagers
Part 3 Enterprise Library 6, Unity 3 and MVC 4, Registration by Convention
Part 5 Enterprise Library 6, Unity 3, MVC, Validation with Interception ValidationCallHandler5

Links:
http://unity.codeplex.com/discussions/448041

http://unity.codeplex.com/

http://msdn.microsoft.com/en-us/library/ff660861%28v=pandp.20%29.aspx

http://msdn.microsoft.com/en-us/library/microsoft.practices.unity.interceptionextension.interfaceinterceptor%28v=pandp.20%29.aspx

http://msdn.microsoft.com/en-us/magazine/gg535676.aspx

5 comments

  1. Stuart Hood · · Reply

    Thanks for your efforts. Part 2 of this series was a great help to me, but with Part 4 I get a reflection exception from the GetTypesWithCustomAttributes method with a LoaderException message of “Could not load file or assembly ‘Microsoft.Practices.ServiceLocation'”. Any suggestions? VS2012 on Win7x64.

  2. Stuart Hood · · Reply

    Found it! In case someone else needs it…
    PM> Install-Package CommonServiceLocator

  3. Great thanks for the info

    greetings Damien

  4. Great series of Interception posts, very helpful. Can I get the code as downloadable project ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: