2011-10-31 30 views
5

Tôi có giao diện chung, có hai loại chung. Tôi muốn trang trí tất cả các phiên bản trả về, nhưng vì tôi không biết loại khi gọi EnrichWith, nó rõ ràng là không biên dịch. Tôi đã thử sử dụng EnrichWith overload quá tải trong ngữ cảnh, nghĩ rằng có lẽ tôi có thể lấy các kiểu generic được truyền vào và gọi Activator.CreateInstance, nhưng ngữ cảnh không có bất kỳ thông tin hữu ích nào khi gỡ lỗi và kiểm tra nó.Trang trí giao diện chung với Structuremap

Đây là những gì tôi có cho đến nay. Đây là giao diện chung của tôi:

public interface IServiceOperation<in TRequest, out TResponse> where TResponse : ServiceResult, new() 
{ 
    TResponse PerformService(TRequest validatedRequest); 
} 

Dưới đây là một việc thực hiện mẫu:

public class SignUpService : IServiceOperation<SignUpRequest, SignUpResult> 
{ 
    private readonly IUserRepository _userRepo; 

    public SignUpService(IUserRepository userRepo) 
    { 
     _userRepo = userRepo; 
    } 

    public SignUpResult PerformService(SignUpRequest validatedRequest) 
    { 
     var user = Mapper.Map<User>(validatedRequest); 

     user.MarkAsLoggedIn(); 
     user.ChangePassword(validatedRequest.UnhashedPassword); 

     using(var transaction = _userRepo.BeginTransaction()) 
     { 
      _userRepo.Save(user); 
      transaction.Commit(); 
     } 

     return new SignUpResult(); 
    } 
} 

Đây là trang trí của tôi, mà mất trong một dịch vụ khác cũng như:

public class ValidateServiceDecorator<TRequest, TResponse> : IServiceOperation<TRequest, TResponse> where TResponse : ServiceResult, new() 
{ 
    private readonly IServiceOperation<TRequest, TResponse> _serviceOperation; 
    private readonly IValidationService _validationService; 

    public ValidateServiceDecorator(IServiceOperation<TRequest, TResponse> serviceOperation, 
     IValidationService validationService) 
    { 
     _serviceOperation = serviceOperation; 
     _validationService = validationService; 
    } 

    public TResponse PerformService(TRequest request) 
    { 
     var response = new TResponse(); 
     var validationResult = _validationService.Validate(request); 

     if (!validationResult.IsValid) 
     { 
      response.ValidationErrors = validationResult.ValidationErrors; 
      return response; 
     } 

     return _serviceOperation.PerformService(request); 
    } 

Cuối cùng, đây là cách xa tôi đã nhận được trên container của tôi. Điều này rõ ràng không biên dịch, nhưng dòng EnrichWith cho thấy những gì tôi đang cố gắng để đạt được:

public class StructureMapServiceScanner : Registry 
{ 
    public StructureMapServiceScanner() 
    { 
     Scan(scanner => 
       { 
        scanner.AssemblyContainingType(typeof (IServiceOperation<,>)); 
        scanner.ConnectImplementationsToTypesClosing(typeof (IServiceOperation<,>)); 
       }); 

     For(typeof (IServiceOperation<,>)) 
     .EnrichWith((ioc, original) => new ValidateServiceDecorator(original, ioc.GetInstance<IValidationService>())); 
    } 
} 

Và chỉ vì câu hỏi này cần một ít mã hơn, đây là thử nghiệm của tôi rằng tôi đang cố gắng để có được để vượt qua :

[TestClass] 
public class StructureMapServiceScannerSpecs 
{ 
    [TestMethod] 
    public void Test() 
    { 
     ObjectFactory.Configure(cfg => 
            { 
             cfg.AddRegistry<StructureMapServiceScanner>(); 
             cfg.For<IUserRepository>().Use(new Mock<IUserRepository>().Object); 
             cfg.For<IValidationService>().Use(new Mock<IValidationService>().Object); 
            }); 

     var service = ObjectFactory.GetInstance<IServiceOperation<SignUpRequest, SignUpResult>>(); 

     service.ShouldNotBeNull(); 
     service.ShouldBeType<ValidateServiceDecorator<SignUpRequest, SignUpResult>>(); 
    } 
} 

Tôi cảm thấy đây là điều đơn giản và tôi thực sự thiếu thứ gì đó về cách sử dụng StructureMap. Tôi có thể tạo ra các phiên bản kiểu cụ thể cho tất cả các kết hợp của các kiểu Yêu cầu và Phản hồi, nhưng rõ ràng đó không phải là điều mong muốn. Vì vậy, tôi đang thiếu gì?

+0

Đã có thể tìm ra, sử dụng RegistrationConvention để làm phong phú từng loại hình đóng của giao diện trực tiếp. Tôi đã đăng những gì tôi đã làm, nhưng tôi không thể cho một vài giờ. – Robert

Trả lời

4

Đã có thể tìm ra, cuối cùng. Tôi tạo ra một RegistrationConvention:

public class ServiceRegistrationConvention : IRegistrationConvention 
{ 
    public void Process(Type type, Registry registry) 
    { 
     var interfacesImplemented = type.GetInterfaces(); 

     foreach (var interfaceImplemented in interfacesImplemented) 
     { 
      if (interfaceImplemented.IsGenericType && interfaceImplemented.GetGenericTypeDefinition() == typeof(IServiceOperation<,>)) 
      { 
       var genericParameters = interfaceImplemented.GetGenericArguments(); 
       var closedValidatorType = typeof(ValidateServiceDecorator<,>).MakeGenericType(genericParameters); 

       registry.For(interfaceImplemented) 
        .EnrichWith((context, original) => Activator.CreateInstance(closedValidatorType, original, 
                       context.GetInstance<IValidationService>())); 
      } 
     } 
    } 
} 
3

Dưới đây là một cách tiếp cận mà vẫn thúc đẩy khả năng IoC StructureMap của, cho phép các dịch vụ bổ sung để được tiêm cách dễ dàng vào trang trí của bạn. Nó không hoàn hảo vì nó giả định bạn đang sử dụng các container chính và không phải là một container con, nhưng nó có thể sẽ làm việc cho hầu hết các kịch bản.

public class ServiceRegistrationConvention : IRegistrationConvention 
{ 
    public void Process(Type type, Registry registry) 
    { 
     var handlerInterfaces = (from t in type.GetInterfaces() 
           where t.IsGenericType && 
             t.GetGenericTypeDefinition() == typeof (IHandle<,>) 
           select t); 

     foreach (var handler in handlerInterfaces) 
     { 
      var decoratorType = typeof (ValidationDecorator<,>).MakeGenericType(handler.GetGenericArguments()); 

      registry.For(handler) 
       .EnrichWith((ctx, orig) => ObjectFactory.With(handler, orig).GetInstance(decoratorType)); 
     } 
    } 
} 

Lý tưởng nhất, IContext của StructureMap sẽ hiển thị phương thức With giống như IContainer. Nếu không có điều đó, không thực sự là một giải pháp tuyệt vời cho vấn đề này.

Các vấn đề liên quan