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

ASP.NET Core Web API异常处理方案咨询:两种主流方式解析

ASP.NET Core Web API 异常与意外结果处理方案探讨

尽管这是个偏主观的问题,但我还是想了解大家在ASP.NET Core Web API中处理异常或意外结果时的常用方案。目前我了解到两种主流思路,说不定还有更优的选择:

1. 结果模式

异常不在控制器层处理,而是由服务层统一处理。控制器方法签名为ActionResult<Result<T>>,其中T代表资源/数据对象,Result<T>是一个包装类,包含Errors、ResultType等附加字段来标识结果状态。

示例代码:

// BlogPostsController.cs
...
private readonly IBlogPostsService _service;

[HttpGet]
public async Task<ActionResult<Result<BlogPost>>> GetPostById(Guid postId) 
{
    var result = await _service.GetPostById(postId);
    return result.ResultType switch 
    {
         ResultType.NotFound   => NotFound(result),
         ResultType.Ok         => Ok(result),
         ResultType.Unexpected => BadRequest(result)
    };
}

2. 自定义异常+全局中间件模式

异常不在控制器层处理,由服务层根据业务场景抛出自定义异常,再通过全局中间件统一捕获并处理,将异常转换为标准的HTTP响应。

控制器代码

// BlogPostsController.cs
...
private readonly IBlogPostsService _service;

[HttpGet]
public async Task<IActionResult> GetPostById(Guid postId) 
{
    return await _service.GetPostById(postId);
}

服务层代码

// BlogPostsService.cs
public async Task<BlogPost?> GetPostById(Guid postId) 
{
    var post = await _db.Where(post => post.Id == postId).SingleOrDefaultAsync();
    if (post == null)
       throw new PostNotFoundException($"Post {postId} not found");
    return post;
}

异常处理中间件代码

// ExceptionMiddleware.cs
public async Task Invoke(HttpContext context) 
{
    try
    {
        await _next(context);
    }
    catch (PostNotFoundException) 
    {
        var details = new ExceptionDetails()
        {
             Status = 404,
             Detail = "Post does not exist"
        };
        await context.Response.WriteAsync(JsonConvert.SerializeObject(details));
    }
    // 可添加更多自定义异常的处理分支
    ...
}

补充方案:自定义异常过滤器

除了中间件,还可以使用ASP.NET Core自带的异常过滤器(IExceptionFilter或IAsyncExceptionFilter)处理异常。过滤器更贴近MVC管道,能直接访问ActionContext,支持针对特定控制器或Action配置,灵活性更强。

示例代码:

public class CustomExceptionFilter : IAsyncExceptionFilter
{
    private readonly ILogger<CustomExceptionFilter> _logger;

    public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
    {
        _logger = logger;
    }

    public async Task OnExceptionAsync(ExceptionContext context)
    {
        _logger.LogError(context.Exception, "未处理的异常发生");

        if (context.Exception is PostNotFoundException)
        {
            context.Result = new NotFoundObjectResult(new 
            {
                Status = 404,
                Detail = "请求的文章不存在"
            });
        }
        else
        {
            context.Result = new ObjectResult(new 
            {
                Status = 500,
                Detail = "服务器发生意外错误"
            })
            {
                StatusCode = StatusCodes.Status500InternalServerError
            };
        }

        context.ExceptionHandled = true;
    }
}

注册过滤器到MVC管道:

// Program.cs
builder.Services.AddControllers(options =>
{
    options.Filters.Add<CustomExceptionFilter>();
});

各方案适用场景总结

  • 结果模式:适合需要严格控制返回结果结构、避免依赖异常抛出的场景,逻辑更显式,但会增加控制器层的判断代码,且服务层需要维护Result对象的状态。
  • 自定义异常+中间件/过滤器:适合将异常处理逻辑集中管理,控制器代码更简洁,符合关注点分离原则;但需注意不要过度定义自定义异常,避免类型泛滥,可按业务领域或错误类型归类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:10:20