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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 05:25:39