Я уже давно борюсь с проблемой. Я строю проект на основе проекта eShopOnContainers GitHub См. Здесь . Мой проект работает на ядре asp.net 2.2, и я использую
MediatR 6.0,
- MediatR 6.0
- MediatR.Extensions.Microsoft.DependencyInjection 6.0.1
- FluentValidation.AspNetCore 8.1.2
- Autofac.Extensions.DependencyInjection 4.3.1
Я использую команды MediatR, которые обрабатываются обработчиком команд, и во многих статьях, наряду с примером eShopOnContainers, я реализовал класс ValidatorBehavior
, который реализует IPipelineBehavior
.
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidatorBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var context = new ValidationContext(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(error => error != null)
.ToList();
if (failures.Any())
{
throw new PlanningDomainException(
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
}
var response = await next();
return response;
}
}
Я также включил MediatorModule, как это реализовано в примере проекта.
public class MediatorModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(typeof(IMediator).GetType().Assembly)
.AsImplementedInterfaces();
// Get the assembly name
var assembly = typeof(Startup).GetType().Assembly;
// Register all the Command classes (they implement IRequestHandler) in assembly holding the Commands
builder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(IRequestHandler<,>));
// Register the DomainEventHandler classes (they implement INotificationHandler<>)
// in assembly holding the Domain Events
builder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(INotificationHandler<>));
// Register the Command's Validators (Validators based on FluentValidation library)
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces();
builder.Register<ServiceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; };
});
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(TransactionBehaviour<,>)).As(typeof(IPipelineBehavior<,>));
}
}
Мой тестовый контроллер:
[Route("api/[controller]")]
[ApiController]
public class ApplicationsController : ControllerBase
{
private readonly IMediator _mediator;
public ApplicationsController(IMediator mediator)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}
[HttpPost]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Put([FromBody]ApplicationCreateCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{
var c = await _mediator.Send(command);
return c ? Ok() : (IActionResult)BadRequest();
}
}
У меня есть следующие проблемы:
Всякий раз, когда я пытаюсь вызвать этот API, я получаю следующую ошибку:
Невозможно разрешить параметр «MediatR.IMediator mediator» конструктора «Void .ctor (MediatR.IMediator)».
Я решаю эту проблему, добавляя медиатор в качестве службы, используя .AddMediatR()
, хотя в примере проекта он никогда не добавляется таким образом.
- После добавления медиатора API работает правильно, команда отправляется, а обработанная команда обрабатывает ее правильно. Между тем,
ValidatorBehavior
вызывается правильно, но CommandValidator отсутствует. Список _validators
фактически пуст, поэтому проверка не выполняется.
Я также установил точки останова в валидаторе команд, но ни одна не попала.
Это мой валидатор команд:
public class ApplicationCreateCommandValidator : AbstractValidator<ApplicationCreateCommand>
{
public ApplicationCreateCommandValidator()
{
RuleFor(cmd => cmd.CategoryType).NotEmpty().Must(BeValidCategoryType).WithMessage("The category type is not valid.");
RuleFor(cmd => cmd.CompetitionId).NotEmpty().WithMessage("The competition id must be specified.");
RuleFor(cmd => cmd.ParticipantId).NotEmpty().WithMessage("The participant id must be specified.");
}
private bool BeValidCategoryType(int categoryType)
{
return categoryType != 0;
}
}
Все должно работать нормально! Я не понимаю, почему это не так. Возможно, я неправильно загружаю валидаторы команд в autofac, однако каждый пример кода, который я нашел в сети, указывает на один и тот же метод регистрации:
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces();
У меня есть весь исходный код этого проекта в моей учетной записи git hub, если вы хотите поближе взглянуть. Это API .
Может кто-нибудь помочь мне понять, что я делаю не так? Это сводило меня с ума в последние несколько дней.