IoC and the Unity Application Block Once Again

Update:  Fixed code changed from CTP and More in the series:
After the reaction of my last post of talking about IoC and the Unity Application Block, I thought I'd include a few more samples of using Unity and how they compare with other IoC containers.  I realized after my first one, that I didn't give any love to StructureMap and I'm going to fix that for a brief sample as well.  I realize there are plenty of IoC containers out there including Spring, but quite frankly I've found it heavier than most, so I'm going to stick with Unity, Castle Windsor and StructureMap for this example.

Before I continue, check out David Hayden's screencast of IoC with ASP.NET MVC for some more interesting ideas regarding IoC and Unity.

Setter Injection versus Constructor Injection

I've been down the road of constructor injection versus setter injection.  My opinion is that you try to inject the most you can through your constructor such as in a Model View Presenter, injecting the View and the Service Layer.  Now, you may have cross-cutting concerns such as logging that you may want to swap out, but putting it in the constructor can just get ugly and you can set a default logger in your class anyways such as a NullLogger.  Martin Fowler, as always, covers this topic here and it's quite interesting as it is an open debate.

The other option I've done down this road was to create an IContext interface which is injected through the constructor that has some of the cross-cutting concerns wrapped up into it, but for now, let's just walk through a sample of having setter injection as well. 

Get Down to Details

Now that we got all the other stuff out of the way, let's go ahead and set up some basic examples in Unity, Castle Windsor and StructureMap doing setter injection.  I'll basically take the code from last time and apply it here as well.  So, let's start out with the Unity Application Block Sample:

namespace UnitySamples

{

    public interface ILogger

    {

        void Log(string message);

    }

}


And we have two implementations, the NullLogger (the default) and the ConsoleLogger (the override).  Let's go through each of those.

namespace UnitySamples

{

    public class NullLogger : ILogger

    {

        public void Log(string message)

        {

            // Do nothing

        }

    }

}


using System;

 

namespace UnitySamples

{

    public class ConsoleLogger : ILogger

    {

        public void Log(string message)

        {

            Console.WriteLine(message);

        }

    }

}


Now that I have these two implementations, I won't bother repeating these for the others unless they specifically change, which they shouldn't.  Now, to my implementation details of my CustomerTasks object.

using Microsoft.Practices.Unity;

 

namespace UnitySamples

{

    public class CustomerTasks

    {

        private ILogger logger = new NullLogger();

 

        [Dependency]

        public ILogger Logger

        {

            get { return logger; }

            set { logger = value; }

        }

 

        public void SaveCustomer()

        {

            Logger.Log("Saved customer");

        }

    }

}


As you may note, I set the default implementation of my logger to a NullLogger because by default, I don't care about logging, so it's about the same as a NoOp.  But, if I want to change that, I can through my setter injection.  This goes for any cross-cutting concern.  I also marked my Logger property with the DependencyAttribute which basically says that give me the ILogger instance registered when you go through the container to create it.  This of course requires class modification, so it's not a simple rip and replace as it was with constructor injection.  So, now let's look at the implementation of our configuration, much as before.

using System.Configuration;

using Microsoft.Practices.Unity;

using Microsoft.Practices.Unity.Configuration;

 

namespace UnitySamples

{

    class Program

    {

        static void Main(string[] args)

        {

            IUnityContainer container = new UnityContainer();

            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            section.Containers.Default.GetConfigCommand().Configure(container);

            CustomerTasks tasks1 = container.Resolve<CustomerTasks>();

            CustomerTasks tasks2 = container.Resolve<CustomerTasks>();

            tasks1.SaveCustomer();

            tasks2.SaveCustomer();  

        }

    }

}


And the configuration file will look much like before as:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <configSections>

    <section name="unity"

            type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,

                  Microsoft.Practices.Unity.Configuration" />

  </configSections>

  <unity>

    <containers>

      <container>

        <types>

          <type type="UnitySamples.ILogger,UnitySamples"

                mapTo="UnitySamples.ConsoleLogger,UnitySamples"

                lifetime="Singleton"/>

        </types>

      </container>

    </containers>

  </unity>

</configuration>


Now, let's do the same thing with Castle Windsor.  Most of the code will be the same from our Unity sample as I can't imagine that much will change except that I don't need to register the DependencyAttribute on the CustomerTasks object.  Let's first look at the changed CustomerTasks object.

namespace CastleSamples

{

    public class CustomerTasks

    {

        private ILogger logger = new NullLogger();

 

        public ILogger Logger

        {

            get { return logger; }

            set { logger = value; }

        }

 

        public void SaveCustomer()

        {

            Logger.Log("Saved customer");

        }

    }

}


Now, let's look at the program.cs file to see how really nothing changed at all from our perspective:

using Castle.Windsor;

using Castle.Windsor.Configuration.Interpreters;

 

namespace CastleSamples

{

    class Program

    {

        static void Main(string[] args)

        {

            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            CustomerTasks tasks1 = container.Resolve<CustomerTasks>();

            CustomerTasks tasks2 = container.Resolve<CustomerTasks>();

            tasks1.SaveCustomer();

            tasks2.SaveCustomer();

        }

    }

}


And then our config file looks like this:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <configSections>

    <section name="castle"

        type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />

  </configSections>

  <castle>

    <components>

      <component id="customertasks" type="CastleSamples.CustomerTasks, CastleSamples" lifestyle="transient" />

      <component id="logger.console" service="CastleSamples.ILogger, CastleSamples" type="CastleSamples.ConsoleLogger, CastleSamples" lifestyle="singleton" />

    </components>

  </castle>

</configuration>


So, in reality, nothing changed from our constructor injection versus our setter injection implementation for Castle Windsor.  That to me is pretty cool...  But, now, let's move our attention to StructureMap.  Let's walk through only the code that has changed.  I'm only going to use the one with the StructureMap.config file and not the fluent interfaces just yet.  I know more of the config file and not enough of the interfaces to be effective.  Let's go through what really changed.  In reality, everything is the same from the Castle Windsor implementation and the StructureMap one except for the Program.cs and the StructureMap.config file, so let's look at the Program.cs first.

using StructureMap;

 

namespace StructureMapSamples

{

    class Program

    {

        static void Main(string[] args)

        {

            CustomerTasks tasks1 = ObjectFactory.GetInstance<CustomerTasks>();

            CustomerTasks tasks2 = ObjectFactory.GetInstance<CustomerTasks>();

            tasks1.SaveCustomer();

            tasks2.SaveCustomer();  

        }

    }

}


And to make sure our object is a singleton, let's make our StructureMap.config file and walk through the details:

<?xml version="1.0" encoding="utf-8" ?>

<StructureMap>

  <PluginFamily Type="StructureMapSamples.ILogger" Assembly="StructureMapSamples" DefaultKey="Console">

    <Interceptors>

      <Interceptor Type="Singleton" />

    </Interceptors>

    <Plugin Assembly="StructureMapSamples" Type="StructureMapSamples.ConsoleLogger" ConcreteKey="Console" />

    </PluginFamily>

  <PluginFamily Type="StructureMapSamples.CustomerTasks" Assembly="StructureMapSamples" DefaultKey="CustomerTasks">

    <Plugin Assembly="StructureMapSamples" Type="StructureMapSamples.CustomerTasks" ConcreteKey="CustomerTasks">

      <Setter Name="Logger" Key="Console" />

    </Plugin>

  </PluginFamily>

</StructureMap>


If you're familiar with StructureMap, the config file should make sense to you as I'm creating an ILogger with the default implementation being the ConsoleLogger and then we make sure it is a singleton through the use of an interceptor.  Then we also do a setter injection through our plugin of the CustomerTasks with setting the Logger property to the key of Console.  Pretty simple and straightforward.

So, as you can see, they are very similar in nature, but attack the problem in different ways.  That's the beauty of it all, just determine your needs and your programming style and then the pick of your IoC container should come into line with that.  These are pretty simple and naive samples, but I just want to whet your appetite to open your mind and look for yourself at these containers for yourself.

AOP with PostSharp and Unity?

Gael Fraiteur recently posted on the altdotnet list about the new release of PostSharp.  Gael blogged about that here.  A couple of things intrigued me about it, including the license change to LGPL for the runtime and GPL for the code.  This requires a commercial license should you want to redistribute it with your application.  But, I'll leave that up to him and the lawyers to figure out. 

But, let's get back to Unity for just a second.  Gael recently announced on the Unity Application Block discussion list about including an extension to support PostSharp which you can find here.  You can find the code in particular to do this, plus the Stoplight sample converted at GoogleCode here under PostSharp4Unity.  Get your favorite SVN client and pull it down.

So, let's take my basic example from above and try to get it using the default constructors instead of the approach of calling the container to get ourselves an instance.  A good approach is to keep the container out of your way and produce cleaner code.  A downside of using IoC containers is that they can litter up your code.  PostSharp4Unity allows us to create an extension for Unity and use our default constructors.

First, let's create a Unity container provider so that we can initialize our container programmatically.  Create a UnityContainerProvider in your project that inherits from the IUnityContainerProvider.  That code should look like this:

using Microsoft.Practices.Unity;

using PostSharp4Unity;

using UnitySamples;

 

namespace UnitySamples

{

    public sealed class UnityContainerProvider : IUnityContainerProvider

    {

        private readonly IUnityContainer container;

 

        public UnityContainerProvider()

        {

            this.container = new UnityContainer()

                .RegisterType<ILogger, ConsoleLogger>(new ContainerControlledLifetimeManager());

        }

 

        public IUnityContainer CurrentContainer

        {

            get { return this.container; }

        }

    }

}


Now we also have to mark our assemblyinfo.cs with our default UnityProviderContainer, so open up your assemblyinfo.cs and put this info in there:

using PostSharp4Unity;

using UnitySamples;

 

[assembly: DefaultUnityContainerProvider(typeof(UnityContainerProvider))]


Ok, done and now we have to mark our class that we want to mark our configurable objects that we want to control with PostSharp.  So, open CustomerTasks and modify it to this:

using Microsoft.Practices.Unity;

using PostSharp4Unity;

 

namespace UnitySamples

{

    [Configurable]

    public class CustomerTasks

    {

        private ILogger logger = new NullLogger();

 

        [Dependency]

        public ILogger Logger

        {

            get { return logger; }

            set { logger = value; }

        }

 

        public void SaveCustomer()

        {

            Logger.Log("Saved customer");

        }

    }

}


So, then our program.cs can look like this now:

namespace UnitySamples

{

    class Program

    {

        static void Main(string[] args)

        {

            CustomerTasks tasks1 = new CustomerTasks();

            CustomerTasks tasks2 = new CustomerTasks();

            tasks1.SaveCustomer();

            tasks2.SaveCustomer();  

        }

    }

}


But, in order for PostSharp to do its magic, we need to make sure it's part of our compilation targets in our .csproj file.  So, I hand munged mine and got it to work like this:

  </PropertyGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <Import Project="$(PostSharpDirectory)PostSharp.targets" Condition=" Exists('$(PostSharpDirectory)PostSharp.targets') " />
</Project>

Then I'm able to get the magic of PostSharp to do its work.  Pretty slick!

Wrapping It Up

So, I hopefully whetted your appetite for these IoC containers for you to go and do a comparison on your own.  Each container has a different way of configuring itself and each solves a different problem set.  It's up to you to decide which one to use.  Along the way you can have a pretty cool journey though in learning deciding what works for you and what doesn't.  Until next time, and hopefully an F# related post...

kick it on DotNetKicks.com

27 Comments

  • Matthew,

    The equivalent Xml markup for StructureMap 2.5 will be considerably more terse. Even here, you don't have to configure the node like that. You could just put a Scope="Singleton" attribute on the node. There's also a [Setter] property that would eliminate the need for the Xml. You can also use the node instead of the full blown , , bit to collapse most of that down to one single Xml node.

    The Setter Injection support in StructureMap *is* clumsy, but I almost feel like that is a point in its favor. Setter injection is evil and I want it to feel bad.


    Part of my mission on StructureMap 2.0 and 2.5 has been to declare war on Xml configuration wherever it can be found until the angle bracket disease is quarantined.

  • Jeremy,

    Thanks for the feedback... I should have realized there's a better way of doing a singleton, but it's the way I've done it in the past. And good information on collapsing the XML down to the smallest possible footprint. I'm always for that.

    I'd agree that setter injection isn't the most preferred way of configuration due to making it crystal clear what your dependencies are. In fact, with my cross-cutting concerns, I'd rather stick with an injected IApplicationContext so that I can do things with logging. But instead of being dogmatic about it, I acknowledged it is there, but I do emphasize or perhaps I should have emphasized constructor injection instead.

    Matt

  • Phillip,

    No, I didn't forget you and in fact I've written about it in the past. Like I said before, there are many IoC containers out there and it's really hard to get my head around each and every one of them. Each of them tackle the problem in slightly a different way, which is good, because it can suit to different programming styles

  • From what I see, if you are using Setter Injection approach, Castle is better than Unity because you dont have to change the library code.

  • Hi there! This is my first comment here so I just wanted
    to give a quick shout out and tell you I really enjoy reading
    through your articles. Can you recommend any other blogs/websites/forums that deal with
    the same topics? Thanks for your time!

  • i use both gold and silver bracelets because for me, that they have been both
    great bracelets to wear;;

  • you can still also give away your baby some antibacterial baby
    socks to ensure that your baby is always clean`

  • I visited plenty of website in spite of this I believe this one has something extra in
    it in it

  • Very nice post. I just stumbled upon your blog and wanted to say that I have truly enjoyed surfing around your
    blog posts. In any case I'll be subscribing to your rss feed and I hope you write again very soon!

  • This is my first time I have visited your site. I found plenty of interesting
    information in your blog. Out of the quite a lot of comments on your posts, I guess
    I am not the merely one! keep up that the great work.

  • Very man or woman speeches need to seat giving observe into couples.
    Brand new sound method just before unnecessary people
    should always be mindful of usually senior common rule out
    of public speaking, which can be to be that the mini.
    best man speaches

  • i would love to use hydrogen fuel on my car, this fuel is actually
    nonpolluting in spite of this is just not yet very available,.

  • foot massage have been very relaxing, i love to have a foot massage after a hard days work”

  • hey read your post – Gulvafslibning Kurt Gulvmand in spite of this couldn’t get a hold of your contact form.
    Is there a better method to contact you then through comments?

  • This is some great information. I expect additional facts something like this was distributed across that the web today.

  • He keeps both strands moving along at equal pace, Cage’s is more
    engrossing; that the film paying sly hint to knowing so when it
    utilises the concoction of Hit-Girl to drive that the film’s
    final act on behalf of Cage’s plight.

  • WOW just what I was searching for. Came here by searching for type body

  • The core of your writing whilst appearing agreeable initially, did not sit very
    well with me personally after some time. Someplace throughout that the sentences you
    really were able to make me a believer unfortunately merely for
    a while. I on that the other hand have a query with your leaps in logic and you
    might do well to fill in those breaks. In that the event
    that you really can accomplish that, I could certainly be fascinated.

  • You could definitely see your expertise
    within the work you write. The arena hopes for even more
    passionate writers such as you who are not afraid to mention how they believe.
    Always go after your heart.

  • I am genuinely thankful to the holder of this web page who has shared this wonderful piece of writing
    at here.

  • Heya i'm for the first time here. I found this board and I find It truly useful & it helped me out a lot. I am hoping to provide one thing again and help others such as you aided me.

  • I take pleasure in, cause I discovered just what I was looking for.
    You have ended my 4 day long hunt! God Bless you man.
    Have a nice day. Bye

  • This is a topic that's near to my heart... Many thanks! Exactly where are your contact details though?

  • This is a topic that's near to my heart... Many thanks! Exactly where are your contact details though?

  • My relatives always say that I am killing my time here at net, however I know I am getting
    familiarity everyday by reading such good content.

  • Currently it seems like BlogEngine is the preferred blogging platform available right now.
    (from what I've read) Is that what you're using
    on your blog?

  • Hi there, just became alert to your blog through Google,
    and found that it is truly informative. I am going to watch out for brussels.
    I will appreciate if you continue this in future.
    Lots of people will be benefited from your writing.
    Cheers!

Comments have been disabled for this content.