2013-07-03 27 views
13

Do sau:Autofac - Đăng ký nhiều trang trí

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

tôi có thể trang trí MoveCustomerCommandHandler với một TransactionCommandHandlerDecorator sử dụng đoạn mã sau:

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

nào sẽ ra:

TransactionCommandHandlerDecorator - before 
MoveCustomerCommandHandler 
TransactionCommandHandlerDecorator - after 

Làm thế nào tôi cũng có thể trang trí TransactionCommandHandlerDecorator với số DeadlockRetryCommandHandlerDecorator, để tạo đầu ra sau đây

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

Trả lời

13

Bạn chỉ cần đăng ký của bạn "TransactionCommandHandlerDecoratored" ICommandHandler như một dịch vụ Keyed và sử dụng chìa khóa mới khi đăng ký bạn thứ hai DeadlockRetryCommandHandlerDecorator:

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

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

Và bạn sẽ nhận được sản lượng sau:

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

Câu hỏi bổ sung cho các điểm bổ sung: làm thế nào để bạn đăng ký một trang trí có điều kiện trong Autofac, ví dụ dựa trên một ràng buộc loại chung? – Steven

+1

@Steven tốt câu hỏi, và tôi không có ý tưởng :) Đây là lần đầu tiên tôi đã sử dụng tính năng trang trí trong Autofac để trả lời câu hỏi này, vì vậy tôi phải nhìn nó lên nhưng tôi đoán impletation mặc định không phải là linh hoạt để cung cấp điều kiện, nhưng bạn luôn có thể viết «IRegistrationSource' của riêng mình ... nhưng tôi đoán có một cách đơn giản để thực hiện điều này trong SimpleInjector;) – nemesv

+0

Tôi hỏi điều này vì tôi thường nhận được câu hỏi từ những người muốn áp dụng các mẫu này sử dụng các thùng chứa khác ngoài Simple Injector, nhưng tiếc là tôi không thể cung cấp cho họ câu trả lời hay - ngoại trừ tất nhiên lời khuyên để sử dụng Simple Injector :-). Nhưng có bạn là đúng, đây là một khu vực mà Simple Injector thực sự tỏa sáng. – Steven

13

@nemesv đã trả lời câu hỏi này, Tuy nhiên tôi chỉ nghĩ rằng tôi muốn thêm rằng bạn có thể thêm một số phương pháp helper đơn giản để làm cho hệ thống dây điện lên rất nhiều trang trí chung ít đau đớn trong 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); 
     } 
    } 

Nếu bạn dán các phương pháp đó vào nơi bạn đang cấu hình Autofac, thì bạn chỉ có thể làm điều này:

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

Và nó sẽ kết nối tất cả các trình xử lý lệnh của bạn và thêm trang trí theo thứ tự đã cho.

+0

Đoạn mã tuyệt vời. Cảm ơn rât nhiêu vê nhưng chia sẻ! –

+0

Công việc này có thể cho Eventhandlers xử lý cùng một sự kiện không? –