monodevelop

Unity 2 Setting up the Chain of Responsability pattern and using a configuration file with Mono (monodevelop)


Unity 2 Setting up the Chain of Responsability pattern and using a configuration file with Mono (monodevelop)

The Chain of Responsibility pattern helps to accomplish two main goals when developing software. It keeps very specific
functionality into separate modules, and by using unity we can decide easily plug and unplug functionality.

If you haven’t heard about Chain of Responsibility pattern see http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern, on the other hand, if you haven’t heard about Microsoft Unity 2 Block (an IoC or dependency injection framework, please check http://unity.codeplex.com/.

Now, lets get started with a simple sample.

1. Get Microsoft Unity 2 Block
I’m going to use mono just to show that it’s possible to use Unity on Mono ;-). So, first of all download Unity Source code from codeplex site at http://unity.codeplex.com/SourceControl/list/changesets# . Once you download the source code, you can remove tests and the compile the project. it should compile properly. (BTW I’m using Mono 2.4)

2. In our sample, the application uses repositories, to get and store user data. Our sample has create a project per layer, and these projects communicate by implementing the interfaces (contracts) from the Infrastructure project. Lets see some notes about each layer.

  • “Data” project will retrieve real data from the data base.
  • “Dummy” project will produce dummy data.
  • “Cache” project will perform cache tasks, and then delegate the data retrival tasks to a given sucessor.
  • “Logging” project will perform logging tasks, and then delegate the data retrival to a give successor.
  • “Infrastructure” project will define the interface that is required for the UserRepository. So all projects knows what is the expected input and output for the UserRepository. Additionally it has been define a ISuccessor interface in order to identify layers that require a successor (for example Logging, Cache).

For the sake of the sample, the IUserRepository defines only one operation GetUserFullName. In this opertion, each implementation will add a text indicating that it has been performed a call to each given layer. By using unity 2 we will be able to indicate which levels will be loaded and executed through a configuration file.

using System;
namespace ChainOfResponsability.Infrastructure.Repository
{
	public interface IUserRepository
	{
		string GetUserFullName(int id);
	}
}

This code is sample of the contract that each different layer is going to implement if they want to be part of the chain for IUserRepository.
Additionally, ISuccessor is defined as following:

using System;
namespace ChainOfResponsability.Infrastructure
{
	public interface ISuccessor<T>
	{
		T Successor {get;}
	}
}

This generic interface allows to indicate a successor to perform the next call in the chain.

3. The “Logging” and “Cache” projects will implement IUserRepository and ISuccessor interfaces, and additionally they will require the successor as parameter of the constructor in order to delegate the task itself. Because of Unity 2 can only resolve one (anonymous) mapping for a given type (always into the same container). My colleague Marvin (aka Murven ) suggested a workaround. Basically, each layer which implements ISuccessor will receive in its constructor the IUnityContainer which will resolve the contract, but instead of using the given container, it will use the parent to resolve the type. So, it could get a different resolution for the same given type.

using System;
using ChainOfResponsability.Infrastructure.Repository;
using ChainOfResponsability.Infrastructure;
using ContainerExtensions = Microsoft.Practices.Unity.UnityContainerExtensions;
using Microsoft.Practices.Unity;
namespace ChainOfResponsability.Logging.Repository
{
	public class LoggingUserRespository : IUserRepository, ISuccessor<IUserRepository>
	{
		public LoggingUserRespository (IUnityContainer container)
		{
			this.Successor = ContainerExtensions.Resolve<IUserRepository> (container.Parent);
		}

		#region IUserRepository implementation
		public string GetUserFullName (int id)
		{
			return string.Format ("{0}->{1}", this.GetType ().Name, this.Successor.GetUserFullName (id));
		}
		#endregion

		#region ISuccessor[IUserRepository] implementation
		public IUserRepository Successor { get; set; }
		#endregion

	}
}
using System;
using ChainOfResponsability.Infrastructure;
using ChainOfResponsability.Infrastructure.Repository;
using Microsoft.Practices.Unity;
using ContainerExtensions = Microsoft.Practices.Unity.UnityContainerExtensions;
namespace ChainOfResponsability.Cache.Repository
{
	public class CacheUserRepository : IUserRepository, ISuccessor<IUserRepository>
	{
		public CacheUserRepository (IUnityContainer container)
		{
			this.Successor = ContainerExtensions.Resolve<IUserRepository> (container.Parent);
		}

		#region IUserRepository implementation
		public string GetUserFullName (int id)
		{
			return string.Format ("{0}->{1}", this.GetType ().Name, this.Successor.GetUserFullName (id));
		}
		#endregion

		#region ISuccessor[IUserRepository] implementation
		public IUserRepository Successor { get; set; }
		#endregion
	}
}

Even though both files owns a similar structure, each file can add a very specific functionality (caching or logging) in the previous example, and the invoke the proper successor.

4. The “Data” and “Dummy” projects will implement IUserRepository only and they will implement the task itself.

using System;
using ChainOfResponsability.Infrastructure;
using ChainOfResponsability.Infrastructure.Repository;
namespace ChainOfResponsability.Dummy.Repository
{
	public class DummyUserRepository : IUserRepository
	{
		public DummyUserRepository ()
		{
		}

		#region IUserRepository implementation
		public string GetUserFullName (int id)
		{
			return string.Format ("{0}[{1}]", this.GetType ().Name, id);
		}
		#endregion
	}
}
using System;
using ChainOfResponsability.Infrastructure;
using ChainOfResponsability.Infrastructure.Repository;
namespace ChainOfResponsability.Data.Repository
{
	public class DataUserRepository : IUserRepository
	{
		public DataUserRepository ()
		{
		}

		#region IUserRepository implementation
		public string GetUserFullName (int id)
		{
			return string.Format ("{0}[{1}]", this.GetType ().Name, id);
		}
		#endregion
	}
}

In the case of “Data” and “Dummy” layers, they don’t need a successor so they can perform the task itself and return the proper result.

6. There is an additional step, which is to load all the containers from the configuration file. Basically it’s done by looping through all the containers and asking for a new child on each iteration. So, we can create a sort of chain of containers where each one owns a different type resolution for the save given type. I’ve created an small utility which load the different containers and create a chain (container and parents).

        public static IUnityContainer container;
	private static void UnityBootStrap()
        {
            container = new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            #region Mappings based on the configuration file
            IUnityContainer currentContainer = container;
            foreach (var containerSection in section.Containers)
            {
                var nestedContainer = currentContainer.CreateChildContainer();
                Microsoft.Practices.Unity.Configuration.UnityContainerExtensions.LoadConfiguration(nestedContainer, section, containerSection.Name);
                currentContainer = nestedContainer;
            }
            container = currentContainer;
            #endregion
        }

This code loads the configuration file of Unity, and creates a containers which has a parent, and its parent has a different parent and so on. In this way we can create a chain with different mappings to the same IUserRepository contract. Additionally the following configuration file has been defined:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  	<!-- Defines some aliast to easily manipulate the mappings -->
    <alias alias="IUserRepository" type="ChainOfResponsability.Infrastructure.Repository.IUserRepository, ChainOfResponsability.Infrastructure" />
    <alias alias="DataUserRepository" type="ChainOfResponsability.Data.Repository.DataUserRepository, ChainOfResponsability.Data" />
    <alias alias="DummyUserRepository" type="ChainOfResponsability.Dummy.Repository.DummyUserRepository, ChainOfResponsability.Dummy" />
    <alias alias="CacheUserRepository" type="ChainOfResponsability.Cache.Repository.CacheUserRepository, ChainOfResponsability.Cache" />
    <alias alias="LoggingUserRespository" type="ChainOfResponsability.Logging.Repository.LoggingUserRespository, ChainOfResponsability.Logging" />

    <!-- Default Container when creating the tree-chain of resolution-->
    <container>
    </container>
    <!-- lowest level of the resolution chain -->
    <container name="DummyContainer">
      <register type="IUserRepository" mapTo="DummyUserRepository">
        <lifetime type="ContainerControlledLifetimeManager" />
      </register>
    </container>
    <container name="DataContainer">
      <register type="IUserRepository" mapTo="DataUserRepository">
        <lifetime type="ContainerControlledLifetimeManager" />
      </register>
    </container>
    <!-- Middle tiers. They can be added as many as needed, while they implement the proper interface -->
    <!-- Concrete implementations are chained because they're properly implementing ISuccessor interface -->
    <container name="CacheContainer">
      <register type="IUserRepository" mapTo="CacheUserRepository">
        <lifetime type="ContainerControlledLifetimeManager" />
      </register>
    </container>
    <!-- Chain of excution starts here! -->
    <container name="LoggingContainer">
      <register type="IUserRepository" mapTo="LoggingUserRespository">
        <lifetime type="ContainerControlledLifetimeManager" />
      </register>
    </container>
  </unity>
</configuration>

7. Because of we only have a common reference between projects (technically all projects are referencing “Infrastructure”, and some projects are referencing Unity. The final project does not need to reference all the implementations, but we have to copy the DLLs of each layer before running the application. If not, we will receive a message like:
The type name or alias …. could not be resolved. Please check your configuration file and verify this type name.” Assuming that you’ve written correctly all the types and DLLs names, then this error appears because the application couldn’t find the DLLs required to load the specified type. So, remember to copy the DLLs when running the application.

		public static void Main (string[] args)
		{
			UnityBootStrap();
			//var userRepository = Microsoft.Practices.Unity.UnityContainerExtensions.Resolve<IUserRepository>(container);
			var userRepository =  ContainerExtensions.Resolve<IUserRepository>(container);
			Console.WriteLine ("Call Stack of Layers when invoking GetUserFullName(0):\n {0} ", userRepository.GetUserFullName(0));
		}

At last but not least you can modify the configuration file to dynamically chance the layers that will be executed without changing your code. For example our first call will produce”

Calling our Sample with the Data Layer

And we can replace the “Data” layer with the “Dummy” layer just by commenting the “Data” layer definition into the configuration file.

Calling with Dummy Layer

Certainly this could open the door to more complex tasks and scenarios. The full source code of this sample has been hosted in GitHub at
https://github.com/hmadrigal/playground-dotnet/tree/master/MsUnity.ChainOfResponsability

Best regards,
Herber