ASP.NET ExceptionFilter
最后修改于 2025 年 4 月 3 日
在本文中,我们将探讨 ASP.NET 8 中的异常过滤器。异常过滤器提供了一种集中且一致的方式来处理异常。
ASP.NET 是一个跨平台、高性能的框架,用于构建现代 Web 应用程序。异常过滤器有助于跨控制器管理错误处理。
基本定义
ASP.NET 中的异常过滤器是实现 IExceptionFilter 或 IAsyncExceptionFilter 接口的特性。它们会捕获控制器中未处理的异常。
当异常发生在操作执行期间时,异常过滤器可以在异常到达客户端之前拦截它。它们允许自定义错误响应和日志记录。
异常过滤器可以在不同级别应用:全局、控制器范围或特定操作。它们比传统的 try-catch 块提供了更多的控制。
ASP.NET ExceptionFilter 示例
以下示例演示了如何创建和使用自定义异常过滤器。
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.Filters.Add<CustomExceptionFilter>();
});
var app = builder.Build();
app.MapControllers();
app.Run();
这会将我们的 CustomExceptionFilter 全局注册到所有控制器。该过滤器将处理应用程序中的所有未处理异常。
Filters/CustomExceptionFilter.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Net;
public class CustomExceptionFilter : IExceptionFilter
{
private readonly ILogger<CustomExceptionFilter> _logger;
public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
_logger.LogError(context.Exception,
"An unhandled exception occurred");
var problemDetails = new ProblemDetails
{
Title = "An error occurred",
Status = (int)HttpStatusCode.InternalServerError,
Detail = context.Exception.Message,
Instance = context.HttpContext.Request.Path
};
if (context.Exception is ArgumentException)
{
problemDetails.Status = (int)HttpStatusCode.BadRequest;
problemDetails.Title = "Invalid argument";
}
else if (context.Exception is KeyNotFoundException)
{
problemDetails.Status = (int)HttpStatusCode.NotFound;
problemDetails.Title = "Resource not found";
}
context.Result = new ObjectResult(problemDetails)
{
StatusCode = problemDetails.Status
};
context.ExceptionHandled = true;
}
}
此过滤器记录异常并将它们转换为标准化的 ProblemDetails 响应。不同的异常类型会导致不同的 HTTP 状态码。
Controllers/ProductsController.cs
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private static List<Product> _products = new()
{
new Product(1, "Laptop", 999.99m),
new Product(2, "Mouse", 19.99m),
new Product(3, "Keyboard", 49.99m)
};
[HttpGet("{id}")]
public IActionResult GetProductById(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
throw new KeyNotFoundException($"Product with ID {id} not found");
}
return Ok(product);
}
[HttpPost]
public IActionResult CreateProduct([FromBody] Product product)
{
if (product.Price <= 0)
{
throw new ArgumentException("Price must be greater than zero");
}
_products.Add(product);
return CreatedAtAction(nameof(GetProductById),
new { id = product.Id }, product);
}
}
public record Product(int Id, string Name, decimal Price);
控制器会抛出会被我们的过滤器捕获的异常。该过滤器会将这些异常转换为带有 ProblemDetails 的适当 HTTP 响应。
当抛出 KeyNotFoundException 时,过滤器返回 404 状态。对于 ArgumentException,它返回 400。所有其他异常都导致 500 响应。
这种方法集中了错误处理逻辑,同时保持了控制器的代码整洁。该过滤器确保了整个 API 的一致错误响应。
来源
在本文中,我们探讨了 ASP.NET 8 中的异常过滤器。这些强大的过滤器有助于创建具有一致错误处理模式的健壮 API。