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’