В настоящее время я получаю следующую ошибку при выполнении команды через .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.
---> System.InvalidOperationException: No service for type '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]]' 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.<>c__DisplayClass1_0.<Handle>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.<ExecuteTaskOfT>g__ExecuteAwaited|111_0[T](Task`1 task, HttpContext httpContext)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass89_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>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)
Ключевые части кода находятся в следующих проектах и заключаются в следующем:
BaseCommand
и BaseCommandResponse
.StoredFileTypeId
.StoredFileType
NewStoredFileTypeCommand
и NewStoredFileTypeCommandHandler
.Program.cs
и минимальные конечные точки API.Ключевые классы:
Program.cs (извлечение)
builder.Services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies());
Минимальная конечная точка 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); //Error happens after this MediatR call and is line 47 as referenced in the error
return response;
}
Ньюсторедфилетипекомманд
public class NewStoredFileTypeCommand : BaseCommand, IRequest<BaseCommandResponse<StoredFileTypeId>>
{
public NewStoredFileTypeDto CommandDto { get; init; } = default!;
}
Ньюсторедфилетипекоммандхандлер
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 = $"Created new {nameof(StoredFileType)} aggregate!";
response.IsSuccessful = true;
return response;
}
Судя по нескольким отладочным трассировкам, кажется, что MediatR не сопоставляет NewStoredFileTypeCommandHandler с NewStoredFileTypeCommand, и я не могу понять, почему.
Кроме того, как я объявил AppDomain.CurrentDomain.GetAssemblies() в Program.cs, это не должно быть областью действия.
Любые идеи будут оценены по достоинству, так как это сводит меня с ума!
Мое предположение основано на следующей цитате из документации для AppDomain.GetAssemblies:
Получает сборки, которые были загружены в контекст выполнения этого домена приложения.
Есть вероятность, что соответствующая сборка еще не загружена в домен приложения. Попробуйте использовать AddMediatr и предоставить сборки/типы из сборок, хранящих части mediatr:
// use a type per assembly containing the MediatR components
builder.Services.AddMediatR(typeof(NewStoredFileTypeCommandHandler), typeof(BaseCommand), ...);
@dmeadley - рад был помочь! Если ответ работает для вас - смело отмечайте его как принятый) "Есть ли способ принудительно загрузить сборки" - да, вам нужно использовать тип из него). «Будет мучительно добавлять эту строку для каждого обработчика команд» - насколько я знаю, вам это не нужно, вам нужна только одна сборка (насколько я помню, Mediatr использует тип, чтобы получить свою сборку и загрузить все необходимое компоненты Mediatr).
Спасибо за это @Guru Stron. Я посмотрю, как я могу использовать тип из него при загрузке, чтобы мне не приходилось помнить о добавлении одного на сборку.
@dmeadley typeof(SomeType) - на самом деле это использование. Я бы рекомендовал придерживаться кода в ответе, потому что не будет никакой разницы с точки зрения «необходимости помнить». А использование типов для загрузки сборки перед AddMediatR — довольно хрупкий подход (зависит от порядка, поведения во время выполнения и т. д.). Я бы сказал, что подход AddMediatR с одним типом на сборку намного чище и удобнее в сопровождении.
Спасибо - это сработало отлично! Есть ли способ принудительно загрузить сборки? Будет сложно добавить эту строку для каждого обработчика команд.