Castle Windsor & Command Pattern

911 views Asked by At

I am trying to implement a Command, CommandHandler and CommandDispatcher pattern using Castle Windsor without manually asking the container to resolve a CommandHandler based on Command type (which is generally considered an anti-pattern).

I found this old article, but the implementation of ITypedFactoryComponentSelector has changed, so now it returns a Func, instead of TypedFactoryComponent.

Anyway, I would really appreciate if someone can shed some light on the "correct" implementation of this pattern. Current setup (simplified):

public interface ICommand {}
    
public class CreateUserCommand:ICommand
{
  public string Name { get;set; }
}

public interface ICommandHandler<in TCommand> where TCommand: ICommand
{
    ICommandResult Execute(TCommand command);
}

public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand>
{
    public ICommandResult Execute(CreateUserCommand command)
    {
        // some logic here
        return new CommandResult() {Success = true};
    }
}

public interface ICommandDispatcher
{
    ICommandResult Submit<TCommand>(TCommand command) where TCommand: ICommand;
}

public class CommandDispatcher : ICommandDispatcher
{
    // I DO NOT WANT TO DO THIS:
    IWindsorContainer _container;
    public CommandDispatcher(IWindsorContainer container)
    {
        _container = container;
    }

    public ICommandResult Submit<TCommand>(TCommand command) where TCommand : Commands.ICommand
    {
        // I DO NOT WANT TO DO THIS TOO:
        var handler = _container.Resolve<ICommandHandler<TCommand>>();
        if (handler == null)
        {
            throw new Exception("Command handler not found for command " + typeof(TCommand).ToString());
        }

        return handler.Execute(command);
    }
}

Basically all I want is to configure the container in a way that my WebAPI controller can have a dependency on ICommandDispatcher and simply do something like

var result = this.commandDispatcher.Submit(new CreateUserCommand("John Smith"));
if (result.Success){
  return Ok();
}

Thanks! ;)

2

There are 2 answers

0
timurso On BEST ANSWER

I finally managed to find a minimal fully functional solution by combining the Castle Windsor documentation and a few blog posts. I hope my answer will save someone a few hours.

For the base setup and missing code, please refer to my question above (I don't want to duplicate a lot of code).

Firstly we need to create an interface for our factory, but with no actual implementation (this is used by Castle Windsor to create a factory that will provide a particular implementation of your CommandHandler<T>:

public interface ICommandHandlerFactory
{
    ICommandHandler<TCommand> Resolve<TCommand>() where TCommand : ICommand;
}

Then add the following CW Installer code:

public class CommandingInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<TypedFactoryFacility>()
            .Register(
                Classes.FromThisAssembly()
                    .BasedOn(typeof (ICommandHandler<>))
                    .WithServiceAllInterfaces()
                    .LifestyleTransient(),
                Component.For<ICommandHandlerFactory>().AsFactory(),
                Component.For<ICommandDispatcher>().ImplementedBy(typeof (CommandDispatcher)));
    }
}

so the magic is in this line Component.For<ICommandHandlerFactory>().AsFactory() as it tells CW to use your interface to create a factory that you will use in your CommandDispatcher:

public class CommandDispatcher : ICommandDispatcher
{
    ICommandHandlerFactory _commandHandlerFactory;
    public CommandDispatcher(ICommandHandlerFactory commandHandlerFactory)
    {
        _commandHandlerFactory = commandHandlerFactory;
    }

    public ICommandResult Submit<TCommand>(TCommand command) where TCommand : Commands.ICommand
    {
        try
        {
            var handler = _commandHandlerFactory.Resolve<TCommand>();
            return handler.Execute(command);
        }
        catch (ComponentNotFoundException cnfex)
        {
            // log here
            throw cnfex;
        }

    }
}

HUGE GOTCHA

If you name your factory method something like GetCommandHandler, CW will try to resolve a type literally called CommandHandler and it will fail as you don't have such type. According to docs HERE CW should fall back to non-Get, type-based lookup, but it does not seem to do that and simply spits back a ComponentNotFoundException. So name your factory method ANYTHING but Get*

1
samy On

What you are describing is an interface-based typed factory, ie a factory that resolves components based on the parameters you are passing it without any implementation and without you needing to resolve the components manually. Here is an answer that details how to use the typed factory mechanism, and here is an article from kozmic.net that details it a bit more.