Castle Typed Factory Facility reborn

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.

Technorati Tags:

Comments

Bravo! I only discovered the TypedFactoryFacility a few months ago and was surprised it wasn’t in wider use.

The ‘little bonus’ is clever, but I think it removes one of the main advantages of having the typed factory in the first place…

A MessageDispatcher that depends on IMessageHandlerFactory does a good job of publishing its dependency on the ability to create IMessageHandlers. A MessageDispatcher that depends on IGenericFactory doesn’t – it could try to create literally anything – and this will make it harder to maintain and test.

The fact that IGenericFactory works out of the box like that is a testament to the quality of the internal implementation though.

I hope that now this facility is getting some love it will save the world from the evils of service locators!!! 🙂

Nicholas,

Sure you’re right about the generic factory vs IMessageHandlerFactory. Factory has one great advantage – it’s focused, and I wouldn’t use the generic solution here. The "bonus" was to show the flexibility of this approach, not to encourage creating one factory and using it all over the place, which offers little advantage over SL.

Igor Brejc says:

Krzysztof,

Couldn’t something similar be implemented for registering components, too? I have a scenario where I want to register a service when a Windows form is loaded, but I don’t want to have to reference kernel or container directly in the form. Of course, this would only be used for limited scenarios (singletons only, for example).

Or is there a better way?

@Igor,

Perhaps an ILazyComponentLoader would be a good fit…
If you’re obtaining the form from the container you could utilize OnActivate method or EventWiringFacility to plug into appropriate event of that form and do your job there with the form staying completely agnostic to the container.

It depends on details of your scenario and implementation,

Krzysztof

Igor Brejc says:

Krzystof, another question: I’ve read using.castleproject.org/…/Typed+Factory+Facility , and I’m not sure about one thing: if I create a disposable component using the factory, do I have to explicitly release it using the factory method or is calling Dispose() enough? Example: is this a proper usage:

using (IWebClient webClient = webClientFactory.CreateWebClient ())
{

}

Thanks

@Igor (sorry for delayed answer, Subtext stopped sending me notifications about new comments)

Disposing the factory is equivalent to calling Release for each component resolved through it.