我试图使用Castle Windsor实现Command,CommandHandler和CommandDispatcher模式,而无需手动要求容器根据Command类型(通常被认为是反模式)来解析CommandHandler。

我找到了this旧文章,但是ITypedFactoryComponentSelector的实现已更改,因此现在返回的是Func,而不是TypedFactoryComponent

无论如何,如果有人可以阐明这种模式的“正确”实现,我将非常感激。
当前设置(简体):

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);
    }
}


基本上,我想要做的就是以一种使我的WebAPI控制器可以依赖ICommandDispatcher的方式配置容器,并简单地执行类似的操作

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


谢谢! ;)

最佳答案

通过结合Castle Windsor文档和一些博客文章,我终于设法找到了一个最小的全功能解决方案。希望我的回答可以节省一个人几个小时。

对于基本设置和缺少的代码,请参考上面的问题(我不想重复很多代码)。

首先,我们需要为工厂创建一个接口,但是没有实际的实现(Castle Windsor使用它来创建一个工厂,该工厂将提供您CommandHandler<T>的特定实现:

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


然后添加以下CW安装程序代码:

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)));
    }
}


因此,神奇之处在于这行Component.For<ICommandHandlerFactory>().AsFactory(),因为它告诉CW使用您的界面来创建要在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;
        }

    }
}


巨大的哥达

如果将工厂方法命名为类似GetCommandHandler的名称,则CW会尝试解析字面上称为CommandHandler的类型,并且由于您没有这种类型而将失败。根据文档HERE,CW应该回退到基于类型的非Get查找,但是它似乎并没有这样做,而只是返回ComponentNotFoundException。因此,除“获取”外,将您的工厂方法命名为“任何”

09-19 08:12