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

如何注册MediatR泛型IRequestHandler?已遇服务未注册错误

问题:MediatR泛型处理器注册失败,提示"No service registered"

尝试使用MediatR的泛型IRequestHandler实现通用查询处理器,搭配不同规约返回不同DTO列表,但调用端点时出现错误:No service for type 'MediatR.IRequestHandler2[GetUsersQuery1[UserDto],System.Collections.Generic.List1[UserDto]]' has been registered.`

以下是可复现的代码示例:

核心代码片段

Program.cs

using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") 
                            ?? throw new InvalidOperationException("Connection string is missing");

builder.Services.AddDbContext<IApplicationDbContext, AppDbContext>(options =>
    options.UseNpgsql(connectionString));

// 原注册方式
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapGet("/Users/Adults", ([FromServices] IMediator mediator) =>
{
    return mediator.Send(new GetUsersQuery<UserDto>(new AdultSpecification()));
}).Produces<List<UserDto>>()
.WithName("GetAdultUsers")
.WithOpenApi();

app.MapGet("/Users/GmailAccounts", ([FromServices] IMediator mediator) =>
{
    return mediator.Send(new GetUsersQuery<GmailDto>(new GmailAccountSpecification()));
}).Produces<List<GmailDto>>()
.WithName("GetGmailUsers")
.WithOpenApi();

app.Run();

泛型查询与处理器

// GetUsersQuery.cs
public class GetUsersQuery<T> : IRequest<List<T>> where T : class
{
    public ISpecification<User, T> Specification { get; }

    public GetUsersQuery(ISpecification<User, T> specification)
    {
        Specification = specification;
    }
}

// GetUsersQueryHandler.cs
public class GetUsersQueryHandler<T> : IRequestHandler<GetUsersQuery<T>, List<T>> where T : class
{
    private readonly IApplicationDbContext _context;

    public GetUsersQueryHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<List<T>> Handle(GetUsersQuery<T> request, CancellationToken cancellationToken)
    {
        return await _context.Users
            .WithSpecification(request.Specification).ToListAsync(cancellationToken: cancellationToken);
    }
}

错误信息

Exception has occurred: `CLR/System.InvalidOperationException`
An exception of type `System.InvalidOperationException` occurred in Microsoft.Extensions.DependencyInjection.Abstractions.dll but was not handled in user code: `No service for type 'MediatR.IRequestHandler`2[GetUsersQuery`1[UserDto],System.Collections.Generic.List`1[UserDto]]' has been registered.`
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at MediatR.Wrappers.RequestHandlerWrapperImpl`2.<>c__DisplayClass1_0.<Handle>g__Handler|0()
   at MediatR.Wrappers.RequestHandlerWrapperImpl`2.Handle(IRequest`1 request, IServiceProvider serviceProvider, CancellationToken cancellationToken)
   at MediatR.Mediator.Send[TResponse](IRequest`1 request, CancellationToken cancellationToken)
   at Program.<>c.<<Main>$>b__0_2(IMediator mediator) in /home/hardik/code/dotnet/sample-app/src/Program.cs:line 34

解决方案

原因

MediatR默认的程序集扫描(RegisterServicesFromAssembly)只会自动注册封闭泛型的处理器(即已指定具体类型参数的泛型实现),而GetUsersQueryHandler<T>是开放泛型(未绑定具体T类型),因此无法被自动发现并注册到DI容器中。

修复步骤

在Program.cs的服务注册部分,手动添加开放泛型处理器的注册,替换原有的MediatR注册代码为:

builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
// 手动注册开放泛型查询处理器
builder.Services.AddScoped(typeof(IRequestHandler<GetUsersQuery<>, List<>>), typeof(GetUsersQueryHandler<>));

说明

  • typeof(GetUsersQuery<>)和typeof(List<>)表示开放泛型类型(未指定具体T)
  • 此注册方式告诉DI容器:当需要任何IRequestHandler<GetUsersQuery<T>, List<T>>类型的服务时,使用GetUsersQueryHandler<T>的实例来满足需求
  • 保留原有AddMediatR调用,确保其他非泛型/封闭泛型的MediatR组件仍能被自动注册

修改完成后,重新启动应用,调用/Users/Adults或/Users/GmailAccounts端点即可正常返回数据。


内容的提问来源于stack exchange,提问作者Hardik Dhuri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 11:22:03