1

我正在嘗試使用Castle Windsor實現Command,CommandHandler和CommandDispatcher模式,而無需手動要求容器根據Command類型(通常認爲是反模式)來解析CommandHandler。Castle Windsor&Command Pattern

我發現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安裝代碼:

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

    } 
} 

巨大GOTCHA

如果你的名字你的工廠方法類似GetCommandHandler,CW將盡力解決一類字面上叫CommandHandler,它會失敗,因爲你不沒有這種類型。根據文檔HERE CW應該回退到非基於類型的查找,但它似乎並沒有這樣做,只是回吐了ComponentNotFoundException。因此,請將您的工廠方法命名爲ANYINGING,但獲取*

0

您所描述的是基於接口的類型化工廠,即根據您傳遞的參數解析組件的工廠,無需任何實現,也無需您手動解析組件。 Here是一個答案,詳細說明如何使用鍵入的工廠機制,而here是一篇來自kozmic.net的文章,詳細介紹了它。

+0

謝謝samy,我已經找到這些文章,但不幸的是它仍然無法正常工作。經過幾個小時的戰鬥後,我終於設法使其工作,我會在下面發表一個完整的答案。 無論如何感謝您的幫助! – timurso