Disclaimer:
Notice that code shown here is quite new and is subject to change. If you’re reading this and it’s 2010 it’s likely that the code now is slightly different. I may come back and revisit the post if there are any changes, but don’t hold my word on it.
Pulling from the container
General rule of thumb when using IoC containers is – when you’re referencing your container in your components (anywhere outside of your bootstrapping code) you’re doing it wrong. As with all rules there are exceptions, but they are rare. Still, there are cases where you have to pull from the container somehow. What to do then? Let’s use the following artificial example:
public class MessageDispatcher
{
public void Dispatch(IMessage message)
{
var handler = GetHandlerFor(message);
handler.Handle(message);
Destroy(handler);
}
private IMessageHandler GetHandlerFor(IMessage message)
{
// how to implement this...
}
private void Destroy(IMessageHandler handler)
{
// ... and this?
}
}
Solution – take one – the ugly
The easiest option to implement is just to take dependency on the container.
private IKernel container;
private IMessageHandler GetHandlerFor(IMessage message)
{
return container.Resolve<IMessageHandler>(new { name = message.Name });
}
private void Destroy(IMessageHandler handler)
{
container.ReleaseComponent(handler);
}
This option seems the easiest at first. You just call the container directly. However along the way you coupled your component to the container which has whole list of disadvantages and is the wrong thing™ to do.
Solution – take two – the bad
Ok, so if calling the container directly is bad, we can use a layer of abstraction on top of it, right? Like Common Service Locator for example… This way we can swap the container underneath which proves the component has no dependency on the container.
Well, this is certainly a step in the right direction, but it still has a whole range of flaws. First of all – it won’t work in our scenario. Take a closer look at the code above – when we’re resolving the message handler, we’re also passing an argument in. CSL does not support passing parameters. Besides, using CSL just hides the problem instead of solving it – you’re still having a dependency on an infrastructure library in your domain component.
Solution – take three – the good
The least worst way of solving this problem is to introduce dedicated factory which will hide the container from your domain. Doing this manually (provided you want to do it right™) is however a lot of tedious boring work. You have to define an interface for your factory in your domain assembly, then create an implementation in another one, then actually implement all the calls (and not only to resolve, don’t forget about cleaning up after yourself), which as you’ll soon discover is a lot of repetitious code.
public class MessageDispatcher
{
public void Dispatch(IMessage message)
{
var handler = GetHandlerFor(message);
handler.Handle(message);
Destroy(handler);
}
private void Destroy(IMessageHandler handler)
{
factory.DestroyHandler(handler);
}
private IMessageHandlerFactory factory;
private IMessageHandler GetHandlerFor(IMessage message)
{
return factory.CreateNewHandler(message.Name);
}
}
public interface IMessageHandlerFactory
{
IMessageHandler CreateNewHandler(string name);
void DestroyHandler(IMessageHandler handler);
}
// in another assembly
public class MessageHandlerFactory : IMessageHandlerFactory
{
private IKernel container;
public IMessageHandler CreateNewHandler(string name)
{
return container.Resolve<IMessageHandler>(new { name =name });
}
public void DestroyHandler(IMessageHandler handler)
{
container.ReleaseComponent(handler);
}
}
Wouldn’t it be good if someone else could do the work for you? – Meet Typed Factory Facility.
Windsor Typed Factory Facility
Typed factory is just the tool for this problem – it’s an automatically created factory, created by container, but your code is unaware of the container. It’s been around since 2005 but due to severe limitations imposed on it, and lack of development in recent years it hasn’t been widely used.
However it’s been recently retuned, with new capabilities and old limitations have been removed. It’s considerably more usable now, hence the word reborn in the title on this post. Let’s get to the code, shall we?
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
// register the handler and all the other components
Component.For<MessageDispatcher>(), // register the component with dependency on our factory
Component.For<IMessageHandlerFactory>().AsFactory() //register the factory itself (just the interface)!
); // that's it, now get the dispatcher
var dispatcher = container.Resolve<MessageDispatcher>();
//start dispatching...
we register the facility with the container, than we register all the components the usual way. When we want to use an interface as a factory, we register it without any implementation (if you pass an implementation it will be ignored) and then call the AsFactory() extension method, and we’re all set.
Now the kernel will implement the factory for you based on few conventions
- all the void methods are assumed to be used to release components passed as arguments
- all the non-void methods are assumed to be used to resolve components from the container
- If the factory implements IDisposable, the call to dispose will release all the transient components that were resolved via the factory.
Now, how does the factory know which service to request from the container? By default:
- Method’s return type is used to request the component by type
- If the method on the factory interface is called GetSOMETHING, the component called SOMETHING will be requested by name
- All the arguments passed to the method, will be forwarded to the container with names of the method’s parameters.
This however, is just the default behavior – you can easily change it, by implementing ITypedFactoryComponentSelector and registering it with the container. Then your implementation will be picked, and used to bind factory methods and their arguments to information used by the resolve appropriate components.
Custom ITypedFactoryComponentSelector – example
For example, let’s say you don’t like the GetSOMETHING convention, and decided that if the first argument of typed factory method is a string, it should be bound to component’s name instead.
public class MySelector: ITypedFactoryComponentSelector
{
public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments)
{
string componentName = null;
if(arguments.Length>0 && arguments[0] is string)
{
componentName = arguments[0].ToString();
}
//let's ignore all other arguments here for simplicity sake
return new TypedFactoryComponent(componentName, method.ReturnType, null);
}
}
Little bonus
One thing about this facility that blew my mind, is that the factory is not limited to resolving a single type – with literally no effort you can use it to build a generic service locator.
public interface IGenericFactory
{
T Create<T>();
}
var factory = container.Resolve<IGenericFactory>();
var one = factory.Create<ISomeComponent>();
var two = factory.Create<IOtherComponent>();
The code is in the trunk. It may still contain bugs and not support all scenarios, so approach with caution, and as always – any feedback is appreciated.