我在最近的项目中使用CQRS
模式,并使用Structuremap 3
作为我的IoC Container
,因此我定义了以下转换来解决每个BaseEntity
类型的ICommandHandlers
:
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>>
for ICommandHandler<ICommandParameter<Order>>
有时我需要为某些实体注册自定义InsertCommandHandler
s,例如Product
,我想为ICommandHandler<ICommandParameter<Product>>
而不是InsertCommandHandler<InsertCommandParameter<Product>>
注册非通用InsertProductCustomCommandHandler
类(换句话说,我想覆盖InsertCommendRegistrationConvention
)。
我怎么能做到这一点,与Structuremap 3?
您可以使用IContainer.Configure()
方法来完成此操作- Configure()
方法允许您向现有的Container
或ObjectFactory
添加额外的配置
我已经简化了您的抽象,以便在实际操作中演示:
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);
}
}
}
这个测试演示了用InsertCommandRegistrationConvention
配置的容器将返回所有4个测试类ClassA
到ClassD
的通用InsertCommandHandler<>
[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));
}
您可以将约定修改为"如果有特定的命令处理程序,则使用该处理程序"。否则,使用InsertCommandHandler。"
它看起来像这样(像quick一样,我简化了类):
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>());
这样做的好处是修改了约定,而不是避免对某些项使用约定。如果你的逻辑需要改变,它可以将所有内容保持在一个位置。