2017-05-17 14 views
1

私は、異なるクライアントに対して異なるクラスの実装を持つアプリケーションを作成しています。私たちはCQRSを使用しています。クライアントごとに異なるコマンドとクエリの実装を追加したいのですが(クライアント固有のものがない場合は、デフォルトのものをデフォルトにします)。属性に基づいたユニティコンテナの解決

アプリケーションは以前は1つのクライアントしか持たず、これは問題なく動作しましたが、今度はクライアントごとにコマンドとクライアントをオーバーライドする必要があります。私はこれを行う方法について多くのアイディアを持ってきましたが、クエリー/コマンドのセットを追加するだけで新しいクライアントを簡単に追加できるようになったので、これは最もクリーンです。

クエリをディスパッチコードは以下の通りです:

public InProcQueryDispatcher(
     IQueryHandlerFactory queryHandlerFactory, 
     Action<Exception, IQuery> onHandlerFailed) 
    { 
     this.queryHandlerFactory = queryHandlerFactory; 
     this.onHandlerFailed = onHandlerFailed; 
     this.getHandlerMethod = typeof(IQueryHandlerFactory).GetMethod("GetHandler"); 
    } 

    public async Task<TResult> Execute<TResult>(IQuery<TResult> query) 
    { 
     if (query == null) 
     { 
      throw new ArgumentNullException(); 
     } 

     try 
     { 
      var queryHandler = this.ResolveHandler<TResult>(query.GetType()); 

      var task = (Task<TResult>) queryHandler.Handle((dynamic) query); 

      return await task; 
     } 
     catch (Exception ex) 
     { 
      this.onHandlerFailed(ex, query); 
      throw; 
     } 
    } 

    private dynamic ResolveHandler<TResult>(Type queryType) 
    { 
     var getHandler = this.getHandlerMethod.MakeGenericMethod(queryType, typeof (TResult)); 
     return getHandler.Invoke(this.queryHandlerFactory, null); 
    } 
} 

私は今、次のようにそれを変更することができるようにしたい:

`public async Task<TResult> Execute<TResult>(IQuery<TResult> query) 
     { 
      if (query == null) 
      { 
       throw new ArgumentNullException(); 
      } 

      try 
      { 
       var queryHandler = this.ResolveHandler<TResult>(query.GetType(), query.ClientId); 

       var task = (Task<TResult>) queryHandler.Handle((dynamic) query); 

       return await task; 
      } 
      catch (Exception ex) 
      { 
       this.onHandlerFailed(ex, query); 
       throw; 
      } 
     } 

     private dynamic ResolveHandler<TResult>(Type queryType, Guid clientId) 
     { 
      var getHandler = this.getHandlerMethod.MakeGenericMethod(queryType, clientId, typeof (TResult)); 
      return getHandler.Invoke(this.queryHandlerFactory, null); 
     } 

誰も私を解決するために私のgetHandleMethodを更新する可能性がどのようにお勧めします正しいクエリは、clientIDに基づいていますか?

GetHandleMethod:IoCので

public IQueryHandler<TQuery, TResult> GetHandler<TQuery, TResult>() where TQuery : class, IQuery<TResult> 
    { 
     return container.Resolve<IQueryHandler<TQuery, TResult>>(); 
    } 

答えて

0

、あなたのオブジェクトは、あなたが右ストレートコンストラクタにコンテナを渡すためにしていないという意味で、コンテナ自体の意識すべきではありません。しかし、あなたのクラスに工場を渡して、それを使って解決することができます。私はそれを名前付き登録と組み合わせるとかなりうまくいくことを発見しました。あなたがそれを行うことができる方法の概要は、の線に沿って何かのようになります。

container.RegisterType<IQueryHandler<TQuery, TResult>, QueryHandlerVersionOne<TQuery, TResult>>("1"); 
container.RegisterType<IQueryHandler<TQuery, TResult>, QueryHandlerVersionTwo<TQuery, TResult>>("2"); 

container.RegisterType<Func<int, IQueryHandler<TQuery, TResult>>>(
    new InjectionFactory(c => 
     new Func<int, IQueryHandler<TQuery, TResult>>((clientID) => 
     { 
      var handler = c.Resolve<IQueryHandler<TQuery, TResult>>(clientID.ToString()); 

      return handler; 
     }))); 

そして、あなたのコンストラクタでは、あなたはタイプFunc<int, IQueryHandler<TQuery, TResult>>の工場の注射のためのパラメータを追加します。

私はもっと長い例in this postで答えました。

関連する問題