首页 > 其他分享 >MasaFramework -- 异常处理

MasaFramework -- 异常处理

时间:2022-10-14 10:12:28浏览次数:76  
标签:自定义 -- ExceptionHandler ex context MasaFramework 异常 public

前言

在程序设计中,我们会遇到各种各样的异常问题,一个异常处理不仅仅可以帮助开发者快速的定位问题,也可以给用户更好的使用体验,那么我们在AspNetCore项目中如何捕获以及处理异常呢?

而对应AspNetCore程序,我们有两种异常处理方案,它们分别是:

  • 异常中间件
  • 异常过滤器

介绍

Masa Franework作为一个框架,它为开发者以及用户提供更好的开发体验和使用体验的异常处理功能

Masa.Utils.Exceptions 中定义了两种异常类

  • UserFriendlyException(友好异常)
  • MasaException(框架异常)

并提供了两种异常处理方案,那接下来就让我们看看它们是如何使用的

根据需要自行选择一种方案使用即可

快速入门

项目基于.NET 6.0创建,必须安装所必须的环境

异常中间件

基于中间件实现的全局异常处理,用于捕捉应用程序异常,并将异常信息处理后返回

  1. 新建ASP.NET Core 空项目Assignment.GlobalExceptionDemo,并安装Masa.Utils.Exceptions
dotnet new web -o Assignment.GlobalExceptionDemo
cd Assignment.GlobalExceptionDemo

dotnet add package Masa.Utils.Exceptions --version 0.6.0-rc.3 //提供全局异常过滤器
  1. 新建用户类User
public class User
{
    public string Name { get; set; }

    public int Age { get; set; }
}
  1. 使用全局异常,修改Program
//支持处理自定义异常
app.UseMasaExceptionHandler(options =>
{
    //支持处理自定义异常
    options.ExceptionHandler = context =>
    {
        if (context.Exception is ArgumentNullException ex)
        {
            context.ToResult($"{ex.ParamName}不能为空");
        }
    };
});
  1. 新增注册用户方法(用于自定义抛出异常)
app.MapPost("/register", (User user) =>
{
    if (string.IsNullOrEmpty(user.Name))
        throw new ArgumentNullException(nameof(user.Name));
    //todo: Impersonate a registered user
});

更多使用技巧可查看

异常过滤器

基于MVC的全局异常过滤器,用于捕捉应用程序异常,并将异常信息处理后返回

  1. 新建ASP.NET Core 空项目Assignment.GlobalFilterDemo,并安装Masa.Utils.Exceptions
dotnet new web -o Assignment.GlobalFilterDemo
cd Assignment.GlobalFilterDemo

dotnet add package Masa.Utils.Exceptions --version 0.6.0-rc.3 //提供全局异常过滤器
  1. 新建用户类User
public class User
{
    public string Name { get; set; }

    public int Age { get; set; }
}
  1. 使用全局异常过滤器,修改Program
builder.Services
    .AddMvc()
    //使用MasaException
    .AddMasaExceptionHandler(options =>
    {
        options.ExceptionHandler = context =>
        {
            if (context.Exception is ValidationException ex)
            {
                string message = ex.Errors.Select(error => error.ErrorMessage).FirstOrDefault()!;
                context.ToResult(message);
            }
        };
    });
  1. 新增注册用户方法,用于自定义抛出异常
[ApiController]
[Route("[Action]")]
public class UserController : ControllerBase
{
    [HttpPost]
    public void Register(User user)
    {
        if (string.IsNullOrEmpty(user.Name))
            throw new ArgumentNullException(nameof(user.Name));

        //todo: Impersonate a registered user
    }
}

验证全局异常处理

分别启用使用异常中间件的项目以及异常过滤器的项目,用Postman或者通过Swagger分别请求两个项目的注册用户接口,其中Name为空,可得到以下提示,则代表全局异常处理成功

verify

进阶

不论是通过中间件还是过滤器来处理全局异常,我们都支持自定义异常处理,我们首先来看一下异常的处理流程

Exception.png

根据流程图可以直观的了解到,只要使用了Masa提供的异常处理,哪怕我们不自定义异常,框架也会帮助我们按照无自定义异常流程默认处理异常信息,但如果我们希望对特定的异常做出特定的响应,那么就需要我们自定义异常

自定义异常

自定义异常支持三种方式

以中间件为例:

方案一. 通过配置ExceptionHandler(异常处理),修改Program.cs

app.UseMasaExceptionHandler(options =>
{
    options.ExceptionHandler = context =>
    {
        // 根据context.Exception判断异常类型,并通过context.ToResult()输出响应内容
        if (context.Exception is ArgumentNullException ex)
        {
            context.ToResult($"{ex.ParamName}不能为空");
        }
    };
});

方案二. 通过自定义ExceptionHandler,并注册到服务集合

  1. 自定义异常处理类ExceptionHandler,并继承IMasaExceptionHandler
/// <summary>
/// 构造函数参数需支持从IOC获取
/// </summary>
public class ExceptionHandler : IMasaExceptionHandler
{
    public void OnException(MasaExceptionContext context)
    {
        if (context.Exception is ArgumentNullException ex)
        {
            context.ToResult($"{ex.ParamName}不能为空");
        }
    }
}
  1. 使用指定的异常Handler,修改Program.cs

builder.Services.AddSingleton<IMasaExceptionHandler, ExceptionHandler>();//注册自定义异常

var app = builder.Build();
app.UseMasaExceptionHandler();// 在Program中执行异常处理程序

方案三. 通过自定义ExceptionHandler并指定ExceptionHandler来实现

  1. 自定义异常处理类ExceptionHandler,并继承IMasaExceptionHandler
/// <summary>
/// 构造函数参数需支持从IOC获取
/// </summary>
public class ExceptionHandler : IMasaExceptionHandler
{
    public void OnException(MasaExceptionContext context)
    {
        if (context.Exception is ArgumentNullException ex)
        {
            context.ToResult($"{ex.ParamName}不能为空");
        }
    }
}
  1. 使用指定的异常Handler,修改Program.cs
app.UseMasaExceptionHandler(options => options.UseExceptionHanlder<ExceptionHandler>());//指定使用特定的异常处理程序

上述三种方案任选其一即可,提供的功能时一样的,仅仅是写法不同

修改HttpStatusCode状态码

MasaExceptionContext默认提供了ToResult方法支持输入响应内容,状态码(默认: 299),内容类型 (默认:text/plain; charset=utf-8),我们可以根据自己的实际情况调用传参即可

修改日志级别

异常类型为UserFriendlyException的默认日志等级为Information,其余异常的日志等级为Error,那么如果我想修改对应异常的日志等级应该怎么做?

配置异常日志关系:

builder.Services.Configure<MasaExceptionLogRelationOptions>(options =>
{
    options.MapLogLevel<ArgumentNullException>(LogLevel.None);
});

按照此方式,可以将类型为ArgumentNullException异常的日志等级设置为None(不记录日志)

常见问题

A: 为什么使用全局异常后没有记录日志?
Q:

  1. 检查是否指定了自定义异常处理的Handler,并且当前异常已经被自定义异常处理程序处理(ExceptionHandled = true)
  2. 检查当前异常类型是否配置了指定的日志等级,且当前日志等级小于默认记录日志的等级

A: 实现IMasaExceptionHandler后,为什么发生异常后没有进入OnException
Q: 未注入到服务集合且没有指定使用指定的ExceptionHanlder

  • 自定义异常Handler
public class ExceptionHandler : IMasaExceptionHandler
{
    public void OnException(MasaExceptionContext context)
    {
        throw new NotImplementedException();
    }
}    

可参考自定义异常中的方案二或者方案三修改即可

总结

Masa提供的全局异常中间件,对自定义异常的扩展支持较好,并且后续Masa Framework支持I18n后,全局异常也将增加I18n支持, 届时全局异常会更加方便

本章源码

Assignment13

https://github.com/zhenlei520/MasaFramework.Practice

开源地址

MASA.Framework:https://github.com/masastack/MASA.Framework

MASA.EShop:https://github.com/masalabs/MASA.EShop

MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor

如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们

16373211753064.png

标签:自定义,--,ExceptionHandler,ex,context,MasaFramework,异常,public
From: https://www.cnblogs.com/zhenlei520/p/16789321.html

相关文章

  • leetcode每日一题:940.不同的子序列Ⅱ
    题目描述给定一个字符串s,计算s的不同非空子序列的个数。因为结果可能很大,所以返回答案需要对10^9+7取余。字符串的子序列是经由原字符串删除一些(也可能不删除)字......
  • Linux日志文件/var/log详解
    以下介绍的是20个位于/var/log/目录之下的日志文件。其中一些只有特定版本采用,如dpkg.log只能在基于Debian的系统中看到。/var/log/messages—包括整体系统信息,其中也......
  • 大厂必备的40个方法论
    方法论是一种以解决问题为目标的理论体系或系统,通常涉及对问题阶段、任务、工具、方法技巧的论述。方法论会对一系列具体的方法进行分析研究、系统总结并最终提出较为一般......
  • 《无垠的太空(7).波斯波利斯崛起》速读
     扩展阅读第1部:利维坦觉醒(Leviathan Wakes)速读链接:https://www.cnblogs.com/rockyching2009/p/16483273.html 第2部:卡利班之战(Caliban’s War)速读链接:https:......
  • 知识图谱实体对齐2:基于GNN嵌入的方法
    知识图谱实体对齐2:基于GNN嵌入的方法1导引我们在上一篇博客《知识图谱实体对齐1:基于平移(translation)嵌入的方法》中介绍了如何对基于平移嵌入+对齐损失来完成知识图谱......
  • 看一遍就理解:IO模型详解
    前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll......
  • Java程序员必备基础:内部类解析
    前言整理了一下内部类的相关知识,算是比较全,比较基础的,希望大家一起学习进步。一、什么是内部类?在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本......
  • 后端程序员必备:索引失效的十大杂症
    背景最近生产爆出一条慢sql,原因是用了or和!=,导致索引失效。于是,总结了索引失效的十大杂症,希望对大家有帮助,加油。一、查询条件包含or,可能导致索引失效新建一个user表,它有一......
  • Java程序员必备:异常的十个关键知识点
    前言总结了Java异常十个关键知识点,面试或者工作中都有用哦,加油。一.异常是什么异常是指阻止当前方法或作用域继续执行的问题。比如你读取的文件不存在,数组越界,进行除法时,除......
  • MySql时间处理函数的学习与实践
    前言日常业务开发中,我们经常需要跟SQl的日期打交道,比如查询最近30天的订单,查询某一个月的订单量,统计某天每小时的下单量等等,于是整理了以下MySql时间处理函数。DATE_ADD()定......