Castle Windsor: order of configurations and resulting resolvings
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 f...
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 succsessor 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 succsessor 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’