Валидатор команды FluentValidation не зарегистрирован AutoFac - PullRequest
0 голосов
/ 20 января 2019

Я уже давно борюсь с проблемой. Я строю проект на основе проекта 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();
    }
}

У меня есть следующие проблемы:

  1. Всякий раз, когда я пытаюсь вызвать этот API, я получаю следующую ошибку:

    Невозможно разрешить параметр «MediatR.IMediator mediator» конструктора «Void .ctor (MediatR.IMediator)».

Я решаю эту проблему, добавляя медиатор в качестве службы, используя .AddMediatR(), хотя в примере проекта он никогда не добавляется таким образом.

  1. После добавления медиатора 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 .

Может кто-нибудь помочь мне понять, что я делаю не так? Это сводило меня с ума в последние несколько дней.

1 Ответ

0 голосов
/ 17 мая 2019

У меня такая же конфигурация, как и у вас.Единственное отличие, которое я могу найти - это строки в моем файле start.cs

public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc()
                .AddFluentValidation(fv =>
                {
                    fv.RegisterValidatorsFromAssemblyContaining<MediatorModule>();
                    fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
                }
            );
}
...