我一直在使用SimpleInjector,我正在尝试正确注册所有命令处理程序。
这是我的代码:
public interface ICommand {}
public interface ICommandDispatcher
{
void Execute(ICommand command);
}
public class CommandDispatcher : ICommandDispatcher
{
private readonly Container container;
public CommandDispatcher(Container container)
{
this.container = container;
}
public void Execute(ICommand command)
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
dynamic handler = container.GetInstance(handlerType);
handler.Handle((dynamic)command);
}
}
public interface ICommandHandler<in TParameter> where TParameter : ICommand
{
void Handle(TParameter command);
}
public class UserCommandsHandler : ICommandHandler<CreateUser>
{
public void Handle(CreateUser message)
{
var user = new User(message.Email);
/* logic here */
}
}
public class CreateUser : ICommand
{
public readonly string Email;
public CreateUser(string email)
{
Email = email;
}
}
var assemblies = new[] { typeof(ICommandHandler<>).Assembly };
var container = new SimpleInjector.Container();
container.RegisterCollection(typeof(ICommandHandler<>), assemblies);
container.RegisterSingleton<ICommandDispatcher>(new CommandDispatcher(container));
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
public class HomeController : Controller
{
private readonly ICommandDispatcher _commandDispatcher;
public HomeController(ICommandDispatcher commandDispatcher)
{
_commandDispatcher = commandDispatcher;
}
public ActionResult Index()
{
var command = new CreateUser("[email protected]");
_commandDispatcher.Execute(command);
return Content("It works");
}
}
在CQRS.cs
dynamic handler = container.GetInstance(handlerType);
我明白了:
未找到
ICommandHandler<CreateUser>
类型的注册。但是,有IEnumerable<ICommandHandler<CreateUser>>
的注册;你的意思是打电话给GetAllInstances<ICommandHandler<CreateUser>>()
或依靠IEnumerable<ICommandHandler<CreateUser>>
?
Simple Injector API显然是separates between registrations for collections和一对一的映射。在撰写根目录中,您正在进行以下注册:
container.RegisterCollection(typeof(ICommandHandler<>),
new[] { typeof(ICommandHandler<>).Assembly });
RegisterCollection
的API文档声明:
注册一组serviceTypes,每次枚举已解析的serviceType集合时,其实例将被懒惰地解析。基础集合是一个流,它将根据其特定的注册生活方式返回单个实例,每次调用
IEnumerator<T>.Current
。类型在集合中出现的顺序与项目注册的顺序完全相同,即已解析的集合是确定性的。
换句话说,通过请求IEnumerable<ICommandHandler<T>>
,您允许将命令处理程序解析为集合。
然而,在你的CommandDispatcher
,你通过调用ICommandHandler<T>
请求一个container.GetInstance(handlerType)
。由于没有针对ICommandHandler<T>
的一对一映射,Simple Injector通过抛出以下内容告知您:
未找到
ICommandHandler<CreateUser>
类型的注册。但是,有IEnumerable<ICommandHandler<CreateUser>>
的注册;你的意思是打电话给GetAllInstances<ICommandHandler<CreateUser>>()
或依靠IEnumerable<ICommandHandler<CreateUser>>
?
要解决此问题,有两种选择:
CommandDispatcher
来解析GetAllInstances(Type)
中的一组处理程序。由于命令与其处理程序之间始终存在一对一映射(意味着:每个命令只有一个处理程序),因此选项1是最明显的解决方案。因此,请将注册更改为以下内容:
// Use 'Register' instead of 'RegisterCollection'.
container.Register(typeof(ICommandHandler<>),
new[] { typeof(ICommandHandler<>).Assembly });