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

.NET Core 7模型验证异常无法被Exception Handler捕获的解决咨询

解决.NET Core 7中模型验证异常无法流入统一异常处理器的问题

问题根源

ASP.NET Core的[ApiController]属性默认会自动处理模型验证失败的情况,直接返回400响应,不会抛出异常,因此你的UseExceptionHandler中间件无法捕获到这类错误。同时,若直接在InvalidModelStateResponseFactory中抛出异常,该工厂方法的执行逻辑不会触发异常处理中间件,而是会被框架直接捕获并返回默认错误。

解决方案一:让模型验证失败抛出异常,复用现有异常处理器

这个方案通过禁用默认模型验证行为,自定义过滤器抛出验证异常,让现有ErrorController统一处理。

  1. 禁用默认模型验证过滤器
    在Program.cs中配置ApiBehaviorOptions,关闭自动处理模型验证的功能:
builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});
  1. 实现自定义验证过滤器
    创建一个ActionFilter,在模型验证失败时抛出包含详细错误的自定义异常:
public class CustomValidationFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            var validationErrors = context.ModelState
                .Where(entry => entry.Value.Errors.Any())
                .ToDictionary(
                    entry => entry.Key,
                    entry => entry.Value.Errors.Select(error => error.ErrorMessage).ToArray()
                );
            throw new CustomValidationException("模型验证失败", validationErrors);
        }
    }

    public void OnActionExecuted(ActionExecutedContext context) { }
}

// 自定义验证异常类
public class CustomValidationException : Exception
{
    public Dictionary<string, string[]> Errors { get; }

    public CustomValidationException(string message, Dictionary<string, string[]> errors) : base(message)
    {
        Errors = errors;
    }
}
  1. 注册自定义过滤器
    在Program.cs的AddControllers中添加这个过滤器:
builder.Services.AddControllers(options =>
{
    options.Filters.Add<CustomValidationFilter>();
});
  1. 在ErrorController中处理自定义验证异常
    修改ErrorController的错误处理方法,加入对CustomValidationException的处理:
// DevError方法
[Route("dev-error")]
public IAttempt DevError()
{
    var context = HttpContext.Features.Get<IExceptionHandlerFeature>();
    var exception = context.Error;

    return exception switch
    {
        CustomValidationException validationEx => Attempt.Fail(validationEx),
        _ => Attempt.Fail(exception)
    };
}

// Error方法
[Route("error")]
public IAttempt Error()
{
    var context = HttpContext.Features.Get<IExceptionHandlerFeature>();
    var exception = context.Error;

    _logger.Log(LogLevel.Error, exception, exception.Message);

    return exception switch
    {
        UnauthorizedAccessException => 
        {
            Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            return Attempt.Fail("Unauthorised");
        },
        CustomValidationException validationEx =>
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Attempt.Fail(validationEx.Errors);
        },
        _ =>
        {
            Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            return Attempt.Fail("Generic Error");
        }
    };
}

解决方案二:重写InvalidModelStateResponseFactory,统一返回IAttempt格式

如果不想抛出异常,可以直接修改模型验证失败的响应格式,使其返回和异常处理器一致的IAttempt结构,实现统一格式输出。

在Program.cs中配置InvalidModelStateResponseFactory:

builder.Services.AddControllers(options =>
{
    options.InvalidModelStateResponseFactory = context =>
    {
        var validationErrors = context.ModelState
            .Where(entry => entry.Value.Errors.Any())
            .ToDictionary(
                entry => entry.Key,
                entry => entry.Value.Errors.Select(error => error.ErrorMessage).ToArray()
            );
        
        var failedAttempt = Attempt.Fail(validationErrors);
        return new JsonResult(failedAttempt)
        {
            StatusCode = (int)HttpStatusCode.BadRequest
        };
    };
});

这种方式不需要修改现有异常处理器,模型验证失败会直接返回符合要求的IAttempt响应,同时保留原有异常处理器处理其他异常的逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:40:33