I saw a few tweets and I was reminded of a conversation we had on a project a while ago. The discussion was around abstracting our IoC container.
First thing to consider is, how do you use your container? Ignoring configuring your container for the time being, the container shouldn’t really appear in your code at all. In theory, there should be one call to resolve. Ideally, this call to resolve happens in some infrastructure code so you never actually call it. If you look at the ASP.Net MVC contrib projects you can see how a custom controller factory resolves the controller from the container. Another example is the WCF facility in Windsor – it creates a service factory which resolves the service from the container. PRISM the same for it’s, presenter.
Consider this code:
The second example means dependencies are hidden. This makes using it without a Container impossible. Testing is much harder (you’d need to mock a response to Resolve<T>, assuming that static can be changed to a mock). There are some times when the only option you have is to call Resolve. In those instances you’re probably doing service location, so your class has a dependency on IServiceLocator. It would be wise to have a container agnostic interface (there’s actually one defined now in .Net).
The first has no dependency on a container, it’s just a class which inverts its dependency. Therefore, no abstraction of the container is required. As an aside, the decision to use a container is made on how big your dependency tree is. If your solution would benefit from a container to manage complicated dependency hierarchy, component lifetime etc. then use one. There is no container in SOLID just a lot of SOLID solutions would benefit from one.
In summary application code needs no abstraction of the container, just a service locator for the small percentage of cases you need service location…
There is a part of your code where the container will appear a lot. That’s in the bootstrapper where it needs to configure the container (register all the dependencies etc).
You have the option with most if not all containers to configure them in XML. This approach creates a maintenance headache. There’s more typing, no intellisense, refactoring support (if any) is ropey, it implies it can be changed at deployment time… The last point is a valid reason to use an XML configuration, but realistically a very small proportion of your application actually needs to be configured such that it can be changed at deployment time. If that is a requirement then consider using MEF on top of your container…
So having discounted XML for 80% of your configuration – that leaves you with configuring your container in code. There are many reasons why you may pick a particular IoC container. One important factor is its API – most importantly the confutation API (there’s only so many ways you can call resolve!). I have only used Castle Windsor and Unity in anger on commercial projects, so I can’t really comment on the rest of the containers… But what I can say is Castle Windsor is far superior to Unity (in my opinion). If the richness of the configuration API is a reason for picking a container, why abstract it? You undo all the good work of the people who created you the container.
Container configuration happens in your bootstrapper, it is not application code (this separation of concerns is important and is a key driver to creating a loosely coupled architecture). So your application itself doesn’t actually have a dependency on whatever container you pick. If you do ever need to change container then it’s a case of redoing the mundane configuration and writing some new bits of infrastructure to make sure Resolve is called at the right point (probably already done by the community!).
If you’re writing a framework where people may want to pick a different container then you should abstract the configuration. NServiceBus does this beautifully.
My conclusion is that if done properly your container never appears in application code and there is little value in abstracting the configuration unless you’re writing a developer API / framework.
I’m sorry if I’m just repeating what’s been said before, there was a debate a while ago started by Uncle Bob about when to use a container or not and the various retorts… I hope this gives some context to why I made the decision to lean on Windsor, as stated on my post on caching using an aspect. I think it’s Jeremy Miller (guy behind StructureMap) who talks about leaning on your container so I don’t think that is anything new…