IoC Container, Unity and Breaking Changes Galore

Update: IoC and Unity - The Basics and Interception

As Grigori Melnik noted on my blog previously as well as his own, there was a brand new drop of the Unity Application Block as of March 4th.  This by far was a huge update with a lot of breaking changes.  That teaches me to use a CTP of any product and blog about it actively as it compares to other Inversion of Control (IoC) containers.  Glad I didn't do a lot on ASP.NET MVC just yet but I have a few good projects going on the side with that now.

Where I've Been Before

As noted here before, I've been spending some time actively comparing the Unity Application Block to other IoC containers and what each offers.  Let's get caught up to my previous posts:
I'm probably going to change the code on each one just so that you all don't get angry about code from me not working, so stay tuned, it will get done.  But, keep in mind, it is still CTP, and I'd rather concentrate on the concepts as well.

What's Changed

As you may notice if you did any of the code snippets I published, they sure as heck don't build anymore.  So, let's enumerate the changes made so far:
  • UnityContainer method Register<TFrom, TTo>() becomes RegisterType<TFrom, TTo>()
  • UnityContainer method Get<T>() becomes Resolve<T>
  • UnityContainer method SetSingleton<T> removed
  • UnityContainer method RegisterType<TFrom, TTo> accepts a LifetimeManager to create Singletons
  • Added ContainerControlledLifetimeManager and ExternallyControlledLifetimeManager
  • Removed DependencyAttribute NotPresentBehavior property and enum
  • Added UnityContainer CreateChildContainer method to create child sandboxes
  • Reversed the parameters for UnityContainer method RegisterInstance<T>(value, key) to RegisterInstance<T>(key, value)
As you can see, some of these changes can be seen as quite annoying especially if I were to have a method such as the following and I can't find the error until I sit and read the code through and through:

Old:

IUnityContainer container = new UnityContainer();

container

    .RegisterType<ILogger, ConsoleLogger>(new ContainerControlledLifetimeManager())

    .RegisterInstance<string>("administrator@example.com", "defaultFromAddress");


And sure enough, it blew up due to the fact that it seemed just fine because it was RegisterInstance<string>(string, string) and instead I had to change it to this to get it to work.

New:

IUnityContainer container = new UnityContainer();

container

    .RegisterType<ILogger, ConsoleLogger>(new ContainerControlledLifetimeManager())

    .RegisterInstance<string>("defaultFromAddress", "administrator@example.com");


Nothing from what I can tell changed in the XML configuration, but I prefer to register my types by code instead.  The only thing I really like to switch out from time to time is a Logger of some sort.

Another interesting aspect is the concept of child containers in their own sandbox as it were.  Take for example, we have two loggers, a DebugLogger and a ConsoleLogger.  We have the ability to have these registered in two different child containers all managed by the parent.  Let's walk through a simple example of this.

using Microsoft.Practices.Unity;

 

namespace UnitySamples

{

    class Program

    {

        static void Main(string[] args)

        {

            UnityContainer parentContainer = new UnityContainer();

            IUnityContainer childContainer1 = parentContainer.CreateChildContainer();

            childContainer1.RegisterType<ILogger, ConsoleLogger>(new ContainerControlledLifetimeManager());

            IUnityContainer childContainer2 = parentContainer.CreateChildContainer();

            childContainer2.RegisterType<ILogger, DebugLogger>(new ContainerControlledLifetimeManager());

 

            ILogger logger1 = childContainer1.Resolve<ILogger>();

            ILogger logger2 = childContainer2.Resolve<ILogger>();

            logger1.Log("Foo");

            logger2.Log("Bar");

        }

    }

}


What seemed a little annoying to me is that CreateChildContainer is not available from the IUnityContainer, and instead only from the UnityContainer concrete class instead.  But as you can see, I create two loggers each in their own sandbox, one a DebugLogger and one the ConsoleLogger.

What I'd Like To See

As I've said before, I'm not entirely sold on the Unity Application Block as I like a lot of the other ones in the Open Source Community as well including Castle Windsor, StructureMap and Spring.NET.  It's heartening that they are taking a lot of advice from the community to heart and having quick drops for public approval.  When people are evaluating IoC containers, it's critical that you have a list of essential features that the container must support.  You may also note that your needs for this may change from project to project, so don't assume that if it worked well here that it will suit your needs on all projects.  Due diligence must be done in tool and framework analysis to get the right tool for the right job.

With that in mind, I have a few things that I'm looking for right now in an IoC container.  Some of these requirements are as follows:
  • Must be lightweight (No heavy XML lifting required)
  • Must support interception and AOP with runtime weaving (compile time might be nice)
  • Should be opinionated so that I don't need to mark my dependencies in my constructor, instead match by name
  • When I ask for a logger, give me one and I don't care which
  • Support easy object registration through fluent interfaces
But like I said, it evolves quickly and changes from project to project.  What's your list and why?

Further Thoughts About IoC

Nick Malik recently blogged about IoC container and their overuse in a two part blog series here and here.  In his first post, he tends to think that people are religious about the use of IoC containers and not just the Dependency Injection pattern in particular.  In the second post, he covers that the use of the IoC container is only as good as the team that understands its impact and applicability.  Most tools have their limits and uses.  Mocking containers have the same issue.  Once you start mocking for parts of your tests, then there is a good chance for abuse and overuse as well.  I see his point, but I disagree that many teams are not up for IoC containers and general good design practices of Dependency Injection.

Wrapping It Up

Next time, I'd like to get into the extensibility model of each container in terms registering extensions and so on.  In the mean time, I hope you go and evaluate your needs for an IoC container, even whether you need one or not.  Until next time...

kick it on DotNetKicks.com

3 Comments

  • Sorry about the annoying breakage on RegisterInstance, but I really thought it was necessary. Every other call always had the parameter list be (type, key, other stuff)... except that one. To the point that *every* *single* *time* I tried to write a RegisterInstance call on the fly I got it backwards. And when registering a string, as you found out, the compiler doesn't help you find it.

    At least this way the parameter list is consistent throughout the API. And better a break now than to try and fix it after release.

  • @Chris,

    Thanks for the response. I realize that issue now after examining the source code for a little bit. Thanks for the clarification

  • @Rinat

    Yes, I am aware of autofac as well as LinFu and others. There are too many of them to look at right now as I was comparing just three of them. I have more in this series though to come.

    Matt

Comments have been disabled for this content.