Chain of Responsibility pattern using Unity

Nov 14, 2008 at 2:31 AM
Edited Nov 14, 2008 at 4:34 AM

I was wondering if it is possible to get Unity to build a Chain of Responsibility object graph.  It would be preferrable to specify the chain in config.

ie 
Container.Resolve<IHandler>()  returns FirstHandler with Seccessor = instance of SecondHandler and so on.

 public interface IHandler
 {
  IHandler Successor { get; set; }
  bool HandleRequest( RequestObject request );
 }

 public class RequestObject
 {
 }

 public class FirstHandler : IHandler
 {
  public IHandler Successor { get; set; }

  bool IHandler.HandleRequest( RequestObject request )
  {
   if ( !CanHandleRequest && this.Successor != null )
    return this.Successor.HandleRequest( request );
   return true;
  }
 }

 public class SecondHandler : IHandler
 {
  public IHandler Successor { get; set; }

  bool IHandler.HandleRequest( RequestObject request )
  {
   if ( !CanHandleRequest && this.Successor != null )
    return this.Successor.HandleRequest( request );
   return true;
  }
 }

 public class ThirdHandler : IHandler
 {
  public IHandler Successor { get; set; }

  bool IHandler.HandleRequest( RequestObject request )
  {
   if ( !CanHandleRequest && this.Successor != null )
    return this.Successor.HandleRequest( request );
   return true;
  }
 }


If you be even better it I could use a Generic interface instead, but I keep getting
"System.InvalidOperationException: The current type, IHandler`1[IRequestObject] , is an interface and cannot be constructed. Are you missing a type mapping?"

ie
public interface IHandler<T>
{
  IHandler<T> Successor { get; set; }
  bool HandleRequest( T request );
}

Nov 14, 2008 at 8:45 AM
Yes, it's absolutely supported, with generic interfaces. I'll give an example with the API and leave config as the dreaded "exercise for the reader".

Basically, you use a combination of type mapping and named registrations. I'll assume you have generic versions of FirstHandler, SecondHandler, etc.

You start with your default handler:

container.RegisterType(typeof(IHandler<>), typeof(FirstHandler<>),
    new InjectionProperty("Successor", new ResolvedParameter(typeof(IHandler<>), "second");

What this is saying is: when resolving the unnamed instance of IHandler<whatever>, fulfill it by instantating FirstHandler<whatever>. Also, when building up the object, set the Successor property by resolving through the container IHandler<whatever>, "second".

Next, you define the mapping for "second":

container.RegisterType(typeof(IHandler<>), typeof(SecondHandler<>), "second",
    new InjectionProperty("Successor", new ResolvedParameter(typeof(IHandler<>), "third");

Note the difference is that we supply a name for the registration this time: "second".

Next we define the mapping for "third":

container.RegisterType(typeof(IHandler<>), typeof(ThirdHandler<>), "third");

I didn't specify a value for the Successor property because you didn't give one in the original post, but I hope by now you can see where this is going.

So now, when you do:

    container.Resolve<IHandler<RequestObject>>()

It news up FirstHandler<RequestObject>(), then, to set the Successor property it does:

    container.Resolve<IHandler<RequestObject>>("second")

which news up SecondHandler<RequestObject>(), and to set THAT object's Successor property it does:

    container.Resolve<IHandler<RequestObject>>("third")

which result in an instance of ThirdHandler<RequestObject>. Which does exactly what you asked for.

Note: This only works correctly in Unity 1.2. There were several bugs around generic support in 1.1 that we fixed in the latest release.

-Chris

Nov 14, 2008 at 3:37 PM
This idea of chaining is very similar to an example I did for Generic Decorator Chains which might help:

Generic Decorator Chains Example using Unity Dependency Injection Container

Regards,

Dave
Nov 16, 2008 at 6:49 AM
Thanks Chris.

I got both the code and config versions done, but the config one took me a while.  The documention is not exactly clear when it comes to explaining configuration elements.

I would be really nice if there was a guide to config vs code and what code object relates to what config element ( ie ResolvedParameter class = DependencyElement )

For interest, here are my code and config versions, verify by unit tests as equivalent.  Does it look right to those who better understand he configuration side of things ?

 

IUnityContainer container = new UnityContainer()
  .RegisterType<
IHandler<RequestObject>, FirstHandler>(new InjectionProperty("Successor", new ResolvedParameter<IHandler<RequestObject>>("ChainHandler2")))
  .RegisterType<
IHandler<RequestObject>, SecondHandler>("ChainHandler2", new InjectionProperty("Successor", new ResolvedParameter<IHandler<RequestObject>>("ChainHandler3")))
  .RegisterType<
IHandler<RequestObject>, ThirdHandler>("ChainHandler3");



 

  <unity>
    <typeAliases>
      <typeAlias alias="IHandler" type="Unity.Test.IHandler`1, Unity.Test" />
      <typeAlias alias="FirstHandler" type="Unity.Test.FirstHandler, Unity.Test" />
      <typeAlias alias="SecondHandler" type="Unity.Test.SecondHandler, Unity.Test" />
      <typeAlias alias="ThirdHandler" type="Unity.Test.ThirdHandler, Unity.Test" />
    </typeAliases>

    <containers>
      <container name="ChainOfResponsibility">
        <types>
          <type type="IHandler" mapTo="FirstHandler">
            <typeConfig>
              <property name="Successor" propertyType="SecondHandler">
                <dependency name="ChainHandler2" />
              </property>
            </typeConfig>
          </type>
          <type type="IHandler" mapTo="SecondHandler" name="ChainHandler2">
            <typeConfig>
              <property name="Successor" propertyType="ThirdHandler">
                <dependency name="ChainHandler3" />
              </property>
            </typeConfig>
          </type>
          <type type="IHandler" mapTo="ThirdHandler" name="ChainHandler3" />
        </types>
      </container>
    </containers>
  </unity>

Jan 6, 2009 at 2:32 AM
Edited Jan 6, 2009 at 3:11 AM
I prefer this to the mechanism for Interception in Unity.