使用SimpleInjector APIv3无需注册ICommandHandler类型 [英] No registration for type ICommandHandler using SimpleInjector APIv3

查看:78
本文介绍了使用SimpleInjector APIv3无需注册ICommandHandler类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在玩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 for IEnumerable<ICommandHandler<CreateUser>>; Did you mean to call GetAllInstances<ICommandHandler<CreateUser>>() or depend on IEnumerable<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 for IEnumerable<ICommandHandler<CreateUser>>; Did you mean to call GetAllInstances<ICommandHandler<CreateUser>>() or depend on IEnumerable<ICommandHandler<CreateUser>>?

要解决此问题,有两种选择:

To fix this, there are two options:


  1. 您可以使用一对一映射来注册处理程序,或者

  2. 您可以解析 CommandDispatcher ,通过调用 GetAllInstances(Type)

  1. Either you register your handlers using the one-to-one mapping, or
  2. You resolve a collection of handlers within your CommandDispatcher by calling GetAllInstances(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆