IoC libraries compared

January 7th, 2009

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

  • http://www.ElegantCode.com Chris Brandsma

    @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?

  • Pingback: Arjan`s World

  • http://rant.blackapache.net/ OJ

    Autofac’s author joined MS after Autofac was created and thrown on Google Code (I believe :)).

  • Steve Py

    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 :D )

    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.)

  • http://richarddingwall.name Richard Dingwall

    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.

  • Pingback: Weekly Links #35 | GrantPalin.com

  • Pingback: wolf++ » TuneWiz Loosely Coupled, Easily Testable

  • Bryan

    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…

  • Wade

    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!

  • http://www.ElegantCode.com Chris Brandsma

    @Wade: I didn’t say you had to have attributes with StructureMap, I said attributes were an option. Just like Xml config…it is an option.