Inversion of Control with NET Framework.

Today I want to break-out my series of posts about WPF to talk about an interesting design pattern. The Inversion of Control or Dependency Injection. You can find a clear definition at this address: Martin Fowler.

What is it the Dependency Injection?

The dependency injection is a way to inject some information and configuration inside an object, from another one. In this way we keep our object abstract and recyclable.

image

As you can see in this example, we have two concrete tasks, and each one has an execute command that is exposed by the interface IBaseTask. This will be our bridge from the interface and the concrete implementation.

Manually Dependency Injection.

Now, if we would like to run our example, manually, we should write something like this code:

  1: IBaseTask firstTask = new RunTask();
  2: firstTask.Execute();
  3: IBaseTask secondTask = new WalkTask();
  4: secondTask.Execute();

And the code in each task should be something like that:

  1: public class WalkTask : IBaseTask {
  2:     #region IBaseTask Members
  3: 
  4:     public string TaskName {
  5:         get;
  6:         set;
  7:     }
  8: 
  9:     public void Execute() {
 10:         Console.WriteLine("I am a Walk task");
 11:     }
 12: 
 13:     #endregion
 14: }
 15: 

Microsoft Unity for Dependency Injection.

Microsoft Unity is an open source project done by the Microsoft patterns and practice. It can be downloaded here: http://unity.codeplex.com/ and the actual version is the 1.2 present also in the enterprise library 4.1

After you install it, you will have a folder with some .dlls that you have to reference into your solution.

image

Now let’s go back to our project and let’s change the code in order to have Unity and not a concrete implementation of our interface.

  1: //Unity container
  2: IUnityContainer container = new UnityContainer();
  3: //Type association
  4: container.RegisterType<IBaseTask, WalkTask>();
  5: IBaseTask firstTask = container.Resolve<IBaseTask>();
  6: firstTask.Execute();
  7: 

This is the first step, but as you can notice, it’s not so far from a concrete implementation. I mean, in this way we still have to procedural declare the type we want to convert to our interface.

The next step will be to remove the type association and use a configuration file. First of all we need to declare in our app.config file the unity section:

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

Then we need to associate some type to our container. This is easy.

  1:   <Unity>
  2:     <typeAliases>
  3:       <!-- Lifetime manager types -->
  4:       <typeAlias alias="singleton"
  5:            type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,
  6:                Microsoft.Practices.Unity" />
  7:       <typeAlias alias="external"
  8:            type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,
  9:                Microsoft.Practices.Unity" />
 10:       <!-- Custom types -->
 11:       <typeAlias alias="myInterface" type="InversionOfControl.Model.IBaseTask, InversionOfControl" />
 12:     </typeAliases>

As you can see at the end, we are going to declare our IBaseTask interface. Remember always to declare the complete path otherwise Unity will search the class into the Unity namespace!!

Now let’s build a couple of custom map inside the XML file:

  1:     <containers>
  2:       <container name="firstContainer">
  3:         <types>
  4:           <type type="myInterface" mapTo="InversionOfControl.Model.RunTask, InversionOfControl" name="RunMapping" />
  5:           <type type="myInterface" mapTo="InversionOfControl.Model.WalkTask, InversionOfControl" name="WalkMapping" />
  6:         </types>
  7:       </container>
  8:     </containers>
  9:   </Unity>
 10: </configuration>

As you can see, we are using our Alias to declare the interface and then we are giving a custom name the our mapping. Now we can go back to our code and do some fancy operations.

Declare the configuration section and initialize the container:

  1: IUnityContainer container = new UnityContainer();
  2: UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("Unity");
  3: section.Containers["firstContainer"].Configure(container);
  4: 

Then let’s Inject a couple of objects inside our interface:

  1: IBaseTask firstTask = 
  2:    container.Resolve<IBaseTask>("RunMapping");
  3: firstTask.Execute();
  4: IBaseTask secondTask = 
  5:    container.Resolve<IBaseTask>("WalkMapping");
  6: secondTask.Execute();

Very easy right? In our example we are going to write in a procedural way which mapping we want to use, but of course this information should be retrieved at run-time from a Database or a serialized object.

Inject property and change values at run-time.

Until now our objects were exposing an execute method that was simply printing some fixed text in the console. But we have a name property so we should change the execute method with something like that:

  1: public void Execute() {
  2:     Console.WriteLine
  3:       ("I am a Run task. My name is: {0}",
  4:       TaskName);
  5: }
  6: 

Now we have two ways to initialize the TaskName property value without using a procedural code inside the program. First of all we have to say that the TaskName property of each concrete implementation has a dependency:

  1: [Dependency()]
  2: public string TaskName {
  3:    get;set;
  4: }

And now we can change the configuration in this way:

  1: <type type="myInterface" mapTo="InversionOfControl.Model.WalkTask, InversionOfControl" name="WalkMapping" >
  2:   <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,
  3:                      Microsoft.Practices.Unity.Configuration">
  4:     <property name="TaskName"  propertyType="System.String">
  5:       <value value="SecondTask"/>
  6:     </property>
  7:   </typeConfig>
  8: </type>
  9: 

We are assigning for the mapping called WalkMapping a value of “SecondTask” for the property TaskName. This solution is fine but it’s still fixed. I mean, and if I would like to change the value at run-time and I cannot access the serialization of my object?

Here is coming the second solution:

  1: container.Configure<InjectedMembers>()
  2:    .ConfigureInjectionFor<RunTask>(
  3:    //.ConfigureInjectionFor<IBaseTask>(
  4:    //.ConfigureInjectionFor<WalkTask>(
  5:       new InjectionProperty("TaskName", "12345"));

I put a couple of comments to show you what you can configure.

I hope this short article will be useful to evaluate this amazing IoC framework.

You can find the complete solution here, in my sky drive

Tags: