1

Я пытаюсь реализовать шаблон Command, CommandHandler и CommandDispatcher с помощью Castle Windsor без ручного запроса контейнеру разрешить CommandHandler на основе типа Command (который обычно считается анти-шаблоном).Замок Виндзор и командный шаблон

Я нашел 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(); 
} 

Спасибо! ;)

ответ

1

Наконец-то мне удалось найти минимальное полнофункциональное решение, объединив документацию Castle Windsor и несколько сообщений в блогах. Надеюсь, мой ответ спасет кого-то несколько часов.

Для базовой установки и отсутствия кода, пожалуйста, обратитесь к моему вопросу выше (я не хочу дублировать много кода).

Во-первых, нам нужно создать интерфейс для нашего завода, но без фактической реализации (это используется замок Виндзор, чтобы создать фабрику, которая будет обеспечивать конкретную реализацию Вашего CommandHandler<T>:

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

Затем добавить следующий код CW Installer:

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. Так что назовите свой заводский метод «НИЧЕГО», но Get *

0

Что вы описываете - это типизированная фабрика на основе интерфейса, то есть фабрика, которая разрешает компоненты на основе параметров, которые вы передаете без какой-либо реализации, и без необходимости вручную вручную обрабатывать компоненты. Here - это ответ, в котором подробно описывается использование типичного фабричного механизма, а here - статья от kozmic.net, которая детализирует ее немного больше.

+0

Спасибо, я уже нашел эти статьи, но, к сожалению, он все еще не работал. После нескольких часов борьбы с этим мне, наконец, удалось заставить его работать, я опубликую полный ответ ниже. Спасибо за вашу помощь! – timurso

Смежные вопросы