2013-07-03 2 views
13

を登録します。出力は以下となりますAutofac - 次を考えると、複数のデコレータ

var builder = new ContainerBuilder(); 

builder.RegisterAssemblyTypes(typeof(MoveCustomerCommandHandler).Assembly) 
    .As(type => type.GetInterfaces() 
    .Where(interfaceType => interfaceType.IsClosedTypeOf(typeof(ICommandHandler<>))) 
    .Select(interfaceType => new KeyedService("commandHandler", interfaceType))); 

builder.RegisterGenericDecorator(
     typeof(TransactionCommandHandlerDecorator<>), 
     typeof(ICommandHandler<>), 
     fromKey: "commandHandler"); 

var container = builder.Build(); 

var commandHandler = container.Resolve<ICommandHandler<MoveCustomerCommand>>(); 
commandHandler.Handle(new MoveCustomerCommand()); 

TransactionCommandHandlerDecorator - before 
MoveCustomerCommandHandler 
TransactionCommandHandlerDecorator - after 

public interface ICommandHandler<in TCommand> 
{ 
    void Handle(TCommand command); 
} 

public class MoveCustomerCommand 
{ 

} 

public class MoveCustomerCommandHandler : ICommandHandler<MoveCustomerCommand> 
{ 
    public void Handle(MoveCustomerCommand command) 
    { 
     Console.WriteLine("MoveCustomerCommandHandler"); 
    } 
} 

public class TransactionCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> 
{ 
    private readonly ICommandHandler<TCommand> _decorated; 

    public TransactionCommandHandlerDecorator(ICommandHandler<TCommand> decorated) 
    { 
     _decorated = decorated; 
    } 

    public void Handle(TCommand command) 
    { 
     Console.WriteLine("TransactionCommandHandlerDecorator - before"); 
     _decorated.Handle(command); 
     Console.WriteLine("TransactionCommandHandlerDecorator - after"); 
    } 
} 

public class DeadlockRetryCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> 
{ 
    private readonly ICommandHandler<TCommand> _decorated; 

    public DeadlockRetryCommandHandlerDecorator(ICommandHandler<TCommand> decorated) 
    { 
     _decorated = decorated; 
    } 

    public void Handle(TCommand command) 
    { 
     Console.WriteLine("DeadlockRetryCommandHandlerDecorator - before"); 
     _decorated.Handle(command); 
     Console.WriteLine("DeadlockRetryCommandHandlerDecorator - after"); 
    } 
} 

を私は次のコードを使用してTransactionCommandHandlerDecoratorMoveCustomerCommandHandlerを飾ることができますでTransactionCommandHandlerDecoratorをどのように飾ることができますか?、あなただけのKeyedサービスとしてあなたの「TransactionCommandHandlerDecoratored」ICommandHandlerを登録しDeadlockRetryCommandHandlerDecorator 2番目を登録するときに、新しいキーを使用する必要がある次の出力

DeadlockRetryCommandHandlerDecorator- before 
TransactionCommandHandlerDecorator - before 
MoveCustomerCommandHandler 
TransactionCommandHandlerDecorator - after 
DeadlockRetryCommandHandlerDecorator- after 

答えて

13

を生成する:

builder.RegisterGenericDecorator(
     typeof(TransactionCommandHandlerDecorator<>), 
     typeof(ICommandHandler<>), 
     fromKey: "commandHandler") 
     .Keyed("decorated", typeof(ICommandHandler<>)); 

builder.RegisterGenericDecorator(
     typeof(DeadlockRetryCommandHandlerDecorator<>), 
     typeof(ICommandHandler<>), 
     fromKey: "decorated"); 

そして、あなたが取得します次の出力:

DeadlockRetryCommandHandlerDecorator - before 
TransactionCommandHandlerDecorator - before 
MoveCustomerCommandHandler 
TransactionCommandHandlerDecorator - after 
DeadlockRetryCommandHandlerDecorator - after 
+0

追加ポイントについてのその他の質問:一般的なタイプの制約に基づいて、オートファックに条件付デコレータを登録するにはどうすればよいですか? – Steven

+1

@Steven良い質問、私は考えていない:)これは私がAutofacのデコレータ機能を使ってこの質問に答える初めてのことなので、それを見なければならないが、デフォルトの実装はそれほど柔軟ではない条件を提供しますが、あなたはいつも自分の 'IRegistrationSource'を書くことができます...しかし、私はSimpleInjectorでこれを行う簡単な方法があると思います;) – nemesv

+0

私は頻繁にこれらのパターンを適用したい開発者から質問を得るので、 Simple Injector以外のコンテナを使用していましたが、残念ながら良いインプットを与えることができませんでした。しかし、そうです、これはSimple Injectorが本当に輝く場所です。 – Steven

13

@nemesvはすでにこの質問に回答しており、しかし、私はちょうど私があなたがAutofacではあまり痛みを伴う一般的なデコレータをたくさんアップ配線作るためにいくつかの簡単なヘルパーメソッドを追加できることを追加しようと思いました:

private static void RegisterHandlers(
     ContainerBuilder builder, 
     Type handlerType, 
     params Type[] decorators) 
    { 
     RegisterHandlers(builder, handlerType); 

     for (int i = 0; i < decorators.Length; i++) 
     { 
      RegisterGenericDecorator(
       builder, 
       decorators[i], 
       handlerType, 
       i == 0 ? handlerType : decorators[i - 1], 
       i != decorators.Length - 1); 
     } 
    } 

    private static void RegisterHandlers(ContainerBuilder builder, Type handlerType) 
    { 
     builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) 
      .As(t => t.GetInterfaces() 
        .Where(v => v.IsClosedTypeOf(handlerType)) 
        .Select(v => new KeyedService(handlerType.Name, v))) 
      .InstancePerRequest(); 
    } 

    private static void RegisterGenericDecorator(
     ContainerBuilder builder, 
     Type decoratorType, 
     Type decoratedServiceType, 
     Type fromKeyType, 
     bool hasKey) 
    { 
     var result = builder.RegisterGenericDecorator(
      decoratorType, 
      decoratedServiceType, 
      fromKeyType.Name); 

     if (hasKey) 
     { 
      result.Keyed(decoratorType.Name, decoratedServiceType); 
     } 
    } 

あなたの場所にそれらのメソッドを貼り付ける場合は、Autofacを設定しています、

RegisterHandlers(
     builder, 
     typeof(ICommandHandler<>), 
     typeof(TransactionCommandHandlerDecorator<>), 
     typeof(ValidationCommandHandlerDecorator<>)); 

そして、指定された順序でデコレータを追加して、すべてのコマンドハンドラを接続します。

+0

コードの大きな部分。共にありがとう! –

+0

これは、同じイベントを処理するイベントハンドラでは機能しますか? –

関連する問題