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! ;)
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>
:Then add the following CW Installer code:
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 yourCommandDispatcher
:HUGE GOTCHA
If you name your factory method something like
GetCommandHandler
, CW will try to resolve a type literally calledCommandHandler
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 aComponentNotFoundException
. So name your factory method ANYTHING but Get*