.Net Core API项目中如何优雅的捕获全局异常

185 次浏览次阅读

API项目中Controller层或者Service层都会出现异常处理的需求,如果不使用全局异常捕获就需要针对每个方法单独写异常处理,每个Controller或者Service都会因此产生冗余代码。

  //未使用全局异常捕获
  public async Task AddAsync()
  {
      try
      {
          //你的业务代码
      }
      catch (Exception ex)
      {
          //错误日志记录
          //错误返回信息拼接
          //其他处理
          throw;
      }
  }

  //使用全局异常捕获
  public async Task AddAsync()
  {
          //你的业务代码
  }

通过比较可以看到使用全局异常捕获的代码只需要关注业务实现部分,异常处理已经被剥离成单独的处理模块,不需要再编写重复的处理逻辑,更加符合模块化的编程思想,更加优雅。

全局异常捕获的实现方式

之前的博文有分享过FiltersMiddleware,过滤器和中间件都可以实现全局捕获的功能,中间件可以捕获整个程序启动到执行阶段的异常,过滤器只能捕获控制器或者方法内的异常,可以根据具体需求选择也。

使用Filters捕获全局异常实现代码

  //Filter基类
  public class BaseActionFilterAsync : ActionFilterAttribute
  {
      public async virtual Task OnActionExecuting(ActionExecutingContext context)
      {
          await Task.CompletedTask;
      }

      public async virtual Task OnActionExecuted(ActionExecutedContext context)
      {
          await Task.CompletedTask;
      }

      public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
      {
          await OnActionExecuting(context);
          if (context.Result == null)
          {
              var nextContext = await next();
              await OnActionExecuted(nextContext);
          }
      }
   }
   //全局异常捕获Filter
   public class GlobalExceptionFilter : BaseActionFilterAsync, IAsyncExceptionFilter
   {
       readonly ILogger _logger;
       public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
       {
           _logger = logger;
       }
       public async Task OnExceptionAsync(ExceptionContext context)
       {
           Exception ex = context.Exception;
           //BusException 为自定义异常类型,用于返回业务处理的错误信息
           if (ex is BusException busEx)
           {
               _logger.LogInformation(busEx.Message);
               context.Result = Error(busEx.Message, busEx.ErrorCode);
           }
           else if (ex is ValidationException validationException)
           {
               _logger.LogInformation(validationException.Message);
               context.Result = Error(validationException.Message, 500);
           }
           else
           {
               _logger.LogError(ex, "");
               context.Result = Error("系统繁忙", 500);
           }
           await Task.CompletedTask;
       }
   }


   //需要在Program中给控制器注册Filter
  var builder = WebApplication.CreateBuilder(args);
  var services = builder.Services;
  services.AddControllers(options =>
  {    
      options.Filters.Add<GlobalExceptionFilter>();//全局异常
  })

使用Middleware捕获全局异常实现代码

   public class ErrorHandlerMiddleware
   {
       private readonly RequestDelegate _next;

       public ErrorHandlerMiddleware(RequestDelegate next)
       {
           _next = next;
       }
       public async Task InvokeAsync(HttpContext context)
       {
           try
           {
               await _next(context);
           }
           catch (Exception error)
           {
               var response = context.Response;
               response.ContentType = "application/json";

               switch (error)
               {
                   case BusException e:
                       // custom application error
                       response.StatusCode = (int)HttpStatusCode.BadRequest;
                       break;
                   case KeyNotFoundException e:
                       // not found error
                       response.StatusCode = (int)HttpStatusCode.NotFound;
                       break;
                   default:
                       // unhandled error
                       response.StatusCode = (int)HttpStatusCode.InternalServerError;
                       break;
               }

               var result = JsonSerializer.Serialize(new { message = error?.Message });
               await response.WriteAsync(result);
           }
       }
   }

   //同样需要在Program中注册Middleware
   var builder = WebApplication.CreateBuilder(args);
   var app = builder.Build();
   //注意异常捕获可以尽量靠前,这样能捕获到程序启动阶段的异常
   app.UseMiddleware<ErrorHandlerMiddleware>();//捕获全局异常
正文完
 
马化云
版权声明:本站原创文章,由 马化云 2023-11-23发表,共计2696字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。