IoC and the Unity Application Block

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

As many people who read this would know, I'm a big fan of IoC containers, more in particular Castle Windsor and StructureMap among my favorites.  Anyhow, lately, I've been playing with the Unity Application Block from Microsoft Patterns & Practices (P&P).  Very recently, Grigori Melnik, the product manager for EntLib 4.0 and the Unity Application Block announced the February 2008 Unity CTP.  Anyhow, it's been an active topic on the altdotnet list as well lately as noted here.

Basic Overview

If you're not familiar with the Unity Application Block, it was formerly the Dependency Injection Application Block.  The application block itself is built upon the next version of ObjectBuilder. For a good overview of ObjectBuilder, check out Chris Tavares's blog on the Deconstructing ObjectBuilder series:
Back History

I don't think it's any secret to anyone that many people hated the original implementation of ObjectBuilder.  I used it mostly in Composite Application Block (CAB) applications, but as well I've played with a few samples, enough to know it's too poorly documented to use in any type of system. 

Below, I have a code sample of the original ObjectBuilder approach to build a singleton instance of a Logger object:
 
Builder builder = new Builder();
Locator locator = new Locator();

// Create lifetime container for holding singletons
ILifetimeContainer lifetimeContainer = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), lifetimeContainer);

// Set my singleton policy for creating my logger
builder.Policies.Set<ISingletonPolicy>(new SingletonPolicy(true), typeof(Logger), null);

Logger logger = builder.BuildUp<Logger>(locator, null, null);

It's not the most fun code to write, nor was it very well documented.  David Hayden, EntLib guru extraordinaire also had issues with it as noted here

Another criticism lied in the fact that it was used in the EntLib, so it was hard for those to use another DI framework in its stead.  One of the big reasons behind ALT.NET was that the community wanted to help drive openness within Microsoft in terms of allowing third-party products to integrate fully within Microsoft products. 

Since then the EntLib team announced that they would open up a bit, but also, they were revamping ObjectBuilder as well, and now packaging it under the Unity Application Block.  This of course was met with skepticism from such folks as Jeremy Miller (StructureMap), and Ayende (Windsor/Bindsor contributor).  Of course to say, Ayende's objection was around the duplication of effort seen with Microsoft and the Open Source Community.  See MSTest versus xUnit.NET versus MbUnit versus NUnit as an example of this.  Jeremy Miller saw this as at last some openness within the P&P team, and I'd have to agree that they are consulting the outside community, which is great to see.  It's great to see that P&P and others are actively involved with ALT.NET and the outreach efforts in the community.  Others are a bit concerned because of many shops won't consider the other products such as StructureMap, Spring.NET, Windsor because Microsoft has an offering instead even though the others may be a bit more feature complete.

Taking it for a Test Spin

So, now that I got that other stuff out of the way, let's take things for a quick test spin.  Let's walk through code how to do a basic setup using Dependency Injection with a constructor injection:

namespace UnitySample
{
    public interface ILogger
    {
        void Log(string value);
    }

    public class ConsoleLogger : ILogger
    {
        public void Log(string value)
        {
            Console.WriteLine(value);
        }
    }

    public interface ICustomerTasks
    {
        void SaveCustomer(Customer customer);
    }

    public class CustomerTasks : ICustomerTasks
    {
        private ILogger logger;

        public CustomerTasks(ILogger logger)
        {
            this.logger = logger;
        }

        public void SaveCustomer(Customer customer)
        {
            logger.Log("Customer Saved");
        }
    }

    public class Customer
    {
        public string FirstName { get; set; }

        public string AccountNumber { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer()
                .RegisterType<ILogger, ConsoleLogger>()
                .RegisterType<ICustomerTasks, CustomerTasks>();

            ICustomerTasks tasks = container.Resolve<ICustomerTasks>();
            tasks.SaveCustomer(new Customer());
        }
    }

And as you can see from this, on the console window, you should receive a "Customer Saved" message.  So, that's using constructor injection.  Instead, we could have easily done this through property setter injection which is another popular way of doing injection.  Let's rewrite it just a bit to do that:

namespace UnitySample
{
    public class NullLogger : ILogger
    {
        public void Log(string value)
        {
            // Do nothing
        }
    }
 
    public class CustomerTasks : ICustomerTasks
    {
        private ILogger logger = new NullLogger();

        public void SaveCustomer(Customer customer)
        {
            logger.Log("Customer Saved");
        }

        [Dependency]
        public ILogger Logger
        {
            get { return logger; }
            set { logger = value; }
        }
    }
}

And if using the same program.cs as above, it should work just the same.  These of course are really simple samples, but what most basic DI frameworks do.  This is pretty easy to set up so far in my adventures.  Now you could do like the other DI frameworks and be heavy on the XML configuration as well.  It's not hard to set this up either.  Below is a basic example of this XML configuration file:

<?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="UnitySample.ILogger,UnitySample"
                mapTo="UnitySample.ConsoleLogger,UnitySample" />
          <type type="UnitySample.ICustomerTasks,UnitySample"
                mapTo="UnitySample.CustomerTasks,UnitySample" />
        </types>
      </container>
    </containers>
  </unity>
</configuration>

Now that we got the XML config done, let's then reimplement our program.cs to handle this:

namespace UnitySample
{
    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();

            // Load from config file
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers.Default.GetConfigCommand().Configure(container);

            ICustomerTasks tasks = container.Resolve<ICustomerTasks>();
            tasks.SaveCustomer(new Customer());
        }
}


Wrapping it Up

So, as you can see, it's pretty easy to get started.  This of course is the 1000 ft overview of what it can do.  Competition is a good thing when it comes to creating these frameworks.  Choice is a wonderful thing...  I am especially encouraged by P&P's openness to the community, as well as some in the community to give back and give feedback to Microsoft for these frameworks.  Without one, the other cannot become stronger.  I'm encouraged from the early signs of Unity and I've enjoyed the samples and playing with it as much as I have.  Give it a try and better yet, give feedback to the team...

Until next time...

kick it on DotNetKicks.com

2 Comments

Comments have been disabled for this content.