Share via


Introduction to Unity Application Block 2.1

In this post I would like to do a simple introduction to Unity Application Block. Unity is a framework that supports dependency injection (DI) in constructors, properties, and method calls.  Unity also supports intercepting method calls which I may cover in a later post.

The documentation for Unity is pretty detailed, so it is probably a good place to start for background information.  I’ve also included a link to the download area in the references section at the bottom of the post.

What is Unity and why would you use it?

When you start a project, the code base is usually small so it is not difficult to maintain or test. As the project gets larger, it is often the case that it gets broken down into components, and each component is created separately, and then integrated into the rest of the project. 

In the beginning, the components are self contained and testable on their own if the person doing the work was paying attention to object oriented design principles.  Even if the component was carefully constructed, at some point during integration it is usually the case that component boundaries begin to break down and components start having strong dependencies on each other.

Part of the break down of component boundaries happens because components start to inherit responsibility for configuring the dependencies with other components.  Once a component has built in knowledge on how to create and configure another component, it becomes difficult to separate the components and test them independently.

This is where Unity comes in. Not only does Unity take the responsibility for creating and configuring components, it does so in a consistent way. Components don’t have to know where their dependent components come from. In addition, Unity can automatically create the dependent components if, necessary, or use existing instances.

Inversion of Control (IoC)

Inversion of control is a term that shows up often with dependency injection. It refers to a plug in architecture where the application supplies customizations to the platform it is written on, and the platform holds the logic to use the application supplied plug-ins.

I won’t be covering much about creating plug in architectures in this post. You can probably see how this can be accomplished  using Unity by the end of the post though.

The Unity Container

In Unity, everything begins with a container. It can be created simply like this:

 IUnityContainer container = new UnityContainer();

 

If you want to request that the container create you an instance of a class, all you need to do is call the Resolve method.  It can create instances of classes it doesn’t even know about if they have default constructors:

 var c = container.Resolve<MyClass>();
 c.DoSomething();

 

Although this is interesting, it isn’t particularly useful. You can’t do much with an object in isolation. You have to connect to other objects. Lets try the following class that requires two classes as inputs to the constructor:

 public class MyClass2
 {
     private DependantClass1 m_class1;
     private DependantClass2 m_class2;
  
     public MyClass2(DependantClass1 class1, DependantClass2 class2)
     {
         m_class1 = class1;
         m_class2 = class2;
     }
  
     internal void DoSomething()
     {
         Console.WriteLine("MyClass2.DoSomething");
     }

 

Is the following code going to work?

 var c2 = container.Resolve<MyClass2>();
 c2.DoSomething();

 

Certainly, so long as the container can find existing instances or constructors it can use to satisfy the dependencies.  Although this is a bit more interesting, a program using default arguments still isn’t that useful. You need to be able to vary the behavior of the program by providing some input.

Registering instances

At some point, you will need to pass in several objects of the same type but have different uses. You can distinguish instances of the same type by naming them explicitly.

To show this example, I have created a few classes to configure an API that I have some familiarity with.  The initialization code traditionally looks like the following:

 var platformSettings = new PlatformSettings();
 platformSettings.ListeningPort = 5060;
 platformSettings.ProxyHost = "sip.contoso.com";
 platformSettings.ProxyPort = 5060;
  
 var platform = new Platform(platformSettings);
  
 var endpointSettings = new EndpointSettings();
 endpointSettings.AddressOfRecord = "sip:helpdesk@contoso.com";
  
 var endpoint = new Endpoint(platform, endpointSettings);
  
 var conversationSettings = new ConversationSettings();
 conversationSettings.Subject = "This weeks news article.";
  
 var conversation = new Conversation(endpoint, conversationSettings);

 

To use the container to build the object graph, I can distinguish between the string inputs by naming them with special names. The following shows one way of doing this with the Unity container:

 IUnityContainer container = new UnityContainer();
  
 container.RegisterInstance<int>("proxyPort", 5060);
 container.RegisterInstance<string>("proxyHost", "sip.contoso.com");
  
 container.RegisterInstance<int>("listeningPort", 5060);
 container.RegisterInstance<string>("aor", "sip:helpdesk@contoso.com");
 container.RegisterInstance<string>("subject", "This weeks news article.");
  
 var conversation = container.Resolve<Conversation>();

 

Now this is starting to get useful?  I saved a few lines creating object instances and configuring objects.  You can see how I gave special names to various strings and integers so they can be plugged in the proper places.  Doing this requires adding a few attributes to your classes as shown below:

 public class PlatformSettings
  {
      public PlatformSettings()
      {
      }
  
      [Dependency("listeningPort")]
      public int ListeningPort
      {
          get;
          set;
      }
  
      [Dependency("proxyHost")]
      public string ProxyHost
      {
          get;
          set;
      }
  
      [Dependency("proxyPort")]
      public int ProxyPort
      {
          get;
          set;
      }
  }
  
  public class EndpointSettings
  {
      public EndpointSettings()
      {
      }
  
      [Dependency("aor")]
      public string AddressOfRecord
      {
          get;
          set;
      }
  }
  
  public class ConversationSettings
  {
      public ConversationSettings()
      {
      }
  
      [OptionalDependency("subject")]
      public string Subject
      {
          get;
          set;
      }
  }
  
  public class Platform
  {
      private PlatformSettings m_settings;
  
      public Platform(PlatformSettings settings)
      {
          m_settings = settings;
      } 
  
      public int ListeningPort
      {
          get
          {
              return m_settings.ListeningPort;
          }
      }
  
      public int ProxyPort
      {
          get
          {
              return m_settings.ProxyPort;
          }
      }
  
      public string ProxyHost
      {
          get
          {
              return m_settings.ProxyHost;
          }
      }
  
  }
  
  public class Endpoint
  {
      private EndpointSettings m_settings;
      private Platform m_platform;
  
      public Endpoint(Platform platform, EndpointSettings settings)
      {
          m_platform = platform;
          m_settings = settings;
      }
  
      public Platform Platform
      {
          get
          {
              return m_platform;
          }
      }
  
      public string Uri
      {
          get
          {
              return m_settings.AddressOfRecord;
          }
      }
  
  }
  
  public class Conversation
  {
      private ConversationSettings m_settings;
      private Endpoint m_endpoint;
  
      public Conversation(
          Endpoint endpoint, 
          ConversationSettings settings)
      {
          m_endpoint = endpoint;
          m_settings = settings;
      }
  
      public Endpoint Endpoint
      {
          get
          {
              return m_endpoint;
          }
      }
  
      public string Subject
      {
          get
          {
              return m_settings.Subject;
          }
      }
  }

  

Creating objects later

Just because we have this cool container object, doesn’t mean that our need to create additional objects at a later time goes away. That’s no problem, we can just call container.Resolve<xxx>() any time we need anything.  But to do that we need to have the container available in each object.

Why not have the container inject itself for any object that needs it?  We can start by having the container register an instance of itself:

 IUnityContainer container = new UnityContainer();
 container.RegisterInstance<IUnityContainer>(container);

 

Then in each class that uses it, take the container in the constructor:

 public Conversation(
      Endpoint endpoint,
      ConversationSettings settings,
      IUnityContainer container)
 {
      // ...
      m_container = container;
      // ...
 }

 

The class Conversation is now automatically configured to create other objects when it needs to.

Let’s assume that an application could choose to make an audio call or an instant messaging call. We don’t know the application’s intent when the conversation is created, so it is probably not a good idea to pre-create both and waste memory. We can use the new Lazy<> class in .Net 4.0 to lazy create the calls only when needed. The new conversation class looks like this:

 public class Conversation
  {
      private ConversationSettings m_settings;
      private Endpoint m_endpoint;
      private Lazy<InstantMessagingCall> m_call;
      private IUnityContainer m_container;
  
      public Conversation(
          Endpoint endpoint,
          ConversationSettings settings,
          IUnityContainer container)
      {
          m_endpoint = endpoint;
          m_settings = settings;
          m_container = container;
  
          m_call = new Lazy<InstantMessagingCall>(
              () =>
              {
                  return m_container.Resolve<InstantMessagingCall>();
              }, true);
      }
  
      public Endpoint Endpoint
      {
          get
          {
              return m_endpoint;
          }
      }
  
      public string Subject
      {
          get
          {
              return m_settings.Subject;
          }
      }
  
      public InstantMessagingCall InstantMessagingCall
      {
          get
          {
              return m_call.Value;
          }
      }
  }

 

There is one problem with the implementation though. If I print out the instance of conversation attached to the call, and the original one I find they are different:

 Console.WriteLine(
     "IMCall is hooked up to the same instance of conversation: {0}", 
     object.ReferenceEquals(conversation, call.Conversation));
  

 

The code above yields the following output:

 IMCall is hooked up to the same instance of conversation: False

 

Why is it that the conversation has an IM Call that has a pointer to another conversation instance? It is because the container didn’t know about the existing conversation and automatically created a new one. We don’t really want that behavior. To reuse the same instance, we can add the following line to the conversation constructor:

 m_container.RegisterInstance<Conversation>(this);

 

And then the instant messaging call will contain a pointer back to its parent as expected.

 IMCall is hooked up to the same instance of conversation: True

 

There is another way to do this in Unity for some cases. You can specify that the lifetime of the conversation is tied to the container (i.e. singleton within the container).  Once one object is created, all references to the conversation will be resolved back to this singleton instance.

Summary

In this post I briefly did some exploration of the Unity Application Block.  Using the Unity container and dependency injection requires you to re-think how you design your code.

One great article by Chris Tavares I found was a description of how the use of dependency injection impacts library design. In library design, there are many challenges, including maintaining backward compatibility when you change the underlying structure of the code. Of particular interest, they were able to remove quite a few (200) classes from their code once Unity was integrated.

References

Download Unity 2.1

MSDN Documentation

Using Dependency Injection in Libraries

Comments

  • Anonymous
    August 01, 2011
    It's much cleaner to work with unities capacity to inject Func<IDependency> than using the IContainer interface directly. This keeps your code unaware if the IoC. Daniel

  • Anonymous
    August 01, 2011
    Thanks for the tip. Are you willing to give pointers to existing examples or possibly post a code sample using the technique?

  • Anonymous
    August 01, 2011
    Hy Of course. Your friends are pretty active on this :) blogs.msdn.com/.../unity-2-0-automatic-builders.aspx blogs.msdn.com/.../unity-2-0-automatic-builders.aspx unity.codeplex.com/.../79957 Happy IoC

  • Anonymous
    August 01, 2011
    Just change your Conversation class like this (compiled in Firefox ;-) ): public class Conversation {     private ConversationSettings m_settings;     private Endpoint m_endpoint;     private Lazy<InstantMessagingCall> m_call;     public Conversation(         Endpoint endpoint,         ConversationSettings settings,         Func<InstantMessagingCall> imCallFactory)     {         m_endpoint = endpoint;         m_settings = settings;         m_container = container;         m_call = new Lazy<InstantMessagingCall>(imCallFactory, true);     }     // SNIP : Everything else is the same } See msdn.microsoft.com/.../ff660854%28PandP.20%29.aspx

  • Anonymous
    May 03, 2012
    I don't get the difference between return m_call.Value; and return m_container.Resolve<InstantMessagingCall>(); (leaving out the lazy class)

  • Anonymous
    October 13, 2012
    Nice article, readers can download samples here code.msdn.microsoft.com/Dependency-Injection-with-5702acaf

  • Anonymous
    November 06, 2012
    RE: Lazy<> vs not having Lazy<> The Lazy<> class will call resolve only when m_call.Value is accessed. The motivation is that it won't create/resolve the InstantMessagingCall if nobody intends to use it.