You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中IExceptionHandler未处理特性抛出的ValidationException问题

问题描述

我定义了如下DTO并使用数据注解做验证:

public record CreatorRequestTo(
    [property: JsonPropertyName("id")] 
    long Id,
    
    [property: JsonPropertyName("login")] 
    [StringLength(64, MinimumLength = 2)]
    string Login,
    
    [property: JsonPropertyName("password")] 
    [StringLength(128, MinimumLength = 8)]
    string Password,
    
    [property: JsonPropertyName("firstname")] 
    [StringLength(64, MinimumLength = 2)]
    string FirstName,
    
    [property: JsonPropertyName("lastname")] 
    [StringLength(64, MinimumLength = 2)]
    string LastName
);

发送包含无效数据(比如密码长度小于8位)的POST请求时,预期会触发ValidationException并被自定义全局异常处理器处理,但实际返回的是默认的ProblemDetails响应:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "Password": [
      "The field Password must be a string with a minimum length of 8 and a maximum length of 128."
    ]
  },
  "traceId": "00-af83651d89556659fef605e3689da98f-cffd2070a3d9bc8f-00"
}

自定义全局异常处理器代码如下:

public class GlobalExceptionHandler : IExceptionHandler
{

    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        var errorCode = exception switch
        {
            EntityNotFoundException => (int)HttpStatusCode.BadRequest + "01",
            ValidationException => (int)HttpStatusCode.BadRequest + "02",
            _ => (int)HttpStatusCode.InternalServerError + "00"
        };
        var response = new ErrorResponseTo(exception.Message, errorCode);
        await httpContext.Response.WriteAsJsonAsync(response, cancellationToken);
        return true;
    }
}

Program.cs配置:

...
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();
...
var app = builder.Build();
app.UseExceptionHandler();

我希望返回自定义格式的错误响应:

{
  "errorMessage": "<exception message>",
  "errorCode": 40002
}

请问为什么ValidationException未被自定义处理器捕获?

原因分析

ASP.NET Core中,带有[ApiController]特性的控制器会启用自动模型验证机制:在请求进入Action方法之前,框架会自动校验模型状态,一旦验证失败,会直接返回默认的ProblemDetails响应,不会抛出ValidationException。因此你的全局异常处理器根本没有机会捕获到这个异常。

另外,原处理器中的errorCode存在类型问题:将int类型的状态码与字符串拼接,会生成字符串类型的错误码(比如400+"02"得到"40002"),但你期望的响应中errorCode是数字类型,这会导致序列化后的响应不符合预期。

解决方案

1. 禁用自动模型验证的默认响应

在Program.cs中配置ApiBehaviorOptions,关闭自动返回ProblemDetails的过滤器,让模型验证失败时抛出ValidationException:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        // 禁用自动返回ProblemDetails,触发ValidationException
        options.SuppressModelStateInvalidFilter = true;
    });

builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
// 若不需要默认ProblemDetails功能,可移除AddProblemDetails()
// builder.Services.AddProblemDetails();

var app = builder.Build();
app.UseExceptionHandler();

2. 修正全局异常处理器的错误码逻辑

调整错误码的生成方式,确保返回数字类型的错误码,并设置正确的HTTP状态码:

public class GlobalExceptionHandler : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        var (statusCode, errorCode, errorMessage) = exception switch
        {
            EntityNotFoundException => (HttpStatusCode.BadRequest, 40001, exception.Message),
            ValidationException validationEx => (HttpStatusCode.BadRequest, 40002, validationEx.Message),
            _ => (HttpStatusCode.InternalServerError, 50000, "服务器内部错误")
        };

        // 设置HTTP响应状态码
        httpContext.Response.StatusCode = (int)statusCode;
        
        var response = new ErrorResponseTo(errorMessage, errorCode);
        await httpContext.Response.WriteAsJsonAsync(response, cancellationToken);
        return true;
    }
}

// 确保ErrorResponseTo的属性名称和类型匹配预期响应
public record ErrorResponseTo(string ErrorMessage, int ErrorCode);

3. 验证效果

修改完成后,发送无效数据的POST请求时,框架会抛出ValidationException,全局处理器捕获后会返回你期望的自定义格式响应:

{
  "errorMessage": "One or more validation errors occurred.",
  "errorCode": 40002
}

内容的提问来源于stack exchange,提问作者Kristie _

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 21:58:32