IMediatR - 用于通用请求的通用请求处理程序

Van*_*ira 8 .net generics simple-injector mediatr asp.net-core

我目前面临 IMediatR IRequestHandlers 和 IRequest 的问题。为了提供一些背景信息,在我们的工具上,用户可以通过填写几个字段来请求访问该工具。目前,我们有两个级别的访问权限,这意味着我们应该有两个 IRequestHandler,每个 IRequestHandler 一个。由于我们要做的只是将访问请求注册到数据库并发送电子邮件,因此我认为可以创建一个通用的 IRequestHandler 来处理这些情况(如果我们创建移动访问级别,它将在将来有所帮助)。

我对如何通用注入这些类型的处理程序进行了一些研究,但我只能找到非通用注入。我想知道是否有一种方法可以为我在下面介绍的那些 IRequest 注入这些类型的通用 IRequestHandler?

这是我为 IRequest 创建的代码。

public class CreateAccessRequest<TViewModel> : IRequest<OperationResult<long>>, IValidatable
    where TViewModel : AccessRequestViewModel
{
    public TViewModel Request { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是请求处理程序,我可以创建的更通用的处理程序。

public class CreateAccessRequestHandler<TViewModel, TNotificationModel, TEntity> : IRequestHandler<CreateAccessRequest<TViewModel>, OperationResult<long>>
    where TViewModel : AccessRequestViewModel
    where TEntity : Entity
    where TNotificationModel : INotification
{
    private readonly IRepository<TEntity> _accessRequestRepository;
    private readonly IMediator _mediator;
    private readonly IMapper _mapper;

    public CreateAccessRequestHandler(IRepository<TEntity> accessRequestRepository, IMediator mediator, IMapper mapper)
    {
       // initalization ...
    }

    public async Task<OperationResult<long>> Handle(CreateAccessRequest<TViewModel> request, CancellationToken cancellationToken)
    {
       // mapping, saving to database and sending notifications...
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,这是处理程序的注入代码

void ConfigureMediatR(Container container)
{
    var assemblies = GetAssemblies().ToArray();
    container.RegisterSingleton<IMediator, Mediator>();
    container.Register(typeof(IRequestHandler<,>), assemblies);
}
Run Code Online (Sandbox Code Playgroud)

我正在像这样创建请求:

// CreateApplicationAccessRequestViewModel inherits AccessRequestViewModel
var request = new CreateAccessRequest<CreateApplicationAccessRequestViewModel>();
Run Code Online (Sandbox Code Playgroud)

MediatR 找不到该请求的请求处理程序并引发了此异常:

Error constructing handler for the request of type MediatR.IRequestHandler<CreateAccessRequest<CreateApplicationAccessRequestViewModel>, OperationResult<long>>. Register your handlers with the container. See the samples in GitHub for example.
Run Code Online (Sandbox Code Playgroud)

我无法摆脱这种实现,我必须创建一个继承CreateAccessRequestHandler正确的泛型类型的类,然后它就起作用了:

public sealed class CreateApplicationAccessRequestHandler : CreateAccessRequestHandler<CreateApplicationAccessRequestViewModel, ApplicationAccessRequestNotificationModel, ApplicationAccessRequest>
    {
        public CreateApplicationAccessRequestHandler(IRepository<ApplicationAccessRequest> accessRequestRepository, IMediator mediator, IMapper mapper)
            : base(accessRequestRepository, mediator, mapper)
        { }
    }
Run Code Online (Sandbox Code Playgroud)

我的想法是仅使用通用处理程序,而不需要为每个访问请求类型创建派生类。有办法做到吗?

- -编辑: - -

我使用了史蒂文在他的答案中放置的代码,它几乎适用于我的情况。我将下面解释这一点:

Error constructing handler for the request of type MediatR.IRequestHandler<CreateAccessRequest<CreateApplicationAccessRequestViewModel>, OperationResult<long>>. Register your handlers with the container. See the samples in GitHub for example.
Run Code Online (Sandbox Code Playgroud)

我分别注册了泛型和非泛型类型,它在大多数情况下都有效,除非您有无法解析的类型,这就是我使用TEntity的情况。

SimpleInjector 不知道如何解析 TEntity,因为(我猜)我没有将其提供给定义中的 IRequestHandler。

如果我在请求中放置 TEntity (即CreateAccessRequest<TViewModel, TEntity>),它会起作用,但它会破坏项目的体系结构。因此,我选择这里提到的备份实现(从这些通用中创建具体的处理程序),以至少保持代码集中。

Ste*_*ven 7

\n

MediatR 未找到该请求的请求处理程序

\n
\n\n

MediatR 只是一堆接口;它不负责查找请求处理程序\xe2\x80\x94Simple Injector。

\n\n

您当前正在使用以下代码来注册处理程序:

\n\n
container.Register(typeof(IRequestHandler<,>), assemblies);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这将注册:

\n\n
\n

给定集合中所有具体的、非泛型的、公共的和内部的类型都assemblies实现了给openGenericServiceType定容器的默认生活方式

\n
\n\n

(如 XML 文档所述)

\n\n

您要做的不仅是注册非泛型类型,还要注册泛型类型这可以通过多种方式实现。例如通过附加这些泛型类型:

\n\n
container.Register(typeof(IRequestHandler<,>), assemblies);\ncontainer.Register(typeof(IRequestHandler<,>), typeof(CreateAccessRequestHandler<,>));\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,如果您有许多开放通用实现,则批量注册它们可能会更有效:

\n\n
container.Register(typeof(IRequestHandler<,>), assemblies);\ncontainer.Register(typeof(IRequestHandler<,>), typeof(CreateAccessRequestHandler<,>));\n
Run Code Online (Sandbox Code Playgroud)\n