使用SimpleInjector APIv3无需注册ICommandHandler类型 [英] No registration for type ICommandHandler using SimpleInjector APIv3
问题描述
我一直在玩SimpleInjector,并且尝试正确注册所有命令处理程序。
I've been playing around with SimpleInjector and I'm trying to register properly all command handlers.
这是我的代码:
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);
}
Handler.cs
Handler.cs
public class UserCommandsHandler : ICommandHandler<CreateUser>
{
public void Handle(CreateUser message)
{
var user = new User(message.Email);
/* logic here */
}
}
命令.cs
Command.cs
public class CreateUser : ICommand
{
public readonly string Email;
public CreateUser(string email)
{
Email = email;
}
}
Global.asax.cs
Global.asax.cs
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));
HomeController.cs
HomeController.cs
public class HomeController : Controller
{
private readonly ICommandDispatcher _commandDispatcher;
public HomeController(ICommandDispatcher commandDispatcher)
{
_commandDispatcher = commandDispatcher;
}
public ActionResult Index()
{
var command = new CreateUser("email@example.com");
_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>>
?
No registration for type
ICommandHandler<CreateUser>
could be found. There is, however, a registration forIEnumerable<ICommandHandler<CreateUser>>
; Did you mean to callGetAllInstances<ICommandHandler<CreateUser>>()
or depend onIEnumerable<ICommandHandler<CreateUser>>
?
推荐答案
简单注入器API显然在集合注册和一对一映射之间进行分隔。在您的合成根目录中,您正在进行以下注册:
The Simple Injector API clearly separates between registrations for collections and one-to-one mappings. In your composition root, you are making the following registration:
container.RegisterCollection(typeof(ICommandHandler<>),
new[] { typeof(ICommandHandler<>).Assembly });
RegisterCollection
的API文档指出:
注册serviceTypes的集合,每次枚举已解析的serviceType的集合时,其实例将被延迟解析。基础集合是一个流,该流将根据每次调用
IEnumerator< T> .Current
的特定注册生活方式,返回各个实例。类型在集合中出现的顺序与项目注册的顺序完全相同,即,已解析的集合是确定性的。
Registers a collection of serviceTypes, whose instances will be resolved lazily each time the resolved collection of serviceType is enumerated. The underlying collection is a stream that will return individual instances based on their specific registered lifestyle, for each call to
IEnumerator<T>.Current
. The order in which the types appear in the collection is the exact same order that the items were registered, i.e the resolved collection is deterministic.
换句话说,通过请求 IEnumerable< ICommandHandler< T>>
,允许将命令处理程序解析为集合。
In other words, you are allowing command handlers to be resolved as collections, by requesting IEnumerable<ICommandHandler<T>>
.
在您的 CommandDispatcher
中,您通过调用<$ c $来请求单个 ICommandHandler< T>
c> container.GetInstance(handlerType)。由于 ICommandHandler< T>
没有一对一的映射,因此Simple Injector通过抛出以下内容来通知您:
In your CommandDispatcher
however, you request a single ICommandHandler<T>
by calling container.GetInstance(handlerType)
. Since there is no one-to-one mapping for an ICommandHandler<T>
, Simple Injector informs you about this by throwing:
找不到类型
ICommandHandler< CreateUser>
的注册。
但是,有一个IEnumerable< ICommandHandler< CreateUser>>
的注册;
是要调用GetAllInstances< ICommandHandler< CreateUser>>>()
还是要依赖IEnumerable< ICommandHandler< CreateUser>>
?
No registration for type
ICommandHandler<CreateUser>
could be found. There is, however, a registration forIEnumerable<ICommandHandler<CreateUser>>
; Did you mean to callGetAllInstances<ICommandHandler<CreateUser>>()
or depend onIEnumerable<ICommandHandler<CreateUser>>
?
要解决此问题,有两种选择:
To fix this, there are two options:
- 您可以使用一对一映射来注册处理程序,或者
- 您可以解析
CommandDispatcher
,通过调用GetAllInstances(Type)
。
- Either you register your handlers using the one-to-one mapping, or
- You resolve a collection of handlers within your
CommandDispatcher
by callingGetAllInstances(Type)
.
由于命令与其处理程序之间始终存在一对一的映射关系(意味着:每个命令将有一个处理程序),因此选项1是最明显的解决方案。因此,将您的注册更改为以下内容:
Since there will always be a one-to-one mapping between a command and its handler (meaning: there will be exactly one handler per command), option 1 is the most obvious solution. So change your registration to the following:
// Use 'Register' instead of 'RegisterCollection'.
container.Register(typeof(ICommandHandler<>),
new[] { typeof(ICommandHandler<>).Assembly });
这篇关于使用SimpleInjector APIv3无需注册ICommandHandler类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!