.NET Core 7 极简 API MediatR IRequest 处理程序映射错误

huangapple go评论71阅读模式
英文:

.NET Core 7 Minimal API MediatR IRequest Handler mapping error

问题

以下是您提供的信息的中文翻译:

我在使用.NET Core 7 Minimal API执行命令时遇到以下错误:

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      执行请求时发生未处理的异常。
      System.InvalidOperationException:构造处理程序时出错,类型为MediatR.IRequestHandler`2[mNet.FileServer.Commands.Core.Application.Features.StoredFileTypes.NewStoredFileType.NewStoredFileTypeCommand,mNet.Common.Core.Application.Commands.BaseCommandResponse`1[mNet.FileServer.Shared.Core.Domain.StoredFileTypes.ValueObjects.StoredFileTypeId]]。请将您的处理程序注册到容器中。请参阅GitHub中的示例。
       ---> System.InvalidOperationException:尚未注册类型为' MediatR.IRequestHandler`2[mNet.FileServer.Commands.Core.Application.Features.StoredFileTypes.NewStoredFileType.NewStoredFileTypeCommand,mNet.Common.Core.Application.Commands.BaseCommandResponse`1[mNet.FileServer.Shared.Core.Domain.StoredFileTypes.ValueObjects.StoredFileTypeId]]' 的服务。
         在Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)中获取所需的服务。
         在MediatR.ServiceFactoryExtensions.GetInstance[T](ServiceFactory factory)中获取实例。
         在MediatR.Wrappers.HandlerBase.GetHandler[THandler](ServiceFactory factory)中获取处理程序。
         --- 内部异常堆栈跟踪的结尾 ---
         在MediatR.Wrappers.HandlerBase.GetHandler[THandler](ServiceFactory factory)中获取处理程序。
         在MediatR.Wrappers.RequestHandlerWrapperImpl`2.<>c__DisplayClass1_0.<Handle>g__Handler|0()中获取处理程序。
         在MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)中处理。
         在MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)中处理。
         在MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)中处理。
         在MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)中处理。
         在MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)中处理。
         在MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)中处理。
         在C:\Users\dcmea\OneDrive\mNet Microservices\mNet.FileServer\mNet.FileServer.Commands.Ui.MinimalApi\Endpoints\StoredFileTypeEndpoint.cs:line 47中的mNet.FileServer.Commands.Ui.MinimalApi.Endpoints.StoredFileTypeEndpoint.NewStoredFileTypeAsync(NewStoredFileTypeDto request, IMediator mediator)中处理。
         在Microsoft.AspNetCore.Http.RequestDelegateFactory.<ExecuteTaskOfT>g__ExecuteAwaited|111_0[T](Task`1 task, HttpContext httpContext)中处理。
         在Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass89_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()中处理。
      --- 上一个位置的堆栈跟踪的结尾 ---
         在Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)中处理。
         在Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)中处理。
         在Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)中处理。
         在Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)中处理。

代码的关键部分位于以下项目中,具体如下:

  • mNet.Common.Core.Application:包含BaseCommandBaseCommandResponse
  • mNet.FileServer.Shared.Core.Domain:包含StoredFileTypeId值对象
  • mNet.FileServer.Commands.Core.Domain:包含StoredFileType聚合
  • mNet.FileServer.Commands.Core.Application:包含NewStoredFileTypeCommandNewStoredFileTypeCommandHandler
  • mNet.FileServer.Commands.Ui.MinimalApi:包含主要的Program.cs和最小API端点

关键类包括:

Program.cs(摘录)

builder.Services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies());

Minimal API端点

private static async Task<BaseCommandResponse<StoredFileTypeId>> NewStoredFileTypeAsync(NewStoredFileTypeDto request, IMediator mediator)
    {
        var messageId = Guid.NewGuid();
        var command = new NewStoredFileTypeCommand
        {
            Id = new MessageId(messageId),
            CorrelationId = new CorrelationId(messageId),
            CausationId = new CausationId(messageId),
            CommandDto = request
        };

        var response = await mediator.Send(command); //错误发生在这个MediatR调用之后,如错误中引用的第47行
        return response;
    }

NewStoredFileTypeCommand

public class NewStoredFileTypeCommand : BaseCommand, IRequest<BaseCommandResponse<StoredFileTypeId>>
{
    public NewStoredFileTypeDto CommandDto { get; init; } = default!;
}

NewStoredFileTypeCommandHandler

public class NewStoredFileTypeCommandHandler : IRequestHandler<NewStoredFileTypeCommand, BaseCommandResponse<StoredFileTypeId>>
{
    private readonly IMapper _mapper;
    private readonly IEventSourcingHandler<StoredFileType, StoredFileTypeId> _eventSourcingHandler;

    public NewStoredFileTypeCommandHandler(IMapper mapper,
        IEventSourcingHandler<StoredFileType, StoredFileTypeId> eventSourcingHandler)
    {
        _mapper = mapper;
        _eventSourcingHandler = eventSourcingHandler;
    }

    public async Task<BaseCommandResponse<StoredFileTypeId>> Handle(NewStoredFileTypeCommand request, CancellationToken cancellationToken)
    {
        var response = new BaseCommandResponse<StoredFileTypeId>();

        var aggregate = new StoredFileType(
            new StoredFileTypeId(Guid.NewGuid()), 
            request.CorrelationId, 
            new CausationId(request.Id.Id),
            request.CommandDto.Name, 
            request.CommandDto.IsImageFileType,
            _mapper.Map<BootstrapIconCode>(request.CommandDto.BootstrapIconCode),
            _mapper.Map<MimeType>(request.CommandDto.MimeType)
            );
        
        await _eventSourcingHandler.SaveAsync(aggregate);

        response.Id = aggregate.Id;
        response.Message = "创建了新的StoredFileType聚合!";
        response.IsSuccessful = true;

        return response;
    }

通过一些调试追踪,

英文:

I am currently getting the following error when executing a command via .NET Core 7 Minimal API:

 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.InvalidOperationException: Error constructing handler for request of type MediatR.IRequestHandler`2[mNet.FileServer.Commands.Core.Application.Features.
StoredFileTypes.NewStoredFileType.NewStoredFileTypeCommand,mNet.Common.Core.Application.Commands.BaseCommandResponse`1[mNet.FileServer.Shared.Core.Domain.StoredFile
Types.ValueObjects.StoredFileTypeId]]. Register your handlers with the container. See the samples in GitHub for examples.
       ---&gt; System.InvalidOperationException: No service for type &#39;MediatR.IRequestHandler`2[mNet.FileServer.Commands.Core.Application.Features.StoredFileTypes.NewS
toredFileType.NewStoredFileTypeCommand,mNet.Common.Core.Application.Commands.BaseCommandResponse`1[mNet.FileServer.Shared.Core.Domain.StoredFileTypes.ValueObjects.S
toredFileTypeId]]&#39; has been registered.
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
         at MediatR.ServiceFactoryExtensions.GetInstance[T](ServiceFactory factory)
         at MediatR.Wrappers.HandlerBase.GetHandler[THandler](ServiceFactory factory)
         --- End of inner exception stack trace ---
         at MediatR.Wrappers.HandlerBase.GetHandler[THandler](ServiceFactory factory)
         at MediatR.Wrappers.RequestHandlerWrapperImpl`2.&lt;&gt;c__DisplayClass1_0.&lt;Handle&gt;g__Handler|0()
         at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
         at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
         at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
         at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
         at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
         at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
         at mNet.FileServer.Commands.Ui.MinimalApi.Endpoints.StoredFileTypeEndpoint.NewStoredFileTypeAsync(NewStoredFileTypeDto request, IMediator mediator) in C:\U
sers\dcmea\OneDrive\mNet Microservices\mNet.FileServer\mNet.FileServer.Commands.Ui.MinimalApi\Endpoints\StoredFileTypeEndpoint.cs:line 47
         at Microsoft.AspNetCore.Http.RequestDelegateFactory.&lt;ExecuteTaskOfT&gt;g__ExecuteAwaited|111_0[T](Task`1 task, HttpContext httpContext)
         at Microsoft.AspNetCore.Http.RequestDelegateFactory.&lt;&gt;c__DisplayClass89_2.&lt;&lt;HandleRequestBodyAndCompileRequestDelegateForJson&gt;b__2&gt;d.MoveNext()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Routing.EndpointMiddleware.&lt;Invoke&gt;g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
         at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
         at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

The key parts of the code are in the following projects and are as follows:

  • mNet.Common.Core.Application: Contains the BaseCommand and BaseCommandResponse classes
  • mNet.FileServer.Shared.Core.Domain: Contains the StoredFileTypeId value object
  • mNet.FileServer.Commands.Core.Domain: Contains the StoredFileType aggregate
  • mNet.FileServer.Commands.Core.Application: Contains the NewStoredFileTypeCommand and NewStoredFileTypeCommandHandler classes
  • mNet.FileServer.Commands.Ui.MinimalApi: Contains the main Program.cs and minimal api endpoints

The key classes are:

Program.cs (extract)

builder.Services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies());

Minimal Api Endpoint

private static async Task&lt;BaseCommandResponse&lt;StoredFileTypeId&gt;&gt; NewStoredFileTypeAsync(NewStoredFileTypeDto request, IMediator mediator)
    {
        var messageId = Guid.NewGuid();
        var command = new NewStoredFileTypeCommand
        {
            Id = new MessageId(messageId),
            CorrelationId = new CorrelationId(messageId),
            CausationId = new CausationId(messageId),
            CommandDto = request
        };

        var response = await mediator.Send(command); //Error happens after this MediatR call and is line 47 as referenced in the error
        return response;

    }

NewStoredFileTypeCommand

public class NewStoredFileTypeCommand : BaseCommand, IRequest&lt;BaseCommandResponse&lt;StoredFileTypeId&gt;&gt;
{
    public NewStoredFileTypeDto CommandDto { get; init; } = default!;
}

NewStoredFileTypeCommandHandler

public class NewStoredFileTypeCommandHandler : IRequestHandler&lt;NewStoredFileTypeCommand, BaseCommandResponse&lt;StoredFileTypeId&gt;&gt;
{
    private readonly IMapper _mapper;
    private readonly IEventSourcingHandler&lt;StoredFileType, StoredFileTypeId&gt; _eventSourcingHandler;

    public NewStoredFileTypeCommandHandler(IMapper mapper,
        IEventSourcingHandler&lt;StoredFileType, StoredFileTypeId&gt; eventSourcingHandler)
    {
        _mapper = mapper;
        _eventSourcingHandler = eventSourcingHandler;
    }

    public async Task&lt;BaseCommandResponse&lt;StoredFileTypeId&gt;&gt; Handle(NewStoredFileTypeCommand request, CancellationToken cancellationToken)
    {
       var response = new BaseCommandResponse&lt;StoredFileTypeId&gt;();

        var aggregate = new StoredFileType(
            new StoredFileTypeId(Guid.NewGuid()), 
            request.CorrelationId, 
            new CausationId(request.Id.Id),
            request.CommandDto.Name, 
            request.CommandDto.IsImageFileType,
            _mapper.Map&lt;BootstrapIconCode&gt;(request.CommandDto.BootstrapIconCode),
            _mapper.Map&lt;MimeType&gt;(request.CommandDto.MimeType)
            );
        
        await _eventSourcingHandler.SaveAsync(aggregate);

        response.Id = aggregate.Id;
        response.Message = $&quot;Created new {nameof(StoredFileType)} aggregate!&quot;;
        response.IsSuccessful = true;

        return response;


    }

From doing a few debug traces, it seems like MediatR isn't mapping the NewStoredFileTypeCommandHandler to the NewStoredFileTypeCommand and I cannot work out why.

Also, as I have declared AppDomain.CurrentDomain.GetAssemblies() in Program.cs, it shouldn't be the scope.

Any ideas would be massively appreciated as it's driving me mad!

答案1

得分: 3

我的猜测基于AppDomain.GetAssemblies文档中的以下引用:

获取已加载到此应用程序域的执行上下文中的程序集。

有可能对应的程序集尚未加载到应用程序域中。尝试使用AddMediatr并提供包含 Mediatr 组件的程序集/类型:

// 使用每个包含 MediatR 组件的程序集的类型
builder.Services.AddMediatR(typeof(NewStoredFileTypeCommandHandler), typeof(BaseCommand), ...);
英文:

My guess relies on the following quote from the docs for AppDomain.GetAssemblies:

> Gets the assemblies that have been loaded into the execution context of this application domain.

There is a chance that the corresponding assembly has not yet been loaded into the app domain. Try using the AddMediatr and providing assemblies/types from the assemblies storing mediatr parts:

// use a type per assembly containing the MediatR components
builder.Services.AddMediatR(typeof(NewStoredFileTypeCommandHandler), typeof(BaseCommand), ...);

huangapple
  • 本文由 发表于 2023年2月14日 08:15:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75442350.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定