如何在ASP.NET Core控制器中统一封装请求的Try-Catch逻辑?
ASP.NET Core API 统一异常处理与业务代码封装方案
以下几种方案可以帮你消除控制器中重复的try-catch代码,让业务逻辑更简洁:
方案一:自定义动作过滤器(Action Filter)
动作过滤器是ASP.NET Core中处理请求生命周期的扩展点,能统一拦截Action的执行,封装异常处理逻辑。
1. 实现自定义异常过滤器
public class CustomExceptionFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { try { // 执行后续Action逻辑 var resultContext = await next(); // 可选:统一包装正常返回结果(比如标准化响应格式) if (resultContext.Result is ObjectResult objectResult && objectResult.Value != null) { resultContext.Result = new OkObjectResult(new { Code = 200, Data = objectResult.Value }); } } catch (Exception ex) { // 统一返回BadRequest及异常信息 context.Result = new BadRequestObjectResult(new { Code = 400, Message = ex.Message }); } } }
2. 注册过滤器
全局注册(所有控制器生效)
在Program.cs中添加:
builder.Services.AddControllers(options => { options.Filters.Add<CustomExceptionFilter>(); });
局部注册(指定控制器/Action生效)
直接在控制器或Action上添加特性:
[CustomExceptionFilter] public class YourController : ControllerBase { [HttpGet] public async Task<IActionResult> A() { // 仅需编写业务逻辑,异常由过滤器自动处理 return Ok(await _serviceA.GetA()); } [HttpGet] public async Task<IActionResult> B() { return Ok(await _serviceB.GetB()); } }
优势
- 无侵入性,无需修改现有控制器结构
- 可创建多个过滤器,针对不同场景(如部分接口返回500而非400)配置差异化处理
方案二:基类控制器封装
创建带通用执行方法的基类控制器,子类继承后调用该方法执行业务逻辑。
1. 实现基类控制器
public class BaseApiController : ControllerBase { protected async Task<IActionResult> ExecuteAsync(Func<Task<object>> action) { try { var result = await action(); return Ok(result); } catch (Exception ex) { return BadRequest(ex.Message); } } }
2. 子类控制器使用
public class YourController : BaseApiController { private readonly IServiceA _serviceA; private readonly IServiceB _serviceB; public YourController(IServiceA serviceA, IServiceB serviceB) { _serviceA = serviceA; _serviceB = serviceB; } [HttpGet] public async Task<IActionResult> A() { return await ExecuteAsync(async () => await _serviceA.GetA()); } [HttpGet] public async Task<IActionResult> B() { return await ExecuteAsync(async () => await _serviceB.GetB()); } }
优势
- 逻辑集中,子类只需关注业务代码
- 可扩展多个重载方法,适配不同返回类型的业务逻辑
方案三:委托封装服务
创建通用封装服务,注入到控制器中,通过委托执行业务逻辑并处理异常。
1. 实现封装服务
public interface IActionExecutor { Task<IActionResult> ExecuteAsync(Func<Task<object>> action); } public class ActionExecutor : IActionExecutor { public async Task<IActionResult> ExecuteAsync(Func<Task<object>> action) { try { var result = await action(); return new OkObjectResult(result); } catch (Exception ex) { return new BadRequestObjectResult(ex.Message); } } }
2. 注册服务
在Program.cs中添加:
builder.Services.AddScoped<IActionExecutor, ActionExecutor>();
3. 控制器中使用
public class YourController : ControllerBase { private readonly IServiceA _serviceA; private readonly IServiceB _serviceB; private readonly IActionExecutor _actionExecutor; public YourController(IServiceA serviceA, IServiceB serviceB, IActionExecutor actionExecutor) { _serviceA = serviceA; _serviceB = serviceB; _actionExecutor = actionExecutor; } [HttpGet] public async Task<IActionResult> A() { return await _actionExecutor.ExecuteAsync(async () => await _serviceA.GetA()); } [HttpGet] public async Task<IActionResult> B() { return await _actionExecutor.ExecuteAsync(async () => await _serviceB.GetB()); } }
优势
- 逻辑完全解耦,可独立扩展不同执行策略
- 支持依赖注入,便于单元测试
内容的提问来源于stack exchange,提问作者THEoneANDonly
相关产品推荐
相关产品推荐

