IoC and Unity - The Basics and Interception

I realize it's been a while since my last post on Inversion of Control containers and looking at Unity as one of them.  Since that time, Scott Hanselman linked to some of the comparisons that I did for IoC containers here.  I'll be the first to admit that the look was a bit naive, but to get you all interested in looking at IoC container and how they can improve your applications.  It was suggested here that my posts weren't a complete comparison, although in my previous posts I covered a lot of those topics.  Even so, after talking with said individual, I need to cover more ground on the basics and dive deeper into the details.

Where We Are

Before we begin today, let's see what we've already covered in the past:
So, we have a bit of back history, but I think I dived too far into things without giving some of the back story.

DI Frameworks Galore

As Scott Hanselman noted, there are a number of IoC containers in the .NET Space.  Most of these I was already aware of and played with, so I'm only going to list the ones I've played with.  Here they are in no particular order:
So, as you can see, there are plenty to choose from.  They all serve basic IoC needs and I'll talk about that a little bit more later.

Getting Back to Basics

When we talk about Inversion of Control and dependency inversion principle, we're talking about loosely coupled applications.  It follows the Hollywood Principle which is the trite "Don't call use, we'll call you" mantra.  In a way it means that those dependencies that you have inside your class, say your Logger and its associated formatter.  In the tightly coupled world, you would have a private member of a Logger.  Instead, what you would have in the other case is an interface or abstract class that would represent the functionality of that logger, and that instance given to your class.  Throw on top of that a container to manage those dependencies to those interfaces and mappings to concrete classes.  Also, your container can manage the object lifetimes as well.   Ayende shows how easy it is to create a simple container, although it misses an important point about lifetime management.

To put it succinctly, to be a container should satisfy the following requirements:
  • Configuration - Registering types and mappings through code, XML or script
  • Lifetime Management - How the lifetime of the objects are managed, singleton, transient, etc
  • Resolution - Resolve dependencies and instantiate
  • Extensibility - Be able to add new facilities for additional features (interception, AOP, and so on)
Before we get into any advanced topics, let's get into more detail.  James Kovacs wrote in the March 2008 edition of MSDN Magazine called "Loosen Up - Tame Your Software Dependencies For More Flexible Apps".   This article is a great start for those trying to understand dependency inversion and dependency injection.  James walks through a simple application with tight coupling, and then works to loosen it.  Once that is complete, Castle Windsor is introduced and walks through the XML configuration or using Binsor to auto-wire the container.

One of the more key points in this article and it came from Ayende is to have an anti-corruption layer for your IoC container.  Yes, that's the same Domain Driven Design term in which we isolate things that don't conform to our given architecture and can translate from one context to another.  Let's throw up a simple example of using this.  Remember it's just a quick spike of an anti-corruption layer.

namespace UnitySamples

{

    public static class IoC

    {

        private static IDependencyResolver resolver;

 

        public static void Initialize(IDependencyResolver resolver)

        {

            IoC.resolver = resolver;

        }

 

        public static T Resolve<T>()

        {

            return resolver.Resolve<T>();

        }

 

        public static T Resolve<T>(string name)

        {

            return resolver.Resolve<T>(name);

        }

    }

}


So, what we have is an IDependencyResolver given to the singleton IoC container.  Like I said, this isn't best practice as I haven't done any checking on whether the resolver was initialized or not.  But, what we want is to expose the way of resolving dependencies.  Now let's take a look at the IDependencyResolver interface and how that's used.

namespace UnitySamples

{

    public interface IDependencyResolver

    {

        T Resolve<T>(string name);

 

        T Resolve<T>();

    }

}


Not much to this but gives us the ability to resolve our dependencies by type, or by type and name.  Pretty simple code here once again.  But, if I wanted to suddenly use Unity as the backing store, I'd simply implement it as the following:

using System.Configuration;

using Microsoft.Practices.Unity;

using Microsoft.Practices.Unity.Configuration;

 

namespace UnitySamples

{

    public class UnityDependencyResolver: IDependencyResolver

    {

        private IUnityContainer container;

 

        public UnityDependencyResolver()

        {

            container = new UnityContainer();

            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            section.Containers.Default.GetConfigCommand().Configure(container);

        }

 

        public T Resolve<T>()

        {

            return container.Resolve<T>();

        }

 

        public T Resolve<T>(string name)

        {

            return container.Resolve<T>(name);

        }

    }

}


So, all I'd have to do to switch from one container to another is just swap out the IDependencyResolver and I'm finished.  But, unfortunately, there are some techniques that are partial to one container or another, so there may be some things I'd lose there.  But for most cases, this pattern works and works well at that.

Of course loose coupling, dependency injection and using IoC containers are nice in terms of making unit tests easier, but as you can see, there's a bit more to it than that, including the lifetime management, interception, the flexibility of changing implementations and so on.

Interception and Aspect Oriented Programming

Aspect Oriented Programming (AOP) and basic interception are interesting pieces of some containers.  This technique allows us to handle cross-cutting concerns such as logging, transaction management, security and so on at a different level instead of littering our code and domain model with checks everywhere.  Instead, we centralize those concerns and have them intercept calls and do their work.  Let's get some jargon straight here before we go any further.  An aspect is the part that encapsulates the cross-cutting concern such as logging.  These aspects can give advice, which is to alter the behavior of a given program.  The advice is given at certain join points which is where the aspect advice and the program intersect.  A group of these join points are called a pointcut.

Interception is a feature of some of the IoC containers out there.  A few come to mind such as Castle Windsor, Spring.NET, LinFu, S2Container, Puzzle.NET and even ObjectBuilder2.  These containers provide at least a basic level of interception, meaning that you can intercept calls to methods, analyze the contents of the method call, proceed with the call and even modify the return value.  Since most containers support simple interception, I haven't found it more useful than logging or enforcing security on various things.  However, it can be extended to support more robust Policy Injection style of programming such as you would find in the Policy Injection Application Block.

Interception in Unity?

Quite a bit has changed with Unity since I last blogged about it in terms of the configuration.  You can grab the latest bits here.  It would be nice to have changesets and such checked into CodePlex for things like this instead of zip files or MSIs, but oh well.  Anyhow, most of the changes revolve around managing lifetimes and handling the parameters for constructor injection.  You can read the tests and figure it out.

As I've covered before, right now simple injection in Unity is not supported at the moment.  The intention is to have the Policy Injection Application Block fill that role.  There is also PostSharp4Unity which can also fit that bill for quick fixes, but I want deep down support for simple interception.  Conversations with Brad Wilson led me to ObjectBuilder2 and some spikes that they had with a customer DependencyContainer.  So parts of me wondered why that wasn't leveraged at all.  Let's take a look at what was implemented in the base of ObjectBuilder2.

Interception in ObjectBuilder2

ObjectBuilder2 was a project by Brad Wilson and Scott Densmore which took the original ObjectBuilder, which was really meant for CAB and not a real container, and made some changes and improvements.  Such improvements also came with a few samples of things you can do with it such as a DependencyContainer sample.  In here, there are a few interesting pieces.  Most of which lie in the interception pieces.  Let's take a look at each type below of the ones supported.

        public void InterceptInterface<T>(MethodInfo interfaceMethod,

                                          params IInterceptionHandler[] handlers)

 

        public void InterceptInterface(Type typeToIntercept,

                                       MethodInfo interfaceMethod,

                                       params IInterceptionHandler[] handlers)

 

        public void InterceptRemoting<T>(MethodInfo method,

                                        params IInterceptionHandler[] handlers)

 

        public void InterceptRemoting(Type typeToIntercept,

                                      MethodInfo method,

                                      params IInterceptionHandler[] handlers)

 

        public void InterceptVirtual<T>(MethodInfo method,

                                        params IInterceptionHandler[] handlers)

 

        public void InterceptVirtual(Type typeToIntercept,

                                    MethodInfo method,

                                    params IInterceptionHandler[] handlers)


Now with this, you can see there are three different ways of intercepting, through interfaces, virtual methods or through remoting.  We also have the ability to intercept through attributes or through code.  Let's walk through a test to see how intercepting through attributes might work. 

            [Fact]

            public void InterceptViaAttributes()

            {

                Recorder.Records.Clear();

                DependencyContainer container = new DependencyContainer();

                container.RegisterTypeMapping<ISpy, SpyInterfaceAttributes>();

 

                ISpy obj = container.Get<ISpy>();

                obj.InterceptedMethod();

 

                Assert.Equal(3, Recorder.Records.Count);

                Assert.Equal("Before Method", Recorder.Records[0]);

                Assert.Equal("In Method", Recorder.Records[1]);

                Assert.Equal("After Method", Recorder.Records[2]);

            }


Of course there wouldn't be tests in here without using xUnit.NET of course.  Hope to cover that soon enough.  Anyhow, as you can see, it's pretty simple to register types in here and then check the expectations through the recorder to see whether the actions happened.  To find out what the ISpy and SpyInterfaceAttribtues are actually doing, let's dig through the code. 

            public interface ISpy

            {

                void InterceptedMethod();

                void ThrowsException();

            }

 

            internal sealed class SpyInterfaceAttributes : ISpy

            {

                [InterfaceIntercept(typeof(RecordingHandler))]

                public void InterceptedMethod()

                {

                    Recorder.Records.Add("In Method");

                }

 

                public void ThrowsException()

                {

                    throw new Exception();

                }

            }


What this class allows us to do is to register an intercepting interface handler, in this case the RecordingHandler.  What we intend to have done is that we record a message once we're in the method.  Then our interceptor can put in calls before and after our method call just to prove a point.

namespace ObjectBuilder

{

    public class RecordingHandler : IInterceptionHandler

    {

        readonly string message;

 

        public RecordingHandler()

        {

            message = "";

        }

 

        public RecordingHandler(string message)

        {

            this.message = string.Format(" ({0})", message);

        }

 

        public IMethodReturn Invoke(IMethodInvocation call,

                                    GetNextHandlerDelegate getNext)

        {

            Recorder.Records.Add("Before Method" + message);

            IMethodReturn result = getNext().Invoke(call, getNext);

            Recorder.Records.Add("After Method" + message);

            return result;

        }

    }

}


This IInterceptionHandler interface handles the basic interception tasks of doing some before and after work on the given method.  Here it is doing nothing special but recording a message before and after intercepting the method call.  I encourage you to dig through this a bit more and understand where it is coming from, because it's good stuff and heck, you might learn some IL emitting as well.  It's a shame I didn't see some of this IP get rolled into Unity, but we can hope some of it does.

Interception in Castle Windsor

Like above with ObjectBuilder2, Castle Windsor has a lightweight interception capability as well.  I covered this in a previous post, but I'll elaborate on it further.  There isn't much on Windsor interception documentation, but you can read about that here.  To take advantage of method interception, simply implement the IInterceptor interface which is marked below.

public interface IInterceptor

{

    void Intercept(IInvocation invocation);

}


And then we can implement a simple logger interceptor which goes ahead and logs the before and after information as well as anything else you might want to log that comes from the method signature such as arguments, method name, targets, etc.  Here, I'm doing nothing special at all, but play around with the IInvocation interface to find out what you can do.

using Castle.Core.Interceptor;

 

namespace CastleSamples

{

    public class LoggingInterceptor : IInterceptor

    {

        private DebugLogger logger = new DebugLogger();

 

        public void Intercept(IInvocation invocation)

        {

            logger.Log("Before Method");

            invocation.Proceed();

            logger.Log("After Method");

        }

    }

}


Like I said above, I am doing nothing special here other than to show that I can log before and after calls, and I have the option of doing more whether I want to proceed with the method call or not.  I can easily register the interceptor either through code, through Binsor or through the XML muck.  An post of mine goes through that here.

To me, these lightweight interceptors are nice, but I don't get much value out of them just yet outside of logging and such.  Ayende has similar thoughts about the uses of AOP in Windsor here.  He also covers doing a Policy Injection Application Block style approach in Windsor as well here

One off the topics discussed at DC ALT.NET was about using Windsor Interception to implement the Unit of Work pattern to implement undo logic for a WPF application.  It was a pretty interesting approach to the issue and I'll definitely have to dig into that a little deeper as well.  I'm hoping Phil McMillan starts blogging more anyways...  But, obviously there are uses of interception and AOP in the enterprise and I'll get to that in the next post in the series.

Conclusion

As you can see, interception is an interesting topic that needs to be explored a bit more before I'd call this subject done.   After all, I haven't touch most other containers, and I definitely want to get into AOP and Spring.NET as it is a topic I'd like to dive a little deeper into as well as AOP in the Enterprise model.  Things that make the .NET rramework bend in all sorts of ways is always a worth cause.  Anyhow, I hope this dive again into the subject is useful and any feedback is appreciated.  Until next time...

kick it on DotNetKicks.com

6 Comments

  • @Chris,

    Thanks for your reply. I'm very familiar with that piece due to the fact that I've been working that same angle. Glad to see it's on the list of things since I like OB2's lightweight interception model. And yes, I did notice the performance issues that you talked about and much appreciated. Glad to see you're keeping touch with the community on these things.

    Matt

  • @EdJez

    First off welcome back to blogging! Look forward to seeing you in Seattle.

    Second off, I totally agree that it should use the existing OB Interception strategies and policies. Should any additional functionality be required, then you can fold in the Policy Injection Application Block afterwards, but the basis should be what's already in the OB2 Interception.

    As for Mono, that's an idea that I hadn't thought of, but sounds like an interesting idea. Anyone care to take the ball and run with that? Of course the tests using MSTest can't be ported, but oh well.

    Matt

  • Nice site you have!

  • Ioc and unity the basics and interception.. Reposted it :)

  • Hey, that's the garetset! So with ll this brain power AWHFY?

  • I don’t even know how I ended up here, but I thought this post was great. I do not know who you are but certainly you're going to a famous blogger if you aren't already ;) Cheers!

Comments have been disabled for this content.