.net 未在MediatR管道中调用FluentValidation

8wigbo56  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(105)

我正在使用:MediatR 12.1.1 FluentValidation 11.6.0
我创建了我的验证器:

internal class CreateTemplateCommandValidator : AbstractValidator<CreateTemplateCommand>
{
    public CreateTemplateCommandValidator(ITemplateRepository templateRepository)
    {
        RuleFor(template => template.Name)
            .NotEmpty()
            .DependentRules(() =>
        {
            RuleFor(template => template.Name)
                .MustAsync(async (name, token) => !(await templateRepository.NameExists(name)))
                .WithMessage("Name must be unique.");
        });
    }
}

字符串
我希望通过MediatR管道处理验证。这是我的ValidationBehavior类:

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)

    {
        var context = new ValidationContext<TRequest>(request);

        var failures = _validators
            .Select(validator => validator.Validate(context))
            .SelectMany(result => result.Errors)
            .Where(failure => failure is not null)
            .ToList();

        if (failures.Any())
        {
            throw new ValidationException(failures);
        }

        return await next();
    }
}


我还注册了这些:

services.AddMediatR(cfg =>
        {
            cfg.RegisterServicesFromAssembly(typeof(Extension).Assembly);
        });

        services.AddValidatorsFromAssemblyContaining(typeof(Extension));
        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));


不幸的是,验证器从未被调用。我被卡住了,因为我在其他地方找不到答案,似乎我已经正确地遵循了模式-我错过了什么?

x4shl7ld

x4shl7ld1#

你的验证器是内部的。您需要将DI更改为:

services.AddValidatorsFromAssemblyContaining(typeof(Extension), includeInternalTypes: true);

字符串
我还建议使用:

services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Extension).Assembly);
    cfg.AddOpenBehavior(typeof(ValidationBehavior<,>)
});


你的方法:

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));


最后,在重现您的问题时,我发现了另一个您将在应用此修复时发现的错误:

Unhandled exception. FluentValidation.AsyncValidatorInvokedSynchronouslyException: Validator "CreateTemplateCommandValidator" contains asynchronous rules but was invoked synchronously. Please call ValidateAsync rather than Validate.


我建议使用System.Linq.Async并将验证代码更改为:

var failures = _validators
    .ToAsyncEnumerable()
    .SelectAwait(async validator => await validator.ValidateAsync(context))
    .ToEnumerable()
    .SelectMany(result => result.Errors)
    .Where(failure => failure is not null)
    .ToList();

相关问题