【C#/.NET】.NET6中全局异常处理

.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;
 4
 5[ApiController]
 6[Route("api/[controller]")]
 7public class UserController : Controller
 8{
 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;
 4
 5namespace ExceptionHandling.Middlewares;
 6
 7public class ExceptionHandlingMiddleware
 8{
 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    {
 4
 5      _logger.LogInformation("Get User Details");
 6
 7           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】控制台上动态构建中间件管道

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ASP.NET MVC 提供了一种处理应用程序出现的异常的方式,即使用全局异常过滤器。 要创建一个全局异常过滤器,请实现 `IExceptionFilter` 接口并在全局过滤器集合注册该过滤器。以下是一个示例: ```csharp public class CustomExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext filterContext) { // 处理异常 } } public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomExceptionFilter()); } } ``` 在上面的示例,`CustomExceptionFilter` 类实现了 `IExceptionFilter` 接口,并在 `OnException` 方法处理异常。然后,在 `FilterConfig` 类,通过调用 `filters.Add` 方法将全局异常过滤器添加到过滤器集合。 除了实现 `IExceptionFilter` 接口外,还可以通过继承 `HandleErrorAttribute` 类来创建全局异常过滤器。以下是一个示例: ```csharp public class CustomExceptionFilter : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { // 处理异常 } } public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomExceptionFilter()); } } ``` 在上面的示例,`CustomExceptionFilter` 类继承自 `HandleErrorAttribute` 类,并在 `OnException` 方法处理异常。然后,在 `FilterConfig` 类,通过调用 `filters.Add` 方法将全局异常过滤器添加到过滤器集合。 无论使用哪种方式创建全局异常过滤器,都应该确保在应用程序只有一个全局异常过滤器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值