Windsor, Decorators and Chains of Responsabilityes, Oh YEAH!

time to read 4 min | 653 words

A few days ago I made a small change to Windsor, the change was basically stopping Windsor from trying to resolve a dependency using a dependency that it is already resolving. Now, this is prettry hard to explain without a good example, so consider this one:

image

Let us say that we have the standard Chain Of Responsability here, each finder will check its store for an item that matches the specification, and would call the next one in the chain if it can't. Now, previously you had to instruct Windsor explicitly about who was the next in the chain, something like this:

<components>
	<component id="cache_finder" service="IResultFinder`1"
		type="CacheResultFinder`1">
		<parameters>
			<finder>${db_finder}</finder>
		</parameters>
	</component>
	<component id="db_finder" service="IResultFinder`1"
		type="DatabaseResultFinder`1">
		<parameters>
			<finder>${ws_finder}</finder>
		</parameters>
	</component>
	<component id="ws_finder" service="IResultFinder`1"
		type="WebServiceResultFinder`1">
		<parameters>
			<finder>${failed_finder}</finder>
		</parameters>
	</component>
	<component id="failed_finder" service="IResultFinder`1"
		type="FailedResultFinder`1"/>
</components>

That is quite a bit of XML, and while it works, it make it awkward to understand what is going on in complex scenarios. The main issue here was that Windsor looked at CacheResultFinder<T>, saw that it accepted IResultFinder<T> and that it had a valid component that had this service (CacheResultFinder<T>) and promptly threw a dependency cycle exception. As a direct result of that, we had to manually override Windsor's selection, and also had to have a FailedResultFinder<T>, which must go on the end of the chain, again, because otherwise Windsor would try to resolve the ctor(IResultFinder<T> finder) constructor.

This is a workable solution, but I feel that this is telling the container way too much, why isn't it smart enough to figure it out? The problem with saying it about OSS software is that I can't really rant about it, since the answer is usually "we accept patches", bummer. So, I went ahead and implement this feature in Windsor, where it will not try to resolve what is currently being resolve. The end result is that for the scenario above we can give up on FailedResultFinder<T> and write just this:

  <components>
    <component id="cache_finder" service="IResultFinder`1"
      type="CacheResultFinder`1"/>
    <component id="db_finder" service="IResultFinder`1"
      type="DatabaseResultFinder`1"/>
    <component id="ws_finder" service="IResultFinder`1"
      type="WebServiceResultFinder`1"/>
  </components>

We put the responsability for putting the chain of responsability together in the hand of the container, and it will build the system using simple first come fist on the chain approach, until it runs out of components that can satisfy the requirement, in which case it will use the default constructor.

Now this is much better, no?