IoC containers: an introduction to Autoregistration
I attended a talk by Krzysztof Kozmic at NDC2011 on IoC container patterns and antipatterns. Krzysztof contributes to the Castle Windsor IoC container, so it centered around Windsor.
I specifically want to talk about autoregistration, since this was a major topic of the talk, and is a best practice (at least it is in Windsor) and one that I have been gearing up to cover.
The talk was at the right level for me – it covered some intermediate and advanced topics for those who already knew the basics. Also I got to talk to him in person which helped my understanding of IoC. His talk and slides can be found here. He travelled to the conference all the way from Brisbane, Australia, which is quite impressive.
My posts on IoC and the comparison code that excercises IoC containers avoids autoregistration. This is useful for understanding how they work, but you can do better. I am working on sample code for autoregistratration in several IoC containers, and it will be ready soon. There are also other interesting topics in IoC that this talk raised, such as releasing of objects that implement IDisposable; and antipatterns like long-lived objects holding references to short-lived objects; widespread use of Service Locators. Maybe I will write code to those later.
If you haven't seen autoregistration before, Mike Hadlow's example is good. You can tell the container to reflect over the application and e.g. "register all types in this assembly as their implemented interfaces". This eliminates a lot of the container registration code. It's a good example of Convention over Configuration.
The takeways about autoregistration from Krzysztof's talk are that:
- Autoregistration reduces change when a new type is added to the code. Ideally, the container configuration code does not change at all since the autoregistration just picks up tthe new types like the existing types. Similarly if a type is removed.
- Autoregistration encourages conventions. Types that follow an internal convention are easier to autoregister. Thus a virtuous circle emerges: following conventions encourages autoregistration, which makes those conventions more useful.
- Use autoregistration by default. Failing that, for the cases that autoregistration is not suitable, or the component needs need special setup (e.g. different lifestyle, a different binding of a type in their constructor), register type mappings one at a time. Failing that, for components where custom logic is needed to make an instance, use a factory. There are various kinds in Windsor, but a simple Func<T> factory method is the most lightweight.
Use XML configuration only where configuration is needed after compilation time. e.g. if different deployments off the application will behave differently.
To be honest, it doesn't look impossible to roll your own autoregistration to suit your needs. You'd start with the type System.Reflection.Assembly and call GetExportedTypes to find out what can be registered, and carry on like this. But there's probably no need - the fluent registrations already written are also flexible enough to bend to your needs - they allow you to filter types, generally using your own code inejcted as lambdas.
Which IoC container?
In my reviews of IoC containers, I never actually said which one I would like to use. I would have a hard time deciding, but there are several good options:
I have autoregistration working in Autofac, Ninject, StuctureMap, Unity and Windsor. These are the main .Net IoC containers that are usually under consideration. In the basic scenarios, they all work well enough. For autoregistration, Windsor is hard to beat; but Autofac and StructureMap also work out of the box. Ninject and Unity both have autoregistration via addons.
Windsor and Autofac both easily do everything that I asked them to. Windsor is the larger and older of these two, and so has more stuff in it, but it is also more complex. This may not be an issue – the simple stuff is still simple in Windsor. And I was impressed from Krzysztof's talk that Windsor is actively being refined, and rough edges are gradually being smoothed. Ninject is also a good option, and so is Structuremap. Unity is acceptable, and may be easier to sell in "Microsoft only" shops since it's from Microsoft.
All of them are powerfull, and I will demonstrate how they do autoregistration in more detail in future posts:
- some groundwork for autoregistration.
- Autoregistration in Castle Windsor.
- Autoregistration in Microsoft Unity.
- Autoregistration in Ninject.
- Autoregistration in StructureMap.
- Autoregistration in Autofac.