我正在使用: 媒体R 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<,>));
不幸的是,验证器从未被调用。 我陷入困境,因为我在其他地方找不到答案,似乎我已经正确遵循了模式 - 我错过了什么?
您的验证器是内部的。 您需要将 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();