来自管道行为的 MediatR 流畅验证响应
MediatR fluent validation response from pipeline behavior
我有一个 MediatR 管道行为,用于使用 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();
}
}
}
我认为这与我尝试将其转换为任务有关 - 但如果没有这个,我会遇到编译器错误。如果验证通过,我将返回与我的命令处理程序相同的类型,所以我不知道为什么它 returns 是预期响应的空实例。我觉得有更好的方法来处理这个问题,但我尝试了多种变体都无济于事。有什么建议么?有没有更好的模式可以使用?我更愿意将其保留在管道中,因为它将被多次重复使用。
我最终将异常处理中间件添加到 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();
}
我正在使用 .Net core 3.1,当我在 Startup
的 Configure
函数中的以下块之前添加中间件时,我无法捕获异常
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
检查配置方法。确保在上述声明之后注册它。这很明显,但可能会帮助像我这样的人。
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ErrorHandlingMiddleware>();
我有一个 MediatR 管道行为,用于使用 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();
}
}
}
我认为这与我尝试将其转换为任务有关 - 但如果没有这个,我会遇到编译器错误。如果验证通过,我将返回与我的命令处理程序相同的类型,所以我不知道为什么它 returns 是预期响应的空实例。我觉得有更好的方法来处理这个问题,但我尝试了多种变体都无济于事。有什么建议么?有没有更好的模式可以使用?我更愿意将其保留在管道中,因为它将被多次重复使用。
我最终将异常处理中间件添加到 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();
}
我正在使用 .Net core 3.1,当我在 Startup
Configure
函数中的以下块之前添加中间件时,我无法捕获异常
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
检查配置方法。确保在上述声明之后注册它。这很明显,但可能会帮助像我这样的人。
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ErrorHandlingMiddleware>();