воскресенье, 12 сентября 2010 г.

Good news, everyone! I've discovered a way to enhance a brilliant DI-container Castle Windsor with not so brilliant feature as BuildUp.

Saying that it is not that brilliant I mean that this feature is a beast, actually. It is an open door to violate DI principles, and there are more elegant ways to overcome a problem of having to resolve an external object through DI-container. After all, if Castle team considered this feature useful, they would roll it out long time ago, have no doubt!However, in my case it is a matter of time, to have an opportunity of resolving existing object's dependencies through DI-container, built as fast as possible. That is why I turned to BuildUp feature that some other DI-frameworks have.

BuildUp functionality is closed up under ComponentActivator. Activators are called when LifetimeManager considers that a new object has to be created. And that logically brings us to restriction of this solution - it won't work with Singleton lifestyle. But it shouldn't actually! When you mark an object as a singleton - you effectively state that a container is going to be an owner of that object, thus it won't ever be built externally.

BuildUpComponentActivator extends DefaultComponentActivator and overrides a single method - Instantiate. This guy is a cheater, as you might guess, it never creates an object, but simply read it from context. All the dirty job of deriving dependencies is done by a parent class.Should BuildUpComponentActivator fail to find an object in context, it will simply delegate all work to parent, and a new object will be created. This is done to support resolving objects of the same type managed by container.

Context is a dictionary, created with BuildUp extension method:

In order to be able to build up an object, one have to modify it's registration and override ComponentActivator setting. CanBeBuiltUp is a neat extension method wrapping this call for Windsor fluent registration API.

There is only one shortcoming with this solution I came with - it doesn't provide you with any facilities to release this external object's dependencies. It has to be done manually somewhere.