如何重抛FluentValidation异常并解决其报错后ErrorHandlingMiddleware不执行的问题?
问题根因
当前FluentValidation未触发ErrorHandlingMiddleware的核心原因:
- 配置的
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false仅会关闭MVC原生数据注解的校验逻辑,FluentValidation完成校验后,依然会把错误信息写入ModelState,由MVC内置的API行为逻辑直接生成400响应,全程不会抛出可被管道中间件捕获的ValidationException,错误根本不会传递到错误处理中间件层。 - 部分场景下还存在中间件注册顺序错误:如果
ErrorHandlingMiddleware注册在MVC端点映射的下游,就算有异常抛出,也无法被中间件捕获。
实现方案
1. 调整服务配置,将ModelState校验错误转为抛出异常
在现有AddMvc的配置链上追加ConfigureApiBehaviorOptions配置,把原本被MVC内置捕获的模型校验错误(含FluentValidation写入的错误)直接组装成ValidationException向上抛出,让异常沿管道传递到错误处理中间件:
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest) .AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; }) .AddFluentValidation(fv => { fv.RegisterValidatorsFromAssemblyContaining<LoginValidator>(); fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false; }) .ConfigureApiBehaviorOptions(options => { // 替换默认的400响应生成逻辑 options.InvalidModelStateResponseFactory = context => { // 提取ModelState中存储的所有FluentValidation校验错误 var validationFailures = context.ModelState .Where(entry => entry.Value.Errors.Any()) .SelectMany(entry => entry.Value.Errors .Select(err => new ValidationFailure(entry.Key, err.ErrorMessage))) .ToList(); // 直接抛出FluentValidation的ValidationException,异常将沿管道向上传递 throw new ValidationException(validationFailures); }; });
注意:此处抛出的
ValidationException必须使用FluentValidation命名空间下的类型,和你HandleMessage方法中switch匹配的异常类型保持完全一致,否则会命中全局异常的默认分支。
2. 核对请求管道的中间件注册顺序
ASP.NET Core管道的执行规则为:从上到下注册的组件依次处理请求,从下到上处理抛出的异常。必须保证ErrorHandlingMiddleware注册在MVC端点映射的上游(也就是代码顺序上写在UseEndpoints之前),才能捕获到MVC层抛出的异常。正确的注册顺序参考:
// 错误处理中间件放在最上游,最先注册 app.UseMiddleware<ErrorHandlingMiddleware>(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // MVC端点映射在下游,异常从这里向上传递 app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
3. 触发链路验证
完成上述配置后,当FluentValidation检测到校验规则不通过时的完整链路为:
- 模型绑定阶段把校验错误写入
ModelState - 自定义的
InvalidModelStateResponseFactory捕获这些错误,抛出ValidationException - 异常沿管道向上传递,被
ErrorHandlingMiddleware捕获,命中预定义的ValidationException分支,生成统一格式的错误响应
补充说明
- 现有FluentValidation的注册逻辑本身无问题,不需要额外调整
- FluentValidation官方集成模式下的校验错误默认是作为模型校验结果返回,不是未处理异常,不要依赖默认行为触发异常
- 场景中如果存在手动调用校验器的逻辑,校验失败后可以直接抛出
ValidationException,同样能被中间件捕获,不需要额外适配逻辑
内容的提问来源于stack exchange,提问作者user8753842
相关产品推荐
相关产品推荐

