IoC Container, Unity and Breaking Changes Galore
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:
- IoC and the Unity Application Block
- IoC and the Unity Application Block - Going Deeper
- IoC and the Unity Application Block Once Again
- IoC Containers, Unity and ObjectBuilder2 - The Saga Continues
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)
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
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...