.NET 6 WebAPI中MediatR无法解析请求处理器的问题求助
.NET 6 WebAPI中MediatR找不到请求处理器的问题排查与解决
错误信息
System.InvalidOperationException: 'No service for type 'MediatR.IRequestHandler`2[CFR.Server.Application.Reporting.Queries.GetAllReportingQuery,CFR.Blazor.Shared.AllReports]' 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 CFR.Server.Controllers.ReportingController.GetAll() in ReportingController.cs:line 29 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.<Execute>d__0.MoveNext()
相关代码
控制器代码
namespace CFR.Server.Controllers { [ApiController] [Authorize] [Route("[controller]")] public class ReportingController : ControllerBase { private readonly IMediator _mediator; public ReportingController(IMediator mediator) { _mediator = mediator; } /// <summary> /// Api endpoint to get all report for issue page /// </summary> /// <returns>AllReports</returns> [HttpGet] public Task<AllReports> GetAll() => _mediator.Send(new GetAllReportingQuery() { }); // 此处崩溃 } }
Startup配置代码
public void ConfigureServices(IServiceCollection services) { services.AddCors(options => options.AddPolicy("AppCORSPolicy", p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader())); services.AddSingleton(new ConnectionString { Value = Configuration.GetConnectionString("Development") }); services.AddControllersWithViews(); services.AddRazorPages(); services.AddHttpContextAccessor(); services.ConfigureAuth(Configuration); services.AddInfrastructure(); services.AddSwaggerGen(); services.AddResponseCompression(); services.AddMediatR(m => m.RegisterServicesFromAssembly(typeof(Program).Assembly)); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v2" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, }); c.AddSecurityRequirement(new OpenApiSecurityRequirement{ { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header, }, new List<string>() } }); }); }
GetAllReportingQuery及处理器代码
namespace CFR.Server.Application.Reporting.Queries { /// <summary> /// Query for [Get] Reporting /// </summary> public class GetAllReportingQuery : IRequest<AllReports> { } /// <summary> /// Handler for GetAllReportingQuery /// </summary> public class GetAllReportingQueryHandler : IRequestHandler<GetAllReportingQuery, AllReports> { private readonly IViewRepository _repository; public GetAllReportingQueryHandler(IViewRepository repository) { _repository = repository; } public async Task<AllReports> Handle(GetAllReportingQuery request, CancellationToken cancellationToken) { // Get each of reporting item reporting results in order var booksIssuedLocations = await _repository.All<BooksIssuedLocation>(); var booksMonthlySummaries = await _repository.All<BooksMonthlySummary>(); var inventoryByLocations = await _repository.All<InventoryByLocation>(); var monthlyComparisonPrior = await _repository.All<MonthlyComparisonPrior>(); var monthlyComparison = await _repository.All<MonthlyComparison>(); var booksIssuedVsClosed = await _repository.Single<BooksIssuedVsClosed>(); var manualVsAutoCloseCount = await _repository.Single<ManualVsAutoCloseCount>(); var errorsToCorrectCount = await _repository.Single<ErrorsToCorrectCount>(); var boxInTransitCount = await _repository.Single<BoxInTransitCount>(); var statusCodeDifferences = await _repository.Single<StatusCodeDifferences>(); var conductorNfCount = await _repository.Single<ConductorNfCount>(); var countConductorNoRemit = await _repository.Single<CountConductorNoRemit>(); var all = new AllReports { BooksIssuedLocations = booksIssuedLocations, BooksIssuedVsClosed = booksIssuedVsClosed, BooksMonthlySummaries = booksMonthlySummaries, InventoryByLocations = inventoryByLocations, // MonthByMonthTotals = await _repository.All<MonthByMonthTotals>(), ManualVsAutoCloseCount = manualVsAutoCloseCount, ErrorsToCorrectCount = errorsToCorrectCount, BoxInTransitCount = boxInTransitCount, StatusCodeDifferences = statusCodeDifferences, ConductorNfCount = conductorNfCount, CountConductorNoRemit = countConductorNoRemit, MonthlyComparisonPrior = monthlyComparisonPrior, MonthlyComparison = monthlyComparison }; return all; } } }
问题原因与解决方案
1. 程序集扫描范围错误
当前AddMediatR使用typeof(Program).Assembly作为扫描目标,但GetAllReportingQueryHandler所在的CFR.Server.Application程序集可能和Program所在程序集不一致(如拆分了类库项目),导致MediatR未扫描到处理器类。
解决方法:
修改扫描配置,指定包含处理器的程序集:
// 方式1:通过处理器类获取对应程序集 services.AddMediatR(m => m.RegisterServicesFromAssembly(typeof(GetAllReportingQueryHandler).Assembly)); // 方式2:多程序集扫描 services.AddMediatR(m => { m.RegisterServicesFromAssembly(typeof(Program).Assembly); m.RegisterServicesFromAssembly(typeof(GetAllReportingQueryHandler).Assembly); });
2. 处理器类识别问题
- 确认
GetAllReportingQueryHandler实现的IRequestHandler泛型参数与查询类、返回类型完全匹配(包括命名空间)。 - 确保处理器类是public访问修饰符,MediatR默认只扫描public类型。
3. DI注册顺序问题
如果AddInfrastructure()或其他扩展方法覆盖了MediatR的注册,会导致处理器未被正确注入。
解决方法:
调整注册顺序,保证AddMediatR在可能影响DI容器的扩展方法之后调用,避免注册被覆盖。
4. 版本兼容性问题
.NET 6建议使用MediatR 12.x及以上版本,旧版本可能与.NET 6的DI系统存在兼容问题。
解决方法:
更新NuGet包:
Install-Package MediatR -Version 12.0.1 Install-Package MediatR.Extensions.Microsoft.DependencyInjection -Version 12.0.1
内容的提问来源于stack exchange,提问作者GettingStarted
相关产品推荐
相关产品推荐

