Click here to Skip to main content
Click here to Skip to main content

Separating layers and components with constructor injection and Unity

By , 6 Nov 2009
Rate this:
Please Sign up or sign in to vote.

Ok, so how did I come to using Unity and constructor injection?

Anyways... what is Unity? And what is constructor injection?

Unity is a "dependency injection container", (see http://www.codeplex.com/unity/ for details) in other words, it is a library that implements mechanisms to easily apply the dependency injection pattern.

Dependency injection is a design pattern that aims at separating concerns, like separating from the application specific domain all the other concerns that are not strictly "about" the topic of the application (usually are more low level).

For example in a mp3 player app, connecting to the db to save personal info about the songs is not something that affects software functionality. If the db app changes or we decide that the info is going to be stored to a remote server through a web service, the functionality will still be there and the app will continue to work. It would be different if we wanted our app to be able to play iTunes audio books. That would be a change that affects the domain of the app.

So it's a valuable thing if we can separate those facets of the application from the "real" functionalities. This separation enables us to think more clearly and in a clean way about our application and not mix different concerns. Also we can unit test better and apply test driven development.

Let's see a sample app. What about the dear old "Hello world" functionality?! This app is about... saying hello... to you.. Smile | :)

By the way this time we are going to log who we are saying hello to. How and where we are going to store this info is not really relevant to the app. We just want to able to call a method like Log(message), in the HelloWorld method of our class (MainClass, forgive the ugly name..):

   public class MainClass
   {
       ILogger logger;

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

       public string HelloWorld(string name)
       {
           string helloMessage = "Hello " + name + "!";
           this.logger.Log("Said hello to " + name + "!");
           return helloMessage;
       }
   }

HelloWorld calls the Log method of an object implementing the ILogger interface. This way, our application is not dependent upon a specific logger implementation, hence the inversion of dependency, the main application doesn't depend on the logger, it's the logger that depends upon the ILogger interface defined by the app.

Here's a quick look at how the Visual Studio solution looks like:

It's very simple, we have a UnitySampleUse project, a MyLogger project and the test project UnitySampleUse.Test.

UnitySampleUse contains the ILogger interface. MyLogger contains MyLoggerClass that implements ILogger, so MyLogger contains a reference to UnitySampleUse. If we were going to instantiate a MyLoggerClass object inside UnitySampleUse we would have to reference and we don't want to make our app dependant upon MyLogger (plus we would have circular reference).

So who's going to glue things together and pass an ILogger object to UnitySampleUse?
Guess what... Unity!

The client of our code, in this case the test project (it could be a UI project or another library), uses Unity to instantiate ILogger, automagically composing our MainClass, passing in the constructor the concrete object implementing ILogger.
The mapping of the interface to the class implementing it can be stored in the XML config file (app.config), that, in our case, will look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.
	UnityConfigurationSection,Microsoft.Practices.Unity.Configuration, 
	Version=1.2.0.0,Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  </configSections>

  <unity>
    <typeAliases>
      <!--<span class="code-comment"> Lifetime manager types should be inserted if you need lifetime managers --></span>
      <typeAlias alias="singleton" type="Microsoft.Practices.Unity.
	ContainerControlledLifetimeManager,Microsoft.Practices.Unity"/>
      <typeAlias alias="external" type="Microsoft.Practices.Unity.
	ExternallyControlledLifetimeManager,Microsoft.Practices.Unity"/>
      <!--<span class="code-comment"> User defined type aliases --></span>
      <typeAlias alias="ILogger" type="UnitySampleUse.ILogger,UnitySampleUse"/>
    </typeAliases>
    <containers>
      <container>
        <types>
          <type type="ILogger" mapTo="MyLogger.MyLoggerClass, MyLogger">
          </type>
        </types>
      </container>
    </containers>
  </unity>

</configuration>

The test will need to instantiate the MainClass using Unity:

UnityContainer container = new UnityContainer();
UnityConfigurationSection section =
        (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

section.Containers.Default.Configure(container);

MainClass mainClass= container.Resolve<MainClass>(); 

Unity will take care of calling the constructor MainClass(ILogger logger), injecting a MyLoggerClass object. Thus the type of dependency injection applied is constructor injection.

UnitySampleUse project can be compiled without having the source code of the logger and the client code (the unit test, or the UI, etc.) can switch logger implementation without change in the code by just referencing the new logger and updating the config file.

This way we can separate layers, for example our data access layer, very easily and at the same time keep all our application logic in one project.

Separating layers and building by components has never been easier.

This post is published on .

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Software architect. At present working on C# development, with mainly Asp.net Ajax and MVC user inteface. Particularly interested in OOP, test driven, agile development.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 6 Nov 2009
Article Copyright 2009 by Giorgio Bozio
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid