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

WebAPI中如何在MVC范围内处理Action与Filter的ApiException异常?

在ASP.NET Core WebAPI中统一捕获所有自定义异常(含Filter场景)

要在不脱离MVC管道、同时遵循Accept头和OutputFormatters规范的前提下,捕获Action及各类Filter(如IAuthorizationFilter、ActionFilterAttribute)抛出的自定义ApiException,最佳方案是结合UseExceptionHandler中间件与MVC错误处理Action,既覆盖全管道异常捕获,又复用MVC的内容协商和格式化能力。

实现步骤

1. 定义自定义ApiException

先明确你的自定义异常结构,包含响应所需的状态码、详情等字段:

public class ApiException : Exception
{
    public int StatusCode { get; }
    public string? Details { get; }

    public ApiException(string message, int statusCode, string? details = null)
        : base(message)
    {
        StatusCode = statusCode;
        Details = details;
    }
}

2. 创建MVC错误处理Controller

编写专门的错误处理Action,利用MVC管道自动处理内容协商(根据Accept头返回对应格式):

[ApiController]
[Route("api/error")]
[AllowAnonymous] // 确保异常处理路由不受授权限制
public class ErrorController : ControllerBase
{
    [HttpGet]
    [HttpPost]
    [HttpPut]
    [HttpDelete]
    [HttpPatch]
    public IActionResult HandleError()
    {
        var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
        var exception = exceptionFeature?.Error;

        // 处理自定义ApiException
        if (exception is ApiException apiEx)
        {
            var problemDetails = new ProblemDetails
            {
                Status = apiEx.StatusCode,
                Title = apiEx.Message,
                Detail = apiEx.Details,
                Instance = exceptionFeature?.Path
            };
            // 添加追踪ID方便排查
            problemDetails.Extensions.Add("traceId", HttpContext.TraceIdentifier);

            return new ObjectResult(problemDetails)
            {
                StatusCode = apiEx.StatusCode
            };
        }

        // 处理未预期的系统异常
        var defaultProblem = new ProblemDetails
        {
            Status = StatusCodes.Status500InternalServerError,
            Title = "服务器内部错误",
            Detail = "发生了未预期的异常",
            Instance = exceptionFeature?.Path
        };
        defaultProblem.Extensions.Add("traceId", HttpContext.TraceIdentifier);

        return new ObjectResult(defaultProblem)
        {
            StatusCode = StatusCodes.Status500InternalServerError
        };
    }
}

3. 配置异常处理中间件

在Program.cs中,将UseExceptionHandler放在所有业务中间件之前,指定错误处理Action的路由:

var builder = WebApplication.CreateBuilder(args);

// 添加MVC服务,自动包含所有OutputFormatters
builder.Services.AddControllers();

var app = builder.Build();

// 异常处理中间件:捕获全管道异常,转发到MVC错误处理Action
app.UseExceptionHandler("/api/error");

// 其他业务中间件(授权、路由等)
app.UseAuthorization();
app.MapControllers();

app.Run();

4. 验证Filter场景

以IAuthorizationFilter为例,测试异常捕获:

public class CustomAuthFilter : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        // 模拟授权失败抛出异常
        if (!context.HttpContext.User.Identity.IsAuthenticated)
        {
            throw new ApiException("未授权访问", StatusCodes.Status401Unauthorized);
        }
    }
}

在Controller上应用该过滤器:

[ApiController]
[Route("api/test")]
[TypeFilter(typeof(CustomAuthFilter))]
public class TestController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        // 模拟Action抛出异常
        throw new ApiException("参数无效", StatusCodes.Status400BadRequest);
    }
}

方案优势

  • 覆盖全场景:UseExceptionHandler在管道早期执行,能捕获授权过滤器、动作过滤器、Action执行等全阶段抛出的异常。
  • 遵循MVC规范:通过MVC错误处理Action返回响应,自动利用OutputFormatters处理内容协商,完美适配Accept头要求。
  • 自定义响应灵活:可根据异常类型构造符合业务需求的响应格式,同时遵循RFC 7807的ProblemDetails规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:35:30