A Unity Hello World Example


Unity is crazy helpful framework developed by the patterns and practices group, but it’s a little hard to understand how to set it up, and where exactly it can be useful. I’m going to try in this blog to set up something super simple so you can get a good understanding of what the basic minimum is to get Unity going.

What Unity basically does, is provide an easy solution for dependency injection. With dependency injection, you can specify in a config file, which type of a class you want to instantiate without having to maintain different versions of solution, or rebuild. I’m going to start with a simple business scenario.

You are in charge of an inventory system for your company, and they have two locations. One is a simple where house where they maintain a small set of inventory items in SQL Server Express. The other is a larger one where the data is stored in Azure Tables. Other than that, the application is exactly the same. Just work with me on that one.

So, now as a developer, you need to program in two different ways of getting a hold of inventory data. To do this, we’re going to create an interface to represent the *very* crude operations our application will use to get data. Let’s start by creating a new C# console app. Call it “UnityHelloWorld”, and then create an Interface called IInventoryDataSource.

namespace UnityHelloWorld
{
    public interface IInventoryDataSource
    {
       InventoryItem LookupInventoryItem(int id);
       List<InventoryItem> GetAllItems();
       string GetSourceName();
       void AddInventoryItem(InventoryItem item);
    }
}

Great! Now, let’s go ahead and create two classes - One that will get the data from the SQL Server Express, and the other that will connect to Azure. We will put them in a folder called “Sources”. We won't actually connect them to the database or Azure, maybe we will address that in another blog post but for this example, we just want to get everything wired up.

namespace UnityHelloWorld.Sources
{
    class SQLExpressSource : IInventoryDataSource
    {
       public InventoryItem LookupInventoryItem(int id)
       {
          throw new NotImplementedException();
       }

       public List<InventoryItem> GetAllItems()
       {
          throw new NotImplementedException();
       }

       public string GetSourceName()
       {
          return "SQL Express";
       }

       public void AddInventoryItem(InventoryItem item)
       {
          throw new NotImplementedException();
       }
   }
}

The Azure class is basically the same thing except for the GetSourceName() method returns "Azure Source".

public string GetSourceName()
{
    return "Azure Source";
}

Now we have two different classes and they do the same things but in very different ways. As a developer, if we wanted to create this application for the different locations, we need to figure out how to use the class we want. Our options are:

1) Create an application for the Azure Data location, and another for the small SQL Express location.
2) Make it configurable so they can pick a location.

Now the first option might be great, except then we would have to maintain different versions. This is a horrible idea, but in the past I've done it. I remembering having two separate solutions, and the application did basically the same thing. I'd throw one onto a flash drive, and give it to the small shop up the road, and then install the other one on the web server at the big site. The biggest problem was always if there is a change, you need to fix it in both versions. Let’s never do it like this again.

Option #2 is a much better option than number one. You would create a field in app.config and set the environment you're in, and then write code to read that and instantiate the right class. It ends up looking something like this:

if (configSetting == "Azure")
{
Sources.AzureSource az = new Sources.AzureSource();
// do stuff......
}
if(configSetting == "SqlExpress")
{
Sources.SQLExpressSource ex = new Sources.SQLExpressSource();
//do stuff...
}

You can see how that gets hairy. What if we add a third data source? Or remove one? Besides, you need to either do this in every class that accesses data, or you need to create some Factory that creates it. In fact the basic factory pattern could help in that case. http://www.dofactory.com/Patterns/PatternAbstract.aspx.

Let’s do this in Unity instead. What Unity will let us do is use the interface to help us construct the class we need without having to hard code the class that gets used. I'll show you what I mean.

If you haven't already, go to the codeplex site and download the Unity. http://unity.codeplex.com/. Once you've got that, lets create an xml file to configure how Unity will work.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
   </configSections>
   <unity>
    <typeAliases>
      <!-- First comes the typeAlias, that lets us refer to UnityHelloWorld.IInventoryDataSource as just IInventoryDataSource -->
      <typeAlias alias="IInventoryDataSource" type="UnityHelloWorld.IInventoryDataSource, UnityHelloWorld" />
      <!-- Followed by Aliases for the sources-->
      <typeAlias alias="AzureSource" type="UnityHelloWorld.Sources.AzureSource, UnityHelloWorld" />
      <typeAlias alias="SQLExpressSource" type="UnityHelloWorld.Sources.SQLExpressSource, UnityHelloWorld" />
    </typeAliases>
    <containers>
      <container name="containerOne"> <!-- You can call the container anything you like. -->
        <types>
          <!-- Type mapping using aliases defined above -->
          <type type="IInventoryDataSource" mapTo="SQLExpressSource" /> <!-- The mapTo here lets us select which will get Resolved at runtime. -->
        </types>
      </container>
    </containers>
   </unity>
</configuration>

Now let’s go back to our Program.cs, and add some using files for unity, and to get a hold of our xml file:

using System.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

...and now let’s add some code to wire up the config file with unity...

IUnityContainer container = new UnityContainer();

ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "unity.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)config.GetSection("unity");
section.Containers["containerOne"].Configure(container);

These 6 lines of code basically say "go get the unity.xml files, and set up unity to use it." And now that we have Unity all configured, let’s use it!

To mimic "using" unity at this point, we are going tell it we want a new IInventoryDataSource, and it will be of whatever type that we configured in the unity.xml file. If you notice in the xml files, we've told it to map to the "SQLExpressSource". Here's the one line of code that does that:

IInventoryDataSource ds = container.Resolve<IInventoryDataSource>();

Now, in that one line, we never actually tell it what Class we are going to instantiate. We did that in the config file. As you would imagine, if we call the GetSourceName() method on ds, it will return "SQL Express" - which is what we coded in the class. Though Unity, we basically did this:

IInventoryDataSource ds = new Sources.SQLExpressSource();

That's freaking cool.

If we wanted to switch it to the Azure source, all we need to do is change the xml file. If we built a new source, like FlatFileDataSource or OracleDataSource, as long as it implemented IInventoryDataSource, we can add it to the xml file, and choose to have that instantiated instead. The great benefit to this is we don't have to dig through code and find the old instances and replace it with new ones.

There we go! Hopefully you can see the power and simplicity of using Unity in your application. More and more developers are starting to use this as a way of storing connection strings, as well and configuring development, test, and production server environments.

Can you see a use for it with the project you're working on? Would you like to see it actually connected to Azure? Let me know! I've attached the project for you to download and see.

Comments (0)

Skip to main content