.net - IMediatR - 通用请求的通用请求处理程序

标签 .net asp.net-core generics simple-injector mediatr

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

我对如何通用注入(inject)这些类型的处理程序进行了一些研究,但我只能找到非通用注入(inject)。我想知道是否有办法为我在下面展示的那些 IRequest 注入(inject)这些类型的通用 IRequestHandlers?

这是我为 IRequest 创建的代码。

public class CreateAccessRequest<TViewModel> : IRequest<OperationResult<long>>, IValidatable
    where TViewModel : AccessRequestViewModel
{
    public TViewModel Request { get; set; }
}

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

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...
    }
}

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

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

我正在创建这样的请求:

// CreateApplicationAccessRequestViewModel inherits AccessRequestViewModel
var request = new CreateAccessRequest<CreateApplicationAccessRequestViewModel>();

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.

我无法摆脱那个实现,我不得不创建一个继承自 CreateAccessRequestHandler 的类。使用正确的泛型类型,然后它起作用了:
public sealed class CreateApplicationAccessRequestHandler : CreateAccessRequestHandler<CreateApplicationAccessRequestViewModel, ApplicationAccessRequestNotificationModel, ApplicationAccessRequest>
    {
        public CreateApplicationAccessRequestHandler(IRepository<ApplicationAccessRequest> accessRequestRepository, IMediator mediator, IMapper mapper)
            : base(accessRequestRepository, mediator, mapper)
        { }
    }

我的想法是只使用通用处理程序,而无需为每个访问请求类型创建派生类。有没有办法做到这一点?

--- 编辑: ---

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

var types = container.GetTypesToRegister(typeof(IRequestHandler<,>), assemblies, 
new TypesToRegisterOptions { IncludeGenericTypeDefinitions = true });

container.Register(typeof(IRequestHandler<,>), types.Where(t => !t.IsGenericTypeDefinition));

foreach(var openGenericType in types.Where(t => t.IsGenericTypeDefinition)) {
    container.Register(typeof(IRequestHandler<,>), openGenericType);
}

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

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

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

最佳答案

MediatR didn't find the request handler to the request



MediatR 只是一堆接口(interface);它不负责寻找请求处理程序——Simple Injector 是。

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

container.Register(typeof(IRequestHandler<,>), assemblies);

这将注册:

all concrete, non-generic, public and internal types in the given set of assemblies that implement the given openGenericServiceType with container's default lifestyle



(如 XML 文档所述)

您想要做的是不仅注册非泛型,还注册泛型类型。这可以通过多种方式实现。例如通过附加这些泛型类型:
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Register(typeof(IRequestHandler<,>), typeof(CreateAccessRequestHandler<,>));

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

var types =
    container.GetTypesToRegister(typeof(IRequestHandler<,>), assemblies,
        new TypesToRegisterOptions { IncludeGenericTypeDefinitions = true });

container.Register(typeof(IRequestHandler<,>), types);

关于.net - IMediatR - 通用请求的通用请求处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60118890/

相关文章:

java - 为什么Java的Hashtable的get方法接受一个Object作为参数?

c# - 在 Entity Framework 中的 Groupby 中获取(限制)列表

.net - 在 NAnt 中,我可以创建 VS 项目中列出的文件的文件集吗?

c# - 从具有多个零值的枚举中获取项目名称

c# - 无法将自定义用户数据添加到搭建的 ASP.NET Core 项目

java - 泛型继承有什么问题

c# - 使用 firebird RDBMS 在 .NET 应用程序中自动刷新数据

c# - 如何在同一个项目中针对netcoreapp2.0和net461

visual-studio - docker在Visual Studio中运行的命令在哪里

swift - 无法在 Swift 中声明递归泛型类型