2014-07-02 58 views
3

我在我最近的項目中使用CQRS模式和使用Structuremap 3作爲我IoC Container,所以我定義下面的轉換來解決ICommandHandlers每個BaseEntity類型:覆蓋定製登記約定3

public class InsertCommandRegistrationConvention 
    : StructureMap.Graph.IRegistrationConvention 
{ 
    private static readonly Type _openHandlerInterfaceType = typeof(ICommandHandler<>); 
    private static readonly Type _openInsertCommandType = typeof(InsertCommandParameter<>); 
    private static readonly Type _openInsertCommandHandlerType = typeof(InsertCommandHandler<>); 

    public void Process(Type type, Registry registry) 
    { 
     if (!type.IsAbstract && typeof(BaseEntity).IsAssignableFrom(type) && 
      type.GetInterfaces().Any(x => x.IsGenericType && 
       x.GetGenericTypeDefinition() == typeof(IAggregateRoot<>))) 
     { 
      Type closedInsertCommandType = _openInsertCommandType.MakeGenericType(type); 
      Type closedInsertCommandHandlerType = 
       _openInsertCommandHandlerType.MakeGenericType(type); 

      Type insertclosedHandlerInterfaceType = 
       _openHandlerInterfaceType.MakeGenericType(closedInsertCommandType); 
      registry.For(insertclosedHandlerInterfaceType) 
       .Use(closedInsertCommandHandlerType); 
     } 
    } 
} 

,並用它在我CompositionRoot:

public static class ApplicationConfiguration 
{ 
    public static IContainer Initialize() 
    { 
     ObjectFactory.Initialize(x => 
     { 
      x.Scan(s => 
      { 
       s.TheCallingAssembly(); 
       s.WithDefaultConventions(); 
       s.Convention<InsertCommandRegistrationConvention>(); 
      }); 
     }); 

     return ObjectFactory.Container; 
    } 
} 

所以我的每一個實體,它例如註冊適當InsertCommandHandler其註冊

InsertCommandHandler<InsertCommandParameter<Order>>ICommandHandler<ICommandParameter<Order>>

有時我需要爲某些實體,例如用於Product我要註冊非通用InsertProductCustomCommandHandlerICommandHandler<ICommandParameter<Product>>代替InsertCommandHandler<InsertCommandParameter<Product>>(在其他的字註冊自定義InsertCommandHandler S,我想覆蓋InsertCommendRegistrationConvention)。

我怎麼能這樣做,結構圖3?

回答

3

你可以使用方法IContainer.Configure()做到這一點 - 在Configure()方法可以讓你額外的配置添加到現有ContainerObjectFactory

我已經簡化你的抽象的行動來證明這一點:

public abstract class BaseEntity { } 
public interface ICommandHandler<T> { } 
public class ClassA : BaseEntity { } 
public class ClassB : BaseEntity { } 
public class ClassC : BaseEntity { } 
public class ClassD : BaseEntity { } 
public class InsertCommandHandler<T> : ICommandHandler<T> { } 
public class SpecialInsertDCommandHandler : ICommandHandler<ClassD> { } 

InsertCommandRegistrationConvention

public class InsertCommandRegistrationConvention : IRegistrationConvention 
{ 
    private static readonly Type _openHandlerInterfaceType = 
     typeof(ICommandHandler<>); 
    private static readonly Type _openInsertCommandHandlerType = 
     typeof(InsertCommandHandler<>); 

    public void Process(Type type, Registry registry) 
    { 
     if (!type.IsAbstract && typeof(BaseEntity).IsAssignableFrom(type)) 
     { 
      Type closedInsertCommandHandlerType = 
       _openInsertCommandHandlerType.MakeGenericType(type); 

      Type insertclosedHandlerInterfaceType = 
       _openHandlerInterfaceType.MakeGenericType(type); 

      registry.For(insertclosedHandlerInterfaceType) 
       .Use(closedInsertCommandHandlerType); 
     } 
    } 
} 

這個te第一證明用InsertCommandRegistrationConvention構成的容器將用於測試類ClassA的所有4返回通用InsertCommandHandler<>ClassD

[Test] 
public void Handle_Initialize_RegistersClassesAToDToReturnInsertCommandHandler() 
{ 
    var container = ApplicationConfiguration.Initialize(); 

    var resultA = container.GetInstance<ICommandHandler<ClassA>>(); 
    var resultB = container.GetInstance<ICommandHandler<ClassB>>(); 
    var resultC = container.GetInstance<ICommandHandler<ClassC>>(); 
    var resultD = container.GetInstance<ICommandHandler<ClassD>>(); 

    Assert.That(resultA.GetType() == typeof(InsertCommandHandler<ClassA>)); 
    Assert.That(resultB.GetType() == typeof(InsertCommandHandler<ClassB>)); 
    Assert.That(resultC.GetType() == typeof(InsertCommandHandler<ClassC>)); 
    Assert.That(resultD.GetType() == typeof(InsertCommandHandler<ClassD>)); 
} 

而這個試驗顯示了Configure方法成功地更新了登記ClassD返回SpecialInsertDCommandHandler代替InsertCommandHandler<ClassD>

[Test] 
public void Handle_Condfigure_OverridesRegistrationForClassD() 
{ 
    var container = ApplicationConfiguration.Initialize(); 

    container.Configure(x => 
    { 
     x.For<ICommandHandler<ClassD>>().Use<SpecialInsertDCommandHandler>(); 
    }); 

    var resultD = container.GetInstance<ICommandHandler<ClassD>>(); 

    Assert.That(resultD.GetType() == typeof(SpecialInsertDCommandHandler)); 
} 
+0

我用過容器。Configure()',但是當我運行'WhatDoIHave()'時,它顯示'ICommandHandler >'結構映射同時使用'InsertCommandHandler '作爲默認值和自定義'InsertCalendarCommandHandler'(但不是默認值)。 – Masoud

+0

Hi @Masoud - 我的代碼向他們展示了另一個有點令人費解的方式 - 在調用ApplicationConfiguration.Initialize()後添加了自定義註冊嗎? – qujck

+0

你說得對,在修復它之後,我使用'container.Configure()'代替'container.Initialize()'來代替通用的'InsertCommandHandlers',現在'InsertCalendarCommandHandler'是默認的,'ICommandHandler >'不是。但我的程序是模塊化的,我不能每個模塊都有一個'Initialize()'。所以我必須爲程序設置一個「初始化」,爲每個模塊設置一個「配置」。 – Masoud

2

你可以修改約定來說一些類似於「如果有特定的命令處理程序,使用它。否則,使用InsertCommandHandler」

它看起來像這樣(像qujck,我簡單的類):

public class InsertCommandRegistrationConvention : IRegistrationConvention 
{ 
    private static readonly Type _openHandlerInterfaceType = typeof (ICommandHandler<>); 
    private static readonly Type _openInsertCommandHandlerType = typeof (InsertCommandHandler<>); 
    private static readonly IList<Type> _customCommandHandlerTypes; 

    static InsertCommandRegistrationConvention() 
    { 
     _customCommandHandlerTypes = _openInsertCommandHandlerType 
      .Assembly 
      .ExportedTypes 
      .Where(x => !x.IsAbstract) 
      .Where(x => !x.IsGenericType || x.GetGenericTypeDefinition() != typeof (InsertCommandHandler<>)) 
      .Where(x => x.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>))) 
      .ToArray(); 
    } 

    public void Process(Type type, Registry registry) 
    { 
     if (!type.IsAbstract && typeof (BaseEntity).IsAssignableFrom(type)) 
     { 
      var insertclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(type); 
      var closedInsertCommandHandlerType = _openInsertCommandHandlerType.MakeGenericType(type); 

      // check for any classes that implement ICommandHandler<T> that are not also InsertCommandHandler<T> 
      var customHandler = _customCommandHandlerTypes.FirstOrDefault(t => t.GetInterfaces().Any(i => i == insertclosedHandlerInterfaceType)); 

      registry.For(insertclosedHandlerInterfaceType) 
       .Use(customHandler ?? closedInsertCommandHandlerType); 
     } 
    } 
} 

我使用的類:

public abstract class BaseEntity { } 
public class Class1 : BaseEntity { } 
public class Class2 : BaseEntity { } 
public class SpecialClass :BaseEntity { } 

public interface ICommandHandler<T> { } 
public class InsertCommandHandler<T> : ICommandHandler<T> { } 
public class SpecialClassInsertCommandHandler : ICommandHandler<SpecialClass> { } 

通過測試:

 Assert.That(ObjectFactory.GetInstance<ICommandHandler<Class1>>(), Is.InstanceOf<InsertCommandHandler<Class1>>()); 
     Assert.That(ObjectFactory.GetInstance<ICommandHandler<Class2>>(), Is.InstanceOf<InsertCommandHandler<Class2>>()); 
     Assert.That(ObjectFactory.GetInstance<ICommandHandler<SpecialClass>>(), Is.InstanceOf<SpecialClassInsertCommandHandler>()); 

優點是您修改了慣例,而不是避免使用它對於某些項目。如果關於你的邏輯的某些事情必須改變,它將一切都保存在一個地方