IoC libraries compared

I had just posted this to a question on StackOverflow about the differences between various IoC libraries.  By the time I was done I realized I had a blog post.

I am prepping a presentation for a usergroup…as such I just when thru a bunch of them. Namely: AutoFac, MEF, Ninject, Spring.Net, StructureMap, Unity, and Windsor.  I was able to get all of these to work but MEF.  But I’m sure it is nothing that Glen Block couldn’t fix.

I wanted to show off the 90% case (constructor injection, which is mainly what people use an IOC for anyway). You can check out the solution here (VS2008).

As such, there are a few key differences: * Initialization * Object retrieval

Each of them have other features as well (some have AOP, and better gizmos, but generally all I want an IOC to do is create and retrieve objects for me)

Note: the differences between the different libraries object retrieval can be negated by using the CommonServiceLocator.

That leaves us with Initialization, which is done in two ways: via code or via xml configuration (app.config/web.config/custom.config). Some support both, some support only one. I should note: some use attributes to help the IoC along.

About my preference on xml vs code initialization: I started with Spring.Net using xml initialization, later switch to unity with code initialization.  I don’t like xml initialization anymore.  It is too easy to mess up, very error prone, not debugable, and not as testable as I would like. 

On Attributes, which a few support, I’m not a huge fan — but I could be convinced otherwise down the road.  

Finally on typeof: every time I had to write a typeof I threw up in my mouth a little bit.  I’m sure there are reasons for type of, but since the inception of generics in .net 2.0 I don’t see the need.  I’m looking at you Windsor and Spring.Net.

So here is my assessment of the differences:

Ninject

( Code initialization only — with attributes). I hope you like lambdas. Initialization code looks like this:

   1: IKernel kernel = new StandardKernel(
   2:     new InlineModule(
   3:                     x => x.Bind<ICustomerRepository>().To<CustomerRepository>(),
   4:                     x => x.Bind<ICustomerService>().To<CustomerService>(),                    
   5:                     x => x.Bind<Form1>().ToSelf()                    
   6: ));

Also, Ninject has the coolest web site of all the containers.

StructurMap

(Initialization code or Xml or Attributes) Version 2.5 is also very lambda’y. All in all, this is one of my favorites. Some very interesting ideas around how StructureMap uses Attributes.

But, here is my StructureMap initialization code:

   1: ObjectFactory.Initialize(x =>
   2:      {
   3:          x.UseDefaultStructureMapConfigFile = false;
   4:  
   5:          x.ForRequestedType<ICustomerRepository>()
   6:              .TheDefaultIsConcreteType<CustomerRepository>()
   7:              .CacheBy(InstanceScope.Singleton);
   8:  
   9:          x.ForRequestedType<ICustomerService>()
  10:              .TheDefaultIsConcreteType<CustomerService>()
  11:              .CacheBy(InstanceScope.Singleton);
  12:  
  13:          x.ForConcreteType<Form1>();
  14:      });

Also, you can also go nearly config-less with StructureMap.  This is the Attribute driven style.  You litter all of your classes with the attributes Pluggable and PluginFamily.  Then add a file to your project called StructureMap.config that looks like this:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <StructureMap>
   3:   <Assembly Name="StructureMapConfigDemo" />
   4: </StructureMap>

After that you are good to go.  I kind of like this approach…but I feel dirty afterwards.

Unity

(Initialization code and Xml) Nice library, but xml configuration is a pain in the butt. Great library for Microsoft or the highway shops. Code initialization is easy:

   1: container.RegisterType<ICustomerRepository, CustomerRepository>()
   2:           .RegisterType<ICustomerService, CustomerService>();

If you want to initialize via xml, here is what to look forward to:

   1: <unity>
   2:   <typeAliases>
   3:     <typeAlias alias="int" type="System.Int32, mscorlib" />
   4:     <typeAlias alias="singleton"
   5:                type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
   6:     <typeAlias alias="ICustomerRepository"
   7:                type="UnityConfigDemo.ICustomerRepository, UnityConfigDemo" />
   8:     <typeAlias alias="ICustomerService"
   9:                type="UnityConfigDemo.ICustomerService, UnityConfigDemo" />
  10:   </typeAliases>
  11:   <containers>
  12:     <container>
  13:       <types>
  14:         <type type="ICustomerRepository" mapTo="UnityConfigDemo.CustomerRepository, UnityConfigDemo">
  15:           <lifetime type="singleton" />
  16:         </type>
  17:         <type type="ICustomerService" mapTo="UnityConfigDemo.CustomerService, UnityConfigDemo">
  18:           <lifetime type="singleton" />
  19:           <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
  20:             <constructor>
  21:               <param name="dbo" parameterType="ICustomerRepository"/>
  22:             </constructor>
  23:           </typeConfig>
  24:         </type>
  25:         <type type="UnityConfigDemo.Form1, UnityConfigDemo">
  26:           <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
  27:             <constructor>
  28:               <param name="customerService" parameterType="ICustomerService"/>
  29:             </constructor>
  30:           </typeConfig>
  31:         </type>
  32:       </types>
  33:     </container>
  34:   </containers>
  35: </unity>

That was by far the largest amount of xml require to initialize any of the containers. I’m hoping Chris Tavares can fix that down the line.

Actually, my biggest gripe with Unity is the name.  For all the other IoC libraries, if I google the name I get their web site as the first link.  Not Unity.  This make Unity the hardest to find info on.

Spring.net

(xml only as near as I can tell) But does everything under the sun that an IoC can do. I used to use this one, I will not any more.

Anyway, here is a sample of the xml from the app.config.

   1: <spring>
   2:   <context>
   3:     <resource uri="config://spring/objects"/>
   4:   </context>
   5:   <objects xmlns="http://www.springframework.net">
   6:     <object name="MyCustomerRepository" type="SpringDemo.CustomerRepository, SpringDemo"  />
   7:     <object name="MyCustomerService" type="SpringDemo.CustomerService, SpringDemo" >
   8:       <constructor-arg ref="MyCustomerRepository" />
   9:     </object>
  10:     <object name="MyForm1" type="SpringDemo.Form1, SpringDemo">
  11:       <constructor-arg ref="MyCustomerService" />
  12:     </object>
  13:   </objects>  
  14: </spring>

Also, without the Common Service Locator, Spring.Net is not generic friendly.  Another gripe, the download expands to 120 meg (you don’t need all of it).  They include every single thing under the sun (.Net 1.1 and 2.0 asseblies, tutorials, extras, addons, docs, kitchen sink), which makes it a bit more daunting than it is.

Windsor

(xml and code). This one just rubs me the wrong way. No support for generics, configuration is a pain no matter what (to me). But it also does anything you could want it to do. (Edit: I’ve been getting a lot of heat from the Castle Windsor Right-Wing Conspiracy movement.  So I took another look at the api — and realized I was wrong.  Sorry, my bad.  I’ve updated the code using a better api.  Words to remember: Reflector is your friend — not ReSharper’s intellisense).

Here is a sample of in-code initialization:

   1: IWindsorContainer container = new WindsorContainer();
   2:  
   3: container.AddComponentWithLifestyle<ICustomerRepository, CustomerRepository>("CustomerRepository", LifestyleType.Singleton);
   4: container.AddComponentWithLifestyle<ICustomerService, CustomerService>("CustomerService",LifestyleType.Singleton);
   5: container.AddComponent<Form1>("Form1");

Or, here is my code from my app.config:

   1: <castle>
   2:   <components>
   3:     <component
   4:         id="CustomerRepository"
   5:         service="WindsorConfigDemo.ICustomerRepository, WindsorConfigDemo"
   6:         type="WindsorConfigDemo.CustomerRepository, WindsorConfigDemo" />
   7:     <component
   8:         id="CustomerService"
   9:         service="WindsorConfigDemo.ICustomerService, WindsorConfigDemo"
  10:         type="WindsorConfigDemo.CustomerService, WindsorConfigDemo" />
  11:     <component
  12:         id="Form1"
  13:         type="WindsorConfigDemo.Form1, WindsorConfigDemo" />
  14:   </components>
  15: </castle>

Autofac

(code and xml). Nice simple IoC library. Seems to do the basics with not much fuss. Here is how you initialize it:

   1: var builder = new ContainerBuilder();
   2: builder.Register<CustomerRepository>()
   3:         .As<ICustomerRepository>()
   4:         .ContainerScoped();
   5: builder.Register<CustomerService>()
   6:         .As<ICustomerService>()
   7:         .ContainerScoped();
   8: builder.Register<Form1>();

xml configuration looks like this:

   1: <configSections>
   2:   <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac"/>
   3: </configSections>
   4:  
   5: <autofac defaultAssembly="AutofacConfigDemo">
   6:   <components>
   7:     <component
   8:             type="AutofacConfigDemo.CustomerRepository, AutofacConfigDemo"
   9:             service="AutofacConfigDemo.ICustomerRepository, AutofacConfigDemo" />
  10:  
  11:     <component
  12:             type="AutofacConfigDemo.CustomerService, AutofacConfigDemo"
  13:             service="AutofacConfigDemo.ICustomerService, AutofacConfigDemo" >
  14:     </component>
  15:      <component
  16:             type="AutofacConfigDemo.Form1, AutofacConfigDemo"
  17:             service="AutofacConfigDemo.Form1, AutofacConfigDemo" >
  18:     </component>
  19:   </components>
  20: </autofac>

Which also change the code initialization to read the xml:

   1: var builder = new ContainerBuilder();
   2: builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
   3: using (IContainer container = builder.Build())
   4: {
   5:     Application.Run(container.Resolve<Form1>());
   6: }

Fun tidbit about this one: the main contributor for this project is a Microsoft employee — and the code is on Google Code.  Why not CodePlex?  I have no idea.

 

My final verdict (for just this minute)

If I had to choose today: I would probably go with StructureMap. It has the best support for C# 3.0 language features, and the most flexibility in initialization.

If I was in a non-opensource friendly environment, I would go with Unity (or MEF, but I have to get it to work first).

Further Reading

35 thoughts on “IoC libraries compared

  1. Excellent post! I’m glad your post on SO brought up Common Service Locator. I think that’s a good project contributed by great developers that can steer people in the right direction. The direction of at least using an IoC container. 🙂

  2. Why not CodePlex? Why codeplex/ – Google code is SVN natively and Google Code website are clear and simple (UI design wins hands down). Is it just me or do Google Code project sites load in a split second vs CodePlex 5-6 sceonds, in my experience CodePlex SVN adapter (which I believe is based on Ayende code) isn;t always reliable (although it could of been underlying TFS).

  3. Thank you for the summarized list. It is useful.
    Regarding Unity Configuration, I don’t see it pain, so I disagree with you. One of the things that might let me switch from StructureMap to Unity is the configuration. I found Unity very simple to be used in terms of Code or Configuration.
    Would like to know other opinions
    Cheers

  4. Thanks for a reasonable comparison. For what it’s worth, we have made the XML slightly better – you don’t need to put in the extensionType attribute on the element anymore.

  5. for Windsor, if you prefer generics, you could rewrite your code as

    container.Register(
    Component.For().Named(“CustomerRepository”).ImplementedBy(),
    Component.For().Named(“CustomerService”).ImplementedBy(),
    Component.For.Named(“Form1”))

  6. my tags got removed but you can imagine what i mean

    Component.For(<ICustomerRepository>).Named(”CustomerRepository”).ImplementedBy(<CustomerRepository>),

  7. ok…

    container.Register(
    Component.For&ltICustomerRepository>().Named(”CustomerRepository”).ImplementedBy&ltCustomerRepository>(),
    Component.For&ltICustomerService>().Named(”CustomerService”).ImplementedBy<CustomerService>(),
    Component.For&ltForm1>().Named(”Form1?))

    it’s a shame your blog doesn’t support generics! 😉

  8. Thanks Chris, Great Post!!! Post like this are so helpful when there are so many choices and so little time. I appreciate the general feel you have given regarding these containers. I would love to see more posts like these that give a higher level view, most post I see regarding IOC containers re very deep and don’t give someone like myself a good feel for the choices that are available.

  9. @Adam: I’ll have to look into the use of generics with Windsor. But this points to a problem with a lot of these libraries: not great documentation. Or the documentation is there, but the organization is not.

  10. @Muhammad Mosa: pain is relative. I found that I had a lot of typing to get unity configured via xml. But, the code base configuration was no problem at all.

    As I stated in the article, I shy away from xml configuration whenever possible these days anyway.

  11. @Adam You can only do that with windsor if you have the fluent interface libraries, which you have to pull off directly from their source control (and last I checked build yourself, this has probably changed).

    You could however use generics like this:
    _container.AddComponent();

  12. @James,
    How would someone find that site by browsing the Windsor web site?
    Great work and all, but shouldn’t that sort of thing be part of the library you download from the source, not as yet another addon from a completely separate site?

  13. Pingback: Arjan`s World
  14. Yeah, Nick co-wrote Autofac before getting head-hunted to M$ along with the creator of Windsor to work on MEF. I’ve worked with him on occassion including his last assignment prior to getting head-hunted. (Bastage left a big mess over here! j/k 😀 )

    Autofac has my vote now due to its simplicity. We use it here with our web projects. One other thing worth noting is it has a contrib project to compliment it, and I believe a few Brisbane-ites are working on a Winform variation.

    StructureMap is one I’ll be taking a closer look at this year. One tidbit I did learn over on codeBetter is that they have a diagnostic mode to inspect their XML configuration to throw a meaningful exception early rather than NullReferenceExceptions. (A bad smell I get when using IoC containers.)

  15. Nice comparison. Does it worry anyone that there are so many options available? Do compelling reasons exist why each of these six libraries is best for different situations, or are some just me-too coding experiments along for the ride?

    Personally, I’ve settled on Unity CommonServiceLocator. I genuinely prefer the API over most of the open-source offerings (which is rare and impressive for MS), and being part of the enterprise library, it stands out in terms of long-term supportability.

    I also prefer in-code initialization. I never really saw the point of external XML/boo/whatever configuration, unless your application properly supports plugins.

  16. I love Autofac. It’s syntax is great, it’s so simple to configure, and it doesn’t include everything and the kitchen sink (which I don’t need).

    Spring’s XML configuration? I hope I never have to touch that ever again…

  17. Just a note, I have StructureMap working completely free of config files and without attributes! It wasn’t mentioned in your coverage but you can register all of the objects by simply calling IAssemblyScanner.LookForRegistries() within the object factory initialization. Then in your registry file you setup fluently your contracts and defaults. No attributes needed!

  18. Pingback: Confluence: Java
  19. very good post, thanx.
    but can u:
    1. add MEF to the others in detail.
    2. update the post for this year 2011.

Comments are closed.

Proudly powered by WordPress | Theme: Code Blog by Crimson Themes.