微信公众号:趣编程ACE
关注可了解每日一更的.NET日常实战开发技巧,欢迎公众号留言开发 获取源码;

.NET6中全局异常处理

异常处理是我们在程序开发中不可或缺的一环,下文我将会结合程序Sample讲解如何在.NET6中有效处理异常。

  1. Try-Ctach 块包裹

  2. 自定义异常中间件

Try-Catch 块

Try-Catch 是最基本的异常处理方法,下面我们看下例子。
创建一个基于.net6的Asp.Net Core Web Api项目

1using ExceptionHandling.Services;2using Microsoft.AspNetCore.Mvc;3namespace ExceptionHandling.Controllers;45[ApiController]6[Route("api/[controller]")]7public class UserController : Controller8{9    private readonly IUserService _userService;
10    private readonly ILogger<UserController> _logger;
11
12    /// <summary>
13    /// 依赖注入 IUserService ILogger<UserController>
14    /// </summary>
15    /// <param name="userService"></param>
16    /// <param name="logger"></param>
17    public UserController(IUserService userService, ILogger<UserController> logger)
18    {
19        _userService = userService;
20        _logger = logger;
21    }
22
23    [HttpGet]
24    public IActionResult GetUsers()
25    {
26
27       try
28       {
29           _logger.LogInformation("Get User Details");
30
31           var result = _userService.GetUsers();
32           if(result.Count==0)
33            throw new ApplicationException("Get User failed"); // 此处抛出一个获取用户出错异常
34
35           return Ok(result);
36       }
37       catch (System.Exception e)
38       {
39           _logger.LogError(e.Message);
40           return BadRequest("获取失败"); // 返回给前端
41       }
42    }
43}

我们在VsCode里面按照一个Postman插件PostCode 调用上面接口https://localhost:7218/api/User

通过结果可知,当我们没有获取到用户的时候,代码将会抛出一个Get User failed的异常(见上图)。对于初学者来说,这是最常见最基础的方法,但是这个方法对于大项目来说也有一个缺点。

如果项目中有许多控制器和动作方法,然后我们需要对每一个动作方法都使用try-catch,那么在这种情况下,用try-catch就很累赘,也会增加代码行数。此时就需要自定义一个处理全局异常的中间件啦!

使用这个方法的好处就是我们可以在一个地方捕获未处理的异常,而不需要在每个动作方法中使用try-catch。

自定义中间件处理异常

在根目录下创建一个Middlewares文件夹,新建一个名为ExceptionHandlingMiddleware.cs

1using System.Net;2using System.Text.Json;3using ExceptionHandling.Models.Responses;45namespace ExceptionHandling.Middlewares;67public class ExceptionHandlingMiddleware8{9    private readonly RequestDelegate _next;  // 用来处理上下文请求
10    private readonly ILogger<ExceptionHandlingMiddleware> _logger;
11    public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
12    {
13        _next = next;
14        _logger = logger;
15    }
16
17    public async Task InvokeAsync(HttpContext httpContext)
18    {
19        try
20        {
21            await _next(httpContext); //要么在中间件中处理,要么被传递到下一个中间件中去
22        }
23        catch (Exception ex)
24        {
25            await HandleExceptionAsync(httpContext, ex); // 捕获异常了 在HandleExceptionAsync中处理
26        }
27    }
28    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
29    {
30        context.Response.ContentType = "application/json";  // 返回json 类型
31        var response = context.Response;
32
33        var errorResponse = new ErrorResponse
34        {
35            Success = false
36        };  // 自定义的异常错误信息类型
37        switch (exception)
38        {
39            case ApplicationException ex:
40                if (ex.Message.Contains("Invalid token"))
41                {
42                    response.StatusCode = (int) HttpStatusCode.Forbidden;
43                    errorResponse.Message = ex.Message;
44                    break;
45                }
46                response.StatusCode = (int) HttpStatusCode.BadRequest;
47                errorResponse.Message = ex.Message;
48                break;
49            case KeyNotFoundException ex:
50                response.StatusCode = (int) HttpStatusCode.NotFound;
51                errorResponse.Message = ex.Message;
52                break;
53            default:
54                response.StatusCode = (int) HttpStatusCode.InternalServerError;
55                errorResponse.Message = "Internal Server errors. Check Logs!";
56                break;
57        }
58        _logger.LogError(exception.Message);
59        var result = JsonSerializer.Serialize(errorResponse);
60        await context.Response.WriteAsync(result);
61    }
62}

这就是我们自定义的中间件,在ExceptionHandlingMiddleware中,我们首先通过依赖注入ILoggerRequestDelegate服务。委托类型_next用来处理上下文请求,要么将上下文放在中间件中处理,要么传递到下个中间链里的下一个中间件中去。

如果我们的请求发生异常,那么就会执行HandleExceptionAsync这个方法。这个方法里面会根据异常类型来返回不同的状态码并且记录到日志中去,不需要返回给调用的客户端,然后我们就可以通过检查日志来发现异常信息。

我们在Program.cs中添加自定义异常

1 app.UseMiddleware<ExceptionHandlingMiddleware>();

接着我们修改下控制器里GetUsers()这个方法,去掉try-catch,直接抛出异常

1[HttpGet]2    public IActionResult GetUsers()3    {45      _logger.LogInformation("Get User Details");67           var result = _userService.GetUsers();8           if(result.Count==0)9            throw new KeyNotFoundException("Get User failed"); // 此处抛出一个KeyNotFoundException异常
10
11           return Ok(result);
12    }

通过调试我们可以发现,当发生异常的时候,程序将会执行到HandleExceptionAsync()方法中去,接着根据类型KeyNotFoundException 返回404的状态码和异常信息。


如需理解中间件管道执行过程可参考上篇文章:【C#/.NET】控制台上动态构建中间件管道

【C#/.NET】.NET6中全局异常处理相关推荐

  1. Vue实现全局异常处理的几种方案

    Vue实现全局异常处理的几种方案 在开发组件库或者插件,经常会需要进行全局异常处理,从而实现: 全局统一处理异常: 为开发者提示错误信息: 方案降级处理等等. 那么如何实现上面功能呢?本文先简单实现一 ...

  2. 【学习笔记】springboot中的全局异常处理 和@ControllerAdvice的使用

    文章目录 全局异常处理 例子 @ControllerAdvice的其他使用场景 全局异常处理 系统中异常包括:编译时异常和运行时异常RuntimeException ,前者通过捕获异常从而获取异常信息 ...

  3. 在.NET Core程序中设置全局异常处理

    以前我们想设置全局异常处理只需要这样的代码: 1 AppDomain currentDomain = AppDomain.CurrentDomain;2 currentDomain.Unhandled ...

  4. php中的全局异常,tp5 API 自定义全局异常处理(中)

    我们先来梳理一下异常的分类: 异常分类 tp5 有一个全局异常处理类,如果我们想自己实现上面的分类,需要覆盖和重写默认的全局异常处理类. 我们现在在 api 模块的同级下新建一个 lib 文件夹,再新 ...

  5. spring boot中@ControllerAdvice的用法,全局异常处理,全局数据绑定,全局数据预处理

    1: @ControllerAdvice理解 @ControllerAdvice是spring 3.2提供的新注解,他是一个controller增强器,加了@ControllerAdvice的类为那些 ...

  6. java异常统一处理_Java 代码中的全局异常处理

    最近接手一个新项目,写用例的时候去翻看代码,发现部分代码里缺少基本的异常处理,包括对参数异常以及业务异常的处理.对照之前负责过的异常处理做得比较好的项目,给开发提了几点建议,顺便又去翻看了之前项目的代 ...

  7. SpringBoot (二) :全局异常处理设置

    说在前面 在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler.@InitBinder.@ModelAttribute,并应用到所有 ...

  8. 看看人家 SpringBoot 的全局异常处理,多么优雅...

    点击关注公众号,Java干货及时送达 本篇文章主要介绍的是SpringBoot项目进行全局异常的处理. SpringBoot全局异常准备 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程 ...

  9. 别再写满屏的try-catch了,真丑,全局异常处理不会吗?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:巨人大哥 www.cnblogs.com/juren ...

最新文章

  1. sql server密钥
  2. JDBC之应用程序分层
  3. 在JavaScript文件中读取properties文件的方法
  4. javascript - this
  5. 干货 | 毕业论文无从下手?一文帮你理清头绪!
  6. 前端学习(2659):组件间传参
  7. tex文件用什么软件打开_pdf怎么打开?用什么软件打开pdf?
  8. 号称2020最轻薄的5G旗舰,这款手机 你不看看吗?
  9. 【Siddhi 5】Siddhi 5 源码编译
  10. jquery中如何获得$.ajax()事件返回的值
  11. 由项目中的一个小问题所联想到的。
  12. JQuery ajax 在aspx中传值和取值
  13. c# gerber文件读取_Gerber文件查看器
  14. 网络计算机自动显示,怎么设置电脑断网后自动报警提醒?
  15. 中国电信完成首批车联网卡实名登记管理平台T1接口对接
  16. BP神经网络的非线性曲线拟合和预测(未完)
  17. mac无法连接手机进行调试解决方法
  18. 美允许4G技术与WiFi共享5G频段;全球移动用户将达50亿│IoT黑板报
  19. Leetcode 312. 戳气球(经典区间dp)
  20. 4.pycharm(免费专业版)下载与安装与环境配置

热门文章

  1. golang reflect
  2. RHEL5U8配置Centos yum源
  3. 他毕业两年,博客一年,时间
  4. 2015华为校招机试面试
  5. 怎么快速了解自己的MySQL服务器?
  6. IOS Table中Cell的重用reuse机制分析
  7. .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  8. linux 信号_Linux的信号和线程
  9. android通过代码设置铃声_第六十四回:Android中UI控件之SeekBar
  10. C# Global.asax.cs 定时任务