我有一个。net 6 WebApi,我正在使用MediatR的Fluent验证。当没有验证错误时,我的一切都在工作。
当我强制执行错误时,我得到以下Exception:
Unable to cast object of type 'System.Collections.Generic.Dictionary`2[System.String,System.String[]]' to type 'System.Collections.Generic.IEnumerable`1[FluentValidation.Results.ValidationFailure]'.
at TestMediatR.Behaviours.ValidationBehaviour`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at WebApi.Controllers.v1.OrdersController.AddOrder(OrderTicketDto model) in D:Git RepositoriesCurrentWeb-SitesRestWebApisrcWebApiControllersv1OrdersController.cs:line 36
执行mediatR send的代码如下:
[HttpPost("AddOrder")]
public async Task<IActionResult> AddOrder([FromBody] OrderTicketDto model)
{
_logger.LogInformation("Adding Order: {@model}", model);
try
{
var response = await Mediator.Send(new AddOrderCommand()
{
OrderData = model.OrderTicket,
Url = model.SiteUrl,
Token = model.Token
});
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Add Order Error"); //<------ FluentValidation exception caught here
return BadRequest(ex.Message);
}
}
,上面执行的命令的验证是这样完成的
public class AddOrderCommandValidator : AbstractValidator<AddOrderCommand>
{
public AddOrderCommandValidator()
{
RuleFor(x => x.Url)
.NotEmpty()
.NotNull();
RuleFor(x => x.Token)
.NotEmpty()
.NotNull();
RuleFor(x => x.OrderData)
.NotNull();
}
}
验证器的注册在startup
中完成public static IServiceCollection AddPiKSRestValidators(this IServiceCollection services)
{
var domainAssembly = typeof(GetTablesCommandValidator).GetTypeInfo().Assembly;
//Add FluentValidation
services.AddValidatorsFromAssembly(domainAssembly);
return services;
}
正如我所说的,当我传递有效的属性时,一切都工作,但通过设置说Token
属性为null来强制它无效,我得到异常。
感觉我错过了什么。
问题出在validationbehavior
下面是报告错误的代码public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull, IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
private readonly ILogger<TRequest> _logger;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators, ILogger<TRequest> logger)
{
_validators = validators;
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var errorsDictionary = _validators
.Select(x => x.Validate(context))
.SelectMany(x => x.Errors)
.Where(x => x != null)
.GroupBy(
x => x.PropertyName,
x => x.ErrorMessage,
(propertyName, errorMessages) => new
{
Key = propertyName,
Values = errorMessages.Distinct().ToArray()
})
.ToDictionary(x => x.Key, x => x.Values);
if (errorsDictionary.Any())
{
throw new ValidationException((IEnumerable<FluentValidation.Results.ValidationFailure>)errorsDictionary);
}
}
else
_logger.LogDebug("No Validators found");
return await next();
}
}
正如你所看到的,一个字典正试图被强制转换为(IEnumerable
修复。
var errorsDictionary = _validators
.Select(x => x.Validate(context))
.SelectMany(x => x.Errors)
.Where(x => x != null)
.GroupBy(x => new {x.PropertyName, x.ErrorMessage })
.Select(x => x.FirstOrDefault())
.ToList();
if (errorsDictionary.Any())
{
throw new ValidationException(errorsDictionary);
}