8

我目前正在使用 Mediatr 3 中的管道行为进行请求验证。如果发生任何故障,我遇到的所有示例都会抛出 ValidationException,而不是这样做,我想返回带有错误的响应。有人知道怎么做吗?

以下是验证管道的代码:

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

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

    public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
    {
        var failures = _validators
            .Select(v => v.Validate(request))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();

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

        return next();
    }
}

注意:我发现了这个问题使用 CQRS 处理调解器管道中的错误/异常?我对答案的第一个选项感兴趣,但没有明确的例子说明如何做到这一点。

这是我的响应类:

public class ResponseBase : ValidationResult
{
    public ResponseBase() : base() { }

    public ResponseBase(IEnumerable<ValidationFailure> failures) : base(failures)  {
    }
}

我在验证管道类中添加了以下签名:

public class ValidationPipeline<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> 
where TResponse : ResponseBase

然后我在 Handle 方法中这样做了:

var response = new ResponseBase(failures);
return Task.FromResult<TResponse>(response);

但这给了我错误“无法转换为 TResponse”。

4

3 回答 3

4

几年前,我创建了通用的 Result 对象,我正在不断改进它。这很简单,请查看https://github.com/martinbrabec/mbtools

如果您可以接受 Result(或 Result<>)作为应用程序层中每个方法的返回类型,那么您可以像这样使用 ValidationBehavior:

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

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

    public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        if (_validators.Any())
        {
            var context = new ValidationContext(request);

            List<ValidationFailure> failures = _validators
                .Select(v => v.Validate(context))
                .SelectMany(result => result.Errors)
                .Where(f => f != null)
                .ToList();

            if (failures.Any())
            {
                TResponse response = new TResponse();

                response.Set(ErrorType.NotValid, failures.Select(s => s.ErrorMessage), null);

                return Task.FromResult<TResponse>(response);
            }
            else
            {
                return next();
            }
        }

        return next();
    }

}

由于您的所有处理程序都返回 Result(或基于 Result 的 Result<>),因此您将能够处理所有验证错误而不会出现任何异常。

于 2020-05-27T11:25:40.957 回答
3

next如果有任何故障,请不要调用:

public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
    var failures = _validators
        .Select(v => v.Validate(request))
        .SelectMany(result => result.Errors)
        .Where(f => f != null)
        .ToList();

    if (failures.Any())
    {
        var response = new Thing(); //obviously a type conforming to TResponse
        response.Failures = failures; //I'm making an assumption on the property name here.

        return Task.FromResult(response);
    }
    else
    {
        return next();
    }
}

注意:
您的课程(Thing在我的示例中)必须是类型TResponse

于 2017-05-19T08:43:00.353 回答
0

您可以使用包https://www.nuget.org/packages/MediatR.Extensions.FluentValidation.AspNetCore配置验证处理

只需在配置部分插入:

services.AddFluentValidation(new[] {typeof(GenerateInvoiceHandler).GetTypeInfo().Assembly});

GitHub

于 2020-09-04T14:01:28.697 回答