MediatR 管道行为的流畅验证响应

问题描述 投票:0回答:3

我有一个 MediatR Pipeline 行为,用于使用 FluentValidation 库验证命令。我见过很多从行为中抛出 ValidationException 的例子,这对我来说效果很好。但是,在我的场景中,我想使用验证错误更新我的响应对象。

我能够构建并运行以下代码。当我在 if 语句中设置断点时,CommandResponse 会按预期使用验证错误构建 - 但当原始调用者收到响应时,它为 null:

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

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

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

        // Run the associated validator against the request
        var failures = _validators
            .Select(v => v.Validate(context))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();

        if(failures.Count != 0)
        {
            var commandResponse = new CommandResponse(failures) { isSuccess = false };
            return commandResponse as Task<TResponse>;
        }
        else
        {   
            return next();
        }
    }
}

我认为这与我尝试将其转换为任务有关 - 但如果没有这个,我会遇到编译器错误。如果验证通过,我将返回与命令处理程序相同的类型,因此我不知道为什么它会返回预期响应的空实例。我觉得有更好的方法来处理这个问题,但我尝试了多种变体但无济于事。有什么建议么?有更好的模式可以使用吗?我更愿意将其保留在管道中,因为它将被多次重复使用。

c# asp.net-core cqrs fluentvalidation mediatr
3个回答
10
投票

我最终向 MVC 项目添加了异常处理中间件。我没有尝试将验证错误作为对象传回,而是在管道行为内部抛出 ValidationException,中间件会处理整个项目中的所有异常。这实际上效果更好,因为我在处理链中较高的一个位置处理所有异常。

这是我发布的代码的更新部分:

if(failures.Count != 0)
{
    // If any failures are found, throw a custom ValidationException object
    throw new ValidationException(failures);
}
else
{   
    // If validation passed, allow the command or query to continue:
    return next();
}

这是异常处理中间件:

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate next;

    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context /* other dependencies */)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex);
        }
    }


    private static Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        // Log issues and handle exception response

        if (exception.GetType() == typeof(ValidationException))
        {
            var code = HttpStatusCode.BadRequest;
            var result = JsonConvert.SerializeObject(((ValidationException)exception).Failures);
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)code;
            return context.Response.WriteAsync(result);

        }
        else
        {
            var code = HttpStatusCode.InternalServerError;
            var result = JsonConvert.SerializeObject(new { isSuccess = false, error = exception.Message });
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)code;
            return context.Response.WriteAsync(result);
        }
    }
}

然后在添加 MVC 之前在 Startup 中注册中间件:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMiddleware(typeof(ErrorHandlingMiddleware));
    app.UseMvc();
}

注意: 您还可以为您的中间件创建扩展方法:

public static class ErrorHandlingMiddlewareExtension
{
    public static IApplicationBuilder UseErrorHandlingMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ErrorHandlingMiddleware>();
    }
}

这允许您像这样注册它:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseErrorHandlingMiddleware();
    app.UseMvc();
}

1
投票

我正在使用.Net core 3.1,当我在

Configure
Startup

函数中的以下块之前添加中间件时,我无法捕获异常
  if (env.IsDevelopment())          
  {
    app.UseDeveloperExceptionPage();
  }

检查配置方法。确保在上述语句之后注册它。这是很明显的,但可能会帮助像我这样的人。

 if (env.IsDevelopment())
 {
    app.UseDeveloperExceptionPage();
 }
 app.UseMiddleware<ErrorHandlingMiddleware>(); 

0
投票

我认为您使用的 FluentValidation.AspNetCore 高于 8.0 有一些更改尝试使用 var context = new ValidationContext(请求); 它对我有用,祝你好运

© www.soinside.com 2019 - 2024. All rights reserved.