This has been a bad month for blogging. Intense work and weekend personal affairs kept me away from the .NET Brainwork blog admin console. But I'll try to change things from now on, and keep my monthly post rate above 5. I've thought about writing a small introduction on Unity, from the Enterprise Library framework.

 

- Help keep this blog alive -

 

Unity is an Inversion of Control ( IoC ) Container and Dependency Injection Tool from Microsoft Patterns & Practices that uses ObjectBuilder 2.0 as its dependency injection engine. You are probably thinking: "What the hell does Inversion of Control mean!?" or "What's Dependency Injection?". Well a Dependency Injection container is a fabulous tool that allows you to write decoupled software, making it transparently adapt to new interface scenarios. What this means is, your application will now be able to work with decoupled functional modules by implementing an interface-driven architecture. "How does this work?" - you say. Well in Unity you can register an external assembly class to be used by your aplication, by associating it with the application required interfaces. It stores registrations and mappings between types and can instantiate the appropriate concrete types on demand.  Let's take a logging component as an example. In this example we wish to develop an application that can support different logging platforms. we could define the unity section in our web.config or app.config like this:

 

 

   1:  <unity>
   2:          <typeAliases>
   3:              <!-- Lifetime manager types -->
   4:              <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,              Microsoft.Practices.Unity"/>
   5:              <typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,              Microsoft.Practices.Unity"/>
   6:              <!-- Custom object types -->
   7:              <typeAlias alias="IMyInterface" type="MyObjects.IMyInterface, MyObjects"/>
   8:              <typeAlias alias="MyRealObject" type="MyObjects.MyRealObject, MyObjects"/>
   9:              <typeAlias alias="MyOtherObject" type="MyObjects.MyOtherObject, MyObjects"/>
  10:              <typeAlias alias="ILogger" type="MyObjects.ILogger, MyObjects"/>
  11:              <typeAlias alias="MyLogger" type="MyObjects.MyLogger, MyObjects"/>
  12:              <typeAlias alias="MyFastLogger" type="MyObjects.MyFastLogger, MyObjects"/>
  13:          </typeAliases>
  14:          <containers>
  15:              <container name="containerOne">
  16:                  <types>
  17:                      <!-- Default (un-named) mapping for IMyInterface to MyRealObject-->
  18:                      <type type="IMyInterface" mapTo="MyRealObject"/>
  19:                      <!-- Default (un-named) mapping for ILogger to MyLogger -->
  20:                      <type type="ILogger" mapTo="MyFastLogger">
  21:                          <lifetime type="singleton"/>
  22:                      </type>
  23:                      <!-- Named mapping for ILogger to StandardLogger-->
  24:                      <type type="ILogger" mapTo="MyLogger" name="StandardLogger">
  25:                          <lifetime type="singleton"/>
  26:                      </type>
  27:                      <!-- Named mapping for ILogger to SuperFastLogger-->
  28:                      <type type="ILogger" mapTo="MyFastLogger" name="SuperFastLogger">
  29:                          <lifetime type="external"/>
  30:                      </type>
  31:                  </types>
  32:              </container>
  33:          </containers>
  34:      </unity>

 

This example does this by configuration. You can also do this by code, although I find this more interesting to look at for this article. So this is where the magic makes sense. All registered types are kept in one or more containers, although in this example we're using only one. I've called it "containerOne". At runtime, this container is loaded (in an ASP.NET application, this is usually done in global.asax, in the application start event) and underlying/registered types will be made available to the engine. Notice line number 7: what this line does is say that the class MyFastLogger will be implementing the ILogger interface. Every time your application instantiates ILogger, it will be instantiating the MyFastLogger type in the background. Nice huh? If you want to use a different logging assembly for this, just register it and that's it. The lifetime nodes are there because Unity container manages the creation and resolution of objects based on a lifetime you specify when you register the type of an existing object, or on the default lifetime if you do not specify a lifetime manager for it to use. The Unity Application Block includes the two lifetime managers specified above, ContainerControlledLifetimeManager and ExternallyControlledLifetimeManager, but you can create your own with your specific behaviour.

 

The container types are initialized internally like this:

 

 

   1:  UnityContainer myContainer = new UnityContainer();
   2:  UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
   3:  section.Containers["containerOne"].Configure(myContainer);
   4:  Application["MyContainer"] = myContainer;

 

 

And in our application, it all comes down to this:

 

 

   1:  ILogger myExampleInstance = myContainer.Resolve<ILogger>(loggerType);
   2:  string output = myExampleInstance.MyInterfaceMethod("Unity rocks!");

 

 

My logging object will be internally instantiated with my registered class, and the interface member is used. So here it is, a quick example, for a quick start.So if you're into design patterns, download Enterprise Library 4, complement this article with this MSDN walkthrough and happy coding!

 

 

Technoratti Tags: ,