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
相关产品推荐
相关产品推荐

