You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自动注册MediatR泛型处理器,无需手动定义每种类型?

ASP.NET Core中MediatR泛型处理器的自动注册方案

背景与现状

我在ASP.NET Core中结合MediatR和依赖注入开发时,遇到了泛型处理器注册的扩展性问题。当前的注册方式需要手动为每种具体类型(如string、bool、decimal等)显式添加处理器,代码如下:

public static void MediatRServices(this IServiceCollection service)
{
    service.AddMediatR(c => c.RegisterServicesFromAssembly(typeof(LoginCommand).Assembly));

    service.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));

    // 手动为不同具体类型添加处理器
    service.AddTransient(typeof(IRequestHandler<UpdateServicePropertyCommand<string>, GenericResponseDto>),
        typeof(UpdateServiceHandler<string>));
    service.AddTransient(typeof(IRequestHandler<UpdateServicePropertyCommand<bool>, GenericResponseDto>),
        typeof(UpdateServiceHandler<bool>));
    service.AddTransient(typeof(IRequestHandler<UpdateServicePropertyCommand<decimal>, GenericResponseDto>),
        typeof(UpdateServiceHandler<decimal>));
    service.AddTransient(typeof(IRequestHandler<UpdateServicePropertyCommand<TimeSpan>, GenericResponseDto>),
        typeof(UpdateServiceHandler<TimeSpan>));

    // 其他命令的处理器...
    service.AddTransient(typeof(IRequestHandler<UpdateGenericPropertyCommand<ServiceTemplate, bool>, GenericResponseDto>),
        typeof(UpdateGenericPropertyHandler<ServiceTemplate, bool>));
    service.AddTransient(typeof(IRequestHandler<UpdateGenericPropertyCommand<ServiceTemplate, decimal>, GenericResponseDto>),
        typeof(UpdateGenericPropertyHandler<ServiceTemplate, decimal>));
    service.AddTransient(typeof(IRequestHandler<UpdateGenericPropertyCommand<ServiceTemplate, TimeSpan>, GenericResponseDto>),
        typeof(UpdateGenericPropertyHandler<ServiceTemplate, TimeSpan>));
}

对应的命令和处理器定义如下:

public class UpdateServicePropertyCommand<T> : IRequest<GenericResponseDto>
{
    public T Value { get; set; }
}

public class UpdateServiceHandler<T> : IRequestHandler<UpdateServicePropertyCommand<T>, GenericResponseDto>
{
    public Task<GenericResponseDto> Handle(UpdateServicePropertyCommand<T> request, CancellationToken cancellationToken)
    {
        // 业务实现
    }
}

问题与尝试

手动注册每个泛型类型组合的扩展性极差,当类型组合增多时维护成本飙升。我曾尝试直接注册开放式泛型,但ASP.NET Core原生DI不支持这种方式,运行时会报错:

services.AddTransient(typeof(IRequestHandler<UpdateGenericPropertyCommand<,>, GenericResponseDto>),
    typeof(UpdateGenericPropertyHandler<,>));

另外,我尝试启用MediatR的RegisterGenericHandlers配置:

service.AddMediatR(c =>
{
    c.RegisterServicesFromAssembly(typeof(LoginCommand).Assembly);
    c.MaxTypesClosing = 0; // 允许注册所有类型
    c.RegisterGenericHandlers = true;
});

但触发了错误:

System.ArgumentException: Error registering the generic type: . The total number of generic type registrations exceeds the maximum allowed (125000).

该配置会尝试生成过多类型,超出上限。

疑问

  • 有没有更优的方式统一配置注册,无需手动定义每种类型组合?
  • 是否可以通过程序集扫描动态注册所有匹配IRequestHandler<,>的泛型处理器?
  • 如果Autofac等第三方DI容器更适合,该如何简化泛型注册?

解决方案

方案1:使用MediatR的泛型注册支持(无需额外库)

MediatR本身支持注册开放式泛型处理器,无需手动指定具体类型。只需确保你的泛型处理器实现了正确的IRequestHandler<,>接口,然后直接注册开放式泛型即可:

public static void MediatRServices(this IServiceCollection service)
{
    service.AddMediatR(c => c.RegisterServicesFromAssembly(typeof(LoginCommand).Assembly));

    service.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));

    // 注册开放式泛型处理器
    service.AddTransient(
        typeof(IRequestHandler<UpdateServicePropertyCommand<>, GenericResponseDto>),
        typeof(UpdateServiceHandler<>)
    );

    service.AddTransient(
        typeof(IRequestHandler<UpdateGenericPropertyCommand<,>, GenericResponseDto>),
        typeof(UpdateGenericPropertyHandler<,>)
    );
}

注意:ASP.NET Core DI支持开放式泛型注册,但需要确保接口和实现的泛型参数数量完全匹配。比如UpdateServicePropertyCommand<T>是单泛型参数,对应的处理器UpdateServiceHandler<T>也要匹配,注册时用UpdateServicePropertyCommand<>(开放式泛型)而非具体类型。

方案2:使用Scrutor进行程序集扫描

Scrutor可以自动扫描程序集中的泛型类型并注册,只需配置扫描规则:

  1. 安装Scrutor NuGet包:Install-Package Scrutor
  2. 配置服务注册:
public static void MediatRServices(this IServiceCollection service)
{
    service.AddMediatR(c => c.RegisterServicesFromAssembly(typeof(LoginCommand).Assembly));

    service.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));

    // 扫描程序集,自动注册泛型处理器
    service.Scan(scan => scan
        .FromAssemblyOf<UpdateServiceHandler<>>()
        .AddClasses(classes => classes.AssignableTo(typeof(IRequestHandler<,>)))
        .AsImplementedInterfaces()
        .WithTransientLifetime()
    );
}

Scrutor会自动识别所有实现IRequestHandler<,>的泛型类,并按开放式泛型的方式注册,无需手动指定具体类型。

方案3:使用Autofac简化泛型注册

如果迁移到Autofac,开放式泛型注册会更简洁:

  1. 安装Autofac相关NuGet包:Install-Package Autofac.Extensions.DependencyInjection
  2. 在Program.cs中配置Autofac作为DI容器:
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
    // 注册MediatR
    containerBuilder.RegisterMediatR(typeof(LoginCommand).Assembly);

    // 注册开放式泛型处理器
    containerBuilder.RegisterGeneric(typeof(UpdateServiceHandler<>))
        .As(typeof(IRequestHandler<UpdateServicePropertyCommand<>, GenericResponseDto>))
        .InstancePerDependency();

    containerBuilder.RegisterGeneric(typeof(UpdateGenericPropertyHandler<,>))
        .As(typeof(IRequestHandler<UpdateGenericPropertyCommand<,>, GenericResponseDto>))
        .InstancePerDependency();

    // 或者自动扫描所有泛型处理器
    containerBuilder.RegisterAssemblyTypes(typeof(LoginCommand).Assembly)
        .AsClosedTypesOf(typeof(IRequestHandler<,>))
        .InstancePerDependency();
});

Autofac的RegisterGeneric和AsClosedTypesOf可以轻松处理开放式泛型注册,AsClosedTypesOf会自动为所有匹配的闭合泛型类型注册对应的处理器。

内容的提问来源于stack exchange,提问作者Antonio Pisarra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:04:54