IoC and the Unity Application Block - Going Deeper

Update:  Fixed code changed from CTP and More in the series:

I thought after my recent F# post, I'd get back to the Unity post that was halfway done before the firestorm began...

In a previous post, I showed how easy it was to create a basic application using the Unity Application Block. I'm always finding new ways to solve my problems and new tools to do it.  Since Inversion of Control (IoC) containers are near and dear to my heart, I thought I'd investigate to see whether it meets my needs or not.  It's something you need to determine on your own, whether it works for you.  Some like Spring.NET, others StructureMap, Castle Windsor and so on.

Purse Fight???

Now, there has been some rather heated discussion around the Unity Application Block on the altdotnet mailing list.  The discussion even got heated enough for the ALT.NET Pursefight blog to come back into action after a long hibernation with a post called "Dear Idiots"...

Compare/Contrast with Windsor

Anyhow, today I will focus on a little compare/contrast with Castle Windsor just to show the different styles used.  I'm not going to say one is better than the other, because quite frankly, that's up to you to decide...  I want to thank Dustin Campbell for his help in getting a better code formatter via this post here.

So, let's just take a sample from before and have our ILogger and create a singleton first using the Unity Container.  So, we will go ahead and use the ILogger interface, and create a concrete implementation of that called ConsoleLogger, inject it into the constructor and then call the Log method from within the CustomerTasks class.  Pretty simple scenario especially when dealing with cross cutting concerns.  So, the code to do this is below.

namespace UnitySamples

{

    public interface ILogger

    {

        void Log(string message);

    }

}


Now that we have a simple, undecorated interface, let's actually implement it in code for a simple console logger.  Not practical for real use, but shows a point.

using System;

 

namespace UnitySamples

{

    public class ConsoleLogger : ILogger

    {

        public ConsoleLogger()

        {

            Console.WriteLine("Hello from constructor");

        }

 

        public void Log(string message)

        {

            Console.WriteLine(message);

        }

    }

}


Now that we have that, let's create a class that takes an ILogger through constructor injection.

namespace UnitySamples

{

    public class CustomerTasks

    {

        private readonly ILogger logger;

 

        public CustomerTasks(ILogger logger)

        {

            this.logger = logger;

        }

        public void SaveCustomer()

        {

            logger.Log("Saved customer");

        }

    }

}


Ok, time to actually start up the UnityContainer by registering everything through code.  It's a pretty simple operation.  We want the ILogger instance to be a singleton instance.  This happens during the registration process by calling the SetSingleton<T>() method off the container itself.  Note the nice fluent interfaces for doing this component registration.

using Microsoft.Practices.Unity;

 

namespace UnitySamples

{

    class Program

    {

        static void Main(string[] args)

        {

            UnityContainer container = new UnityContainer();

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

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

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

            tasks1.SaveCustomer();

            tasks2.SaveCustomer();       

        }

    }

}


So, as you can see, no real config file was really necessary for me to do any of this.  It was a simple registration process of creating a UnityContainer.  But, that's not ideal, so let's set it as a singleton using the config file instead:

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();       

        }

    }

}


You'll notice that the configuration is still kind of awkward for having to get the configuration section this way and I'm hoping for a cleaner registration soon enough.  And the configuration file would look like this for the registration.  Note that I'm setting the lifetime to Singleton.  For those familiar with Castle Windsor, it should look pretty familiar.

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


So, now that we have this, let's run it and sure enough, the results are:
Hello from constructor
Saved customer
Saved customer

So, we notice that the constructor was called only once, which was our point all along.  Now, let's mosey along and do the same with Castle Windsor.  The only thing I want to change is the Program.cs and sure enough I can do that pretty easily and just change the namespaces.  For brevity's sake, I won't repaste the code with just the namespace change, so let's actually just show the Program.cs below.  First, I'll try using the component registration through the code itself.

using Castle.Core;

using Castle.Windsor;

 

namespace CastleSamples

{

    class Program

    {

        static void Main(string[] args)

        {

            WindsorContainer container = new WindsorContainer();

            container.AddComponentWithLifestyle("logger.console", typeof(ILogger), typeof(ConsoleLogger), LifestyleType.Singleton);

            container.AddComponent("customertasks", typeof(CustomerTasks));

 

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

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

            tasks1.SaveCustomer();

            tasks2.SaveCustomer();

        }

    }

}


Well, once again, it's nice to show we can register through the code itself, but not super useful.  Instead, things like that should get moved over to the config file instead.  Let's redo the code to reflect that:

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();

        }

    }

}


Ok, so our program looks much simpler now, so, let's move the stuff into the app.config and it should look 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>


And of course we run this and get the same result as we expected as before.  Now, what's cool is that none of my interfaces, nor implementations had any knowledge of my container, and so I can switch it out any time with no real harm to my components.  That's what I like.

Container Behavior

Another interesting thing to note is how some containers handle ambiguous references.  Ayende recently posted on the altdotnet list about how Unity versus Castle Windsor resolves.  Jeremy Miller also chimed in as well with this.

With this particular pseudocode, Castle Windsor can resolve this, while the other containers will fail due to an ambiguous reference. 

container.Register<IDisposable, SqlConnection>("SQL")
   .Register<IDisposable, OracleConnection>("ORA");

container.Get<IDisposable>();

AOP in Unity???

In a previous post, I covered how you can do runtime weaving in Castle Windsor by implementing the IInterceptor interface and registering it through the config file.  So, does the Unity Application Block support something like this?  The answer is yes, but it's not out of the box.  Instead, you can build a UnityContainerExtension that supports the Policy Injection Application Block (PIAB)Martijn Veken has built an extension to use the PIAB and you can read more about it here.  So, the AOP really isn't baked into Unity, but who knows, it may in the future, or it may just reside only in the PIAB.  Time will tell...

Conclusion

So, that's just the basics of a little Windsor and Unity bakeoff just to see some of the differences in philosophy.  I'd encourage everyone to take a look at most containers and find out which one really fits your need and programming style.  Competition and choice is a good thing.  Until next time...

kick it on DotNetKicks.com
Published Friday, February 22, 2008 6:13 PM by podwysocki
Filed under: , , ,

Comments

# re: IoC and the Unity Application Block - Going Deeper

Friday, February 22, 2008 9:14 PM by Torkel

I think your windsor example is not really fair, the code example and the config example has alot of unnessary stuff. You do not need to specify the logger parameter, etc.

# re: IoC and the Unity Application Block - Going Deeper

Friday, February 22, 2008 9:41 PM by podwysocki

Why is it unfair?  True, I don't need to specify the default constructor, nor parameters as it will pick up the first one.  I had this in there because I trimmed out another implementation of ILogger and never got rid of that code.  I can fix it though if you think it makes more sense.

# re: IoC and the Unity Application Block - Going Deeper

Sunday, February 24, 2008 9:57 PM by podwysocki

Point taken and I've changed it around as to play both sides with the exact same configuration.  Thanks for noticing and I hope to get further into things as time goes along.

Matt

# re: IoC and the Unity Application Block - Going Deeper

Tuesday, February 26, 2008 2:40 PM by The Godfather

Geez, Matt, BORING....   haha      Hi to KT

# re: IoC and the Unity Application Block - Going Deeper

Wednesday, February 27, 2008 4:29 AM by Udi Dahan

container.Register<ILogger, ConsoleLogger>();

Why on earth would you want to have to specify the interface supported when registering a component?

Just register the component.

container.Register<ConsoleLogger>();

The container should figure out which interfaces it supports.

# re: IoC and the Unity Application Block - Going Deeper

Friday, February 29, 2008 11:22 AM by podwysocki

@Udi Good point, although I was being explicit about which interface it goes with.  I know Ayende was doing something similar with registering IDisposable when wanting a SqlConnection and I wanted to avoid any ambiguity

# re: IoC and the Unity Application Block - Going Deeper

Wednesday, January 7, 2009 7:31 AM by kimptoc

Hi,

Thanks for the article, I was wondering how you could inject base types - like strings or numbers?  Or is that something you don't do with Unity?

Thanks,

Chris

# re: IoC and the Unity Application Block - Going Deeper

Saturday, January 10, 2009 5:25 PM by podwysocki

@Chris,

Of course you can, just make a type alias for it, much like you did for your other classes.

Matt