首页 > 其他分享 >dotNet8 全局异常处理

dotNet8 全局异常处理

时间:2024-03-20 11:36:21浏览次数:26  
标签:exception dotNet8 处理 app Exception 全局 异常 HttpContext

前言

异常的处理在我们应用程序中是至关重要的,在 dotNet 中有很多异常处理的机制,比如MVC的异常筛选器, 管道中间件定义try catch捕获异常处理亦或者第三方的解决方案Hellang.Middleware.ProblemDetails等。MVC异常筛选器不太灵活,对管道的部分异常捕获不到,后两种方式大家项目应该经常出现。

dotNet8 发布之后支持了新的异常处理机制 IExceptionHandler或者UseExceptionHandler异常处理程序的lambda配置,配合dotNet7原生支持的ProblemDetail使得异常处理更加规范。

本文用一个简单的 Demo 带大家看一下新的异常处理方式

文末有示例完整的源代码

先起一个 WebApi 的新项目

Problem Details

Problem Details 是一种在 HTTP API 中用于描述错误信息的标准化格式。根据 RFC 7807,Problem Details 提供了一种统一、可机器读取的方式来呈现出发生在 API 请求中的问题。它包括各种属性,如 title、status、detail、type 等,用于清晰地描述错误的性质和原因。通过使用 Problem Details,开发人员可以为 API 的错误响应提供一致性和易于理解的结构化格式,从而帮助客户端更好地处理和解决问题。

项目中使用 Problem Details

builder.Services.AddProblemDetails();

如果我们不对异常进行捕获处理,Asp.Net Core 提供了两种不同的内置集中式机制来处理未经处理的异常

  • app.UseDeveloperExceptionPage();

    开发人员异常中间件

    开发人员异常中间件会显示服务器错误的详细堆栈跟踪,不建议在非开发环境显示,暴漏核心错误信息给客户端,有严重的安全风险

  • app.UseExceptionHandler(); 异常处理程序中间件,
    使用异常处理程序中间件生成的是标准的简化回复

测试 UseDeveloperExceptionPage

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.MapGet("/TestUseDeveloperExceptionPage",
    () => { throw new Exception("测试UseDeveloperExceptionPage"); });
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
    app.UseDeveloperExceptionPage();// 开发人员异常页
}
app.UseStatusCodePages();
app.UseHttpsRedirection();
app.Run();

调用 TestUseDeveloperExceptionPage 接口
回参

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.6.1",
  "title": "System.Exception",
  "status": 500,
  "detail": "测试UseDeveloperExceptionPage",
  "exception": {
    "details": "System.Exception: 测试UseDeveloperExceptionPage\r\n   at Program.<>c.<<Main>$>b__0_0() in C:\\dotNetParadise\\dot-net-paradise-exception\\dotNetParadise-Exception\\dotNetParadise-Exception\\Program.cs:line 7\r\n   at lambda_method3(Closure, Object, HttpContext)\r\n   at Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware.Invoke(HttpContext context)\r\n   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)\r\n   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)",
    "headers": {
      "Accept": [
        "*/*"
      ],
      "Host": [
        "localhost:7130"
      ],
      "User-Agent": [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0"
      ],
      "Accept-Encoding": [
        "gzip, deflate, br"
      ],
      "Accept-Language": [
        "en-US,en;q=0.9"
      ],
      "Cookie": [
        "ajs_anonymous_id=b96604ea-c096-4693-acfb-b3a9e8403f0e; Quasar_admin_Vue3_username=admin; Quasar_admin_Vue3_token=b1aa15b6-02bb-44b9-8668-0157a1d9b6f0; Quasar_admin_Vue3_lang=en-US"
      ],
      "Referer": [
        "https://localhost:7130/swagger/index.html"
      ],
      "sec-ch-ua": [
        "\"Chromium\";v=\"122\", \"Not(A:Brand\";v=\"24\", \"Microsoft Edge\";v=\"122\""
      ],
      "sec-ch-ua-mobile": [
        "?0"
      ],
      "sec-ch-ua-platform": [
        "\"Windows\""
      ],
      "sec-fetch-site": [
        "same-origin"
      ],
      "sec-fetch-mode": [
        "cors"
      ],
      "sec-fetch-dest": [
        "empty"
      ]
    },
    "path": "/TestUseDeveloperExceptionPage",
    "endpoint": "HTTP: GET /TestUseDeveloperExceptionPage",
    "routeValues": {}
  }

可以看到所有的信息都抛出来给到了客户端,适合在开发环境用,非开发环境尤其是生产环境不要启用。

app.UseExceptionHandler();

异常处理程序中间件

// app.UseDeveloperExceptionPage();// 开发人员异常页
app.UseExceptionHandler();//异常处理中间件

测试一下

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.6.1",
  "title": "An error occurred while processing your request.",
  "status": 500
}

可以看到只保留了最基本的报错信息,这样第一步我们已经完成了。

自定义异常 和 IExceptionHandler

创建一个自定义异常信息

public class CustomException(int code, string message) : Exception(message)
{
    public int Code { get; private set; } = code;

    public string Message { get; private set; } = message;
}

集成IExceptionHandler创建自定义异常处理器

public class CustomExceptionHandler(ILogger<CustomException> logger, IWebHostEnvironment environment) : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        if (exception is not CustomException customException) return false;
        logger.LogError(
              exception, "Exception occurred: {Message} {StackTrace} {Source}", exception.Message, exception.StackTrace, exception.Source);

        var problemDetails = new ProblemDetails
        {
            Status = customException.Code,
            Title = customException.Message,
        };
        if (environment.IsDevelopment())
        {
            problemDetails.Detail = $"Exception occurred: {customException.Message} {customException.StackTrace} {customException.Source}";
        }
        httpContext.Response.StatusCode = problemDetails.Status.Value;
        await httpContext.Response
            .WriteAsJsonAsync(problemDetails, cancellationToken);
        return true;
    }
}

可以注册多个自定义异常处理器分别处理不同类型的异常,按默认的注册顺序来处理,如果返回true则会处理此异常返回false会跳到下一个ExceptionHandler,没处理的异常在 UseExceptionHandler 中间件做最后处理。

创建第二个ExceptionHandler 处理系统异常

public class SystemExceptionHandle(ILogger<CustomException> logger, IWebHostEnvironment environment) : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        if (exception is CustomException) return false;
        logger.LogError(
              exception, "Exception occurred: {Message} {StackTrace} {Source}", exception.Message, exception.StackTrace, exception.Source);

        var problemDetails = new ProblemDetails
        {
            Status = StatusCodes.Status500InternalServerError,
            Title = "An error occurred while processing your request",
        };
        if (environment.IsDevelopment())
        {
            problemDetails.Detail = $"Exception occurred: {exception.Message} {exception.StackTrace} {exception.Source}";
        }

        httpContext.Response.StatusCode = problemDetails.Status.Value;

        await httpContext.Response
            .WriteAsJsonAsync(problemDetails, cancellationToken);

        return true;

    }
}

IOC 容器注册ExceptionHandler

builder.Services.AddExceptionHandler<CustomExceptionHandler>();
builder.Services.AddExceptionHandler<SystemExceptionHandle>();

新加接口测试一下

app.MapGet("/CustomThrow", () =>
{
    throw new CustomException(StatusCodes.Status403Forbidden, "你没有权限!");
}).WithOpenApi();

回参

{
  "title": "你没有权限!",
  "status": 403,
  "detail": "Exception occurred: 你没有权限!    at Program.<>c.<<Main>$>b__0_1() in C:\\dotNetParadise\\dot-net-paradise-exception\\dotNetParadise-Exception\\dotNetParadise-Exception\\Program.cs:line 15\r\n   at lambda_method5(Closure, Object, HttpContext)\r\n   at Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware.Invoke(HttpContext context)\r\n   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)\r\n   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task) dotNetParadise-Exception"
}

可以看出全局异常捕获生效了。

最后

本文讲的是 dotNet8 新的异常处理方式,当时也可以用UseExceptionHandlerlambda方式可以创建,但是不如这种强类型约束的规范,大家在升级 dotNet8 时可以参考本文来修改项目现有的全部异常捕获方式。

Demo 源代码

dotNet 官网教程

 

2024-03-20 11:24:17【出处】:https://www.cnblogs.com/ruipeng/p/18075123

=======================================================================================

标签:exception,dotNet8,处理,app,Exception,全局,异常,HttpContext
From: https://www.cnblogs.com/mq0036/p/18084860

相关文章

  • 网络请求异常问题
    该篇文章记录总结一下,我在做前后端分离项目开发的过程中,所遇到的有关网络请求异常的前后端交互问题。(前端使用的是axios异步请求、后端使用fastAPI接口)一、段落上传部分最初报的错误如下图:   当时查阅了很多的资料,跟着网上所说的解答逐个排查错误,但是都还是没有解决......
  • this指向是在那个全局变量?
    在浏览器环境中,如果没有特殊处理,全局对象是window对象。因此,在浏览器环境中,this的指向在全局作用域中将是window对象。在Node.js环境中,全局对象是global对象。举例来说,在浏览器环境下,如果在全局作用域中使用this,它将指向window对象。例如,以下代码将会输出true:co......
  • nvm 下载新的Node(V18.19.0)版本,查看npm的版本出现异常Error: Cannot find module '@npm
    异常: 之前下载18.17.1查看npm也有问题ERROR:npmv9.6.7isknownnottorunonNode.jsv18.17.1. 大概意思是npm的版本是 v9.6.7单不能运行在v18.17.1的node上,但是node官网显示v18.17.1版本的node是适配v9.6.7的npm。这就很矛盾 最后找到的解决方案是升级nvm的版本......
  • JAVASE各模块结构图:面向对象、常用类、多线程、异常、IO流、集合、网络编程
    ......
  • Java学习笔记:异常处理
    目录Java学习笔记:异常处理什么是异常异常体系结构:Error、Exception自定义异常Java学习笔记:异常处理​ **2024/3/19**什么是异常异常体系结构:Error、Exception自定义异常......
  • 纵横山河万里,终集 Java的错误和异常
    本篇会加入个人的所谓‘鱼式疯言’❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • openGauss Anomaly_detection_数据库指标采集_预测与异常监控
    Anomaly-detection:数据库指标采集、预测与异常监控可获得性本特性自openGauss1.1.0版本开始引入。特性简介anomaly_detection是openGauss集成的、可以用于数据库指标采集、预测以及异常监控与诊断的AI工具,是dbmind套间中的一个组件。支持采集的信息包括IO_Read、IO_Write、CPU......
  • 全局异常捕获(@RestControllerAdvice)介绍和使用
    @RestControllerAdvice是什么@RestControllerAdvice是Spring框架提供的一个注解,用于定义全局异常处理器和全局数据绑定设置。它结合了@ControllerAdvice和@ResponseBody两个注解的功能。@ControllerAdvice@ControllerAdvice是一个用于定义全局控制器增强(即全局异常处理和......
  • 基于似然场的全局定位
    似然场法定位检测似然场最小二乘问题构建机器人Robot在地图World中的位姿表示为\(\boldsymbol{x}\),激光雷达扫描得到的点云表示为\(\{p_i^R\}\),其中\(^R\)表示在机器人坐标系下的坐标,\(_i\)表示点云中第i个点。\[\boldsymbol{x}=[x,y,\theta]^{\rm{T}}\]那么,点云中机器人......
  • Eplan插件 - 修改全局栅格
    前言在工作中,经常使用到窗口宏,尤其是在驱动器比较多的时候,可能一连几十页都是伺服驱动器,但是由于窗口宏是从其他地方获取而来。而窗口宏的制作者使用了过大或过小的栅格就会出现画图连接不齐的情况,那么就需要手动修改栅格的大小。在Eplan中默认修改的是当前页面的栅格。在页数很......