在ASP.NET Core中开发WebAPI时,统一的异常处理是保障接口规范性的重要环节。如果缺少全局异常处理,当接口抛出未捕获的异常时,框架会返回默认的500错误页面或者混乱的JSON数据,前端难以解析,也不利于问题排查。通过C#实现全局异常捕获,可以让所有异常都返回固定格式的错误信息,提升API的易用性和可维护性。

统一错误返回模型定义
首先我们需要定义一个统一的错误返回实体,确保所有异常返回的信息结构一致,方便前端统一处理。
public class ApiErrorResult
{
/// <summary>
/// 错误码,0表示成功,非0表示失败
/// </summary>
public int Code { get; set; }
/// <summary>
/// 错误提示信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 接口返回的时间戳
/// </summary>
public long Timestamp { get; set; }
public ApiErrorResult(int code, string message)
{
Code = code;
Message = message;
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
}
/// <summary>
/// 快速创建服务器内部错误返回实例
/// </summary>
public static ApiErrorResult InternalServerError(string message = "服务器内部错误")
{
return new ApiErrorResult(500, message);
}
}
方式一:使用中间件实现全局异常处理
中间件可以拦截所有进入管道的请求,适合处理全局范围的异常,包括中间件阶段和控制器阶段抛出的异常。
1. 自定义异常处理中间件
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System;
using System.Text.Json;
using System.Threading.Tasks;
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
public GlobalExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
// 执行下一个中间件
await _next(context);
}
catch (Exception ex)
{
// 捕获异常,返回统一错误格式
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
// 默认返回500状态码
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// 可以针对不同类型的异常设置不同的状态码和错误码
var errorResult = ApiErrorResult.InternalServerError(exception.Message);
// 如果是自定义的业务异常,可以调整返回信息
if (exception is BusinessException businessEx)
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
errorResult = new ApiErrorResult(businessEx.ErrorCode, businessEx.Message);
}
var jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
var json = JsonSerializer.Serialize(errorResult, jsonOptions);
await context.Response.WriteAsync(json);
}
}
/// <summary>
/// 自定义业务异常类
/// </summary>
public class BusinessException : Exception
{
public int ErrorCode { get; }
public BusinessException(int errorCode, string message) : base(message)
{
ErrorCode = errorCode;
}
}
2. 注册中间件
在Program.cs中添加中间件注册,注意中间件要放在路由和控制器中间件之前,才能捕获到后续流程的异常。
var builder = WebApplication.CreateBuilder(args); // 添加控制器服务 builder.Services.AddControllers(); var app = builder.Build(); // 注册全局异常处理中间件,放在最前面 app.UseMiddleware<GlobalExceptionMiddleware>(); // 其他中间件 app.UseRouting(); app.MapControllers(); app.Run();
方式二:使用异常过滤器实现异常处理
异常过滤器只针对控制器中的动作方法抛出的异常生效,适合处理MVC/WebAPI场景下的异常,粒度更细。
1. 自定义异常过滤器
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Text.Json;
public class GlobalExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
// 标记异常已处理
context.ExceptionHandled = true;
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
var errorResult = ApiErrorResult.InternalServerError(context.Exception.Message);
// 处理自定义业务异常
if (context.Exception is BusinessException businessEx)
{
context.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
errorResult = new ApiErrorResult(businessEx.ErrorCode, businessEx.Message);
}
var jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
var json = JsonSerializer.Serialize(errorResult, jsonOptions);
context.Result = new ContentResult
{
Content = json,
ContentType = "application/json",
StatusCode = context.HttpContext.Response.StatusCode
};
}
}
2. 注册异常过滤器
在Program.cs中把过滤器添加到控制器配置中。
var builder = WebApplication.CreateBuilder(args);
// 添加控制器并配置全局异常过滤器
builder.Services.AddControllers(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
});
var app = builder.Build();
app.UseRouting();
app.MapControllers();
app.Run();
两种方式的对比与选择
| 对比项 | 中间件方式 | 异常过滤器方式 |
|---|---|---|
| 作用范围 | 整个请求管道,包括中间件和控制器 | 仅控制器中的动作方法 |
| 适用场景 | 需要捕获所有请求的异常,包括静态文件、中间件抛出的异常 | 仅需要处理控制器相关的异常,粒度更细 |
| 优先级 | 更高,先注册先执行 | 较低,属于MVC管道的一部分 |
实际开发中可以根据需求选择,也可以两种方式结合使用,中间件处理全局兜底异常,过滤器处理控制器特定的异常逻辑。
测试验证
我们可以编写一个测试的控制器方法,主动抛出异常验证处理效果。
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class TestController : ControllerBase
{
[HttpGet("normal")]
public IActionResult NormalRequest()
{
return Ok(new { code = 0, message = "请求成功" });
}
[HttpGet("exception")]
public IActionResult ThrowException()
{
// 主动抛出业务异常
throw new BusinessException(1001, "参数校验失败");
}
[HttpGet("system-error")]
public IActionResult SystemError()
{
// 抛出系统异常
throw new NullReferenceException("对象未实例化");
}
}
调用/api/test/exception接口会返回400状态码和自定义错误格式,调用/api/test/system-error会返回500状态码和统一错误信息,符合预期效果。
C#ASP.NET_CoreWebAPI全局异常处理统一返回格式修改时间:2026-06-14 02:15:18