Castle Windsor: order of configurations and resulting resolvings

How Castle Windsor resolves multiple implementations of the same interface and how registration order, named components, and constructor dependencies can build a Chain of Responsibility

If different implementations for the same interface are specified without named keys, then a resolving is made in order of the configurations. So the first fitting implementation is taken.

Different implementations for the same interface is a typical scenario for patterns like “chain of responsibility” and “decorator”. If you want to describe such a chain you could use the next handler as a constructor- parameter in the actual one.

Demo source code

Lets have a look at code.

Interface for one handler/processor/part from the “chain of responsibility” (cor):

public interface ICorHandler<T>
{
    void Process(T data);
    CorHandler<T> NextLink { get; set; }
}

and a “default” implementation for this interface:

public abstract class CorHandler<T> : ICorHandler<T>
{
    protected CorHandler(CorHandler<T> nextLink)
    {
        NextLink = nextLink;
    }

    public void Process(T data)
    {
        if (IsResponsible(data))
        {
            ProcessCore(data);
        }
        else
        {
            CallNextHandler(data);
        }
    }

    private void CallNextHandler(T data)
    {
        if (null != NextLink)
        {
            NextLink.Process(data);
        }
        else
        {
            ProcessEndOfChain(data);
        }
    }

    protected virtual void ProcessEndOfChain(T data)
    {
        string message = string.Format("End from chain of responsibility reached. {0}Type info='{1}'", 
                                        Environment.NewLine, MethodBase.GetCurrentMethod().DeclaringType);
        Trace.WriteLine(message);
    }

    public CorHandler<T> NextLink { get; set; }

    protected abstract bool IsResponsible(T data);

    protected abstract void ProcessCore(T data);
}

an two sample implementations which only checks the type of a given data as the filter-criteria:

public class CorHandlerOne : CorHandler<IData>
{
    public CorHandlerOne(CorHandler<IData> nextLink)
        : base(nextLink)
    {
    }

    public CorHandlerOne() : base(null)
    {
    }

    protected override bool IsResponsible(IData data)
    {
        return typeof (DemoDataOne) == data.GetType();
    }

    protected override void ProcessCore(IData data)
    {
        Console.WriteLine("This is for 'CorHandlerOne'");
    }
}

public class CorHandlerTwo : CorHandler<IData>
{
    public CorHandlerTwo() : base(null)
    {
    }

    public CorHandlerTwo(CorHandler<IData> nextLink)
        : base(nextLink)
    {
    }

    protected override bool IsResponsible(IData data)
    {
        return typeof (DemoDataTwo) == data.GetType();
    }

    protected override void ProcessCore(IData data)
    {
        Console.WriteLine("This is for 'CorHandlerTwo'");
    }
}

Configuration order and resolving effects

Now we use the castle windsor fluent configuration.

And the resolving effect is proved with the following code:

IData data = new DemoDataOne();
corHandler.Process(data);

Console.WriteLine("***");

data = new DemoDataTwo();
corHandler.Process(data);

Ascending order without resolving key

container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerOne>().Named("one").Parameters(Parameter.ForKey("nextLink").Eq("${two}")));
container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerTwo>().Named("two"));

var corHandler = container.Resolve<ICorHandler<IData>>();

We get the result:

This is for 'CorHandlerOne'
***
This is for 'CorHandlerTwo'

So the resolving is along the configuration order – CorHandlerTwo is the succsessor of CorHandlerOne.

Descending order without resolving key

container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerTwo>().Named("two"));
container.Register(Component.For<ICorHandler<IData>>().ImplementedBy<CorHandlerOne>().Named("one").Parameters(Parameter.ForKey("nextLink").Eq("${two}")));

var corHandler = container.Resolve<ICorHandler<IData>>();

We get the result:

End from chain of responsibility reached.
Type info='EsriDE.Trials.ChainOfResponsibility.CorHandler`1[T]'

***

This is for 'CorHandlerTwo'

So the resolving is along the configuration order – CorHandlerTwo is the successor of CorHandlerOne, but the “entry-point” for Castle Windsor is CorHandlerTwo because it is specified before CorHandlerOne. And so this implementation starts the filtering in the chain. However - CorHandlerTwo has no successor and so the message “End from chain of responsibility reached” is outputted.

Descending order with resolving keys

Now we introduce a key for the resolving. So we have deformed the “entry-point”.

var corHandler = container.Resolve<ICorHandler<IData>>(“one”);

We get the result like in the first sample:

This is for 'CorHandlerOne'

***

This is for 'CorHandlerTwo'