.netcore全局异常处理
一、背景
某天,应用程序进程无缘无故退出,也就是我们通常说的崩溃。通常情况下,windows事件会记录一条消息。但是有时候,我们发现这样的信息,对于查找问题,还是远远不够的,因为它说RunTime报错。这时,我就想能不能自己捕获全局未处理的异常。之所以有这样的想法,因为之前在客户端程序中写过。这次我要在.netcore中处理,网上搜了一段代码,高高兴兴地贴上去了,觉得上了保险箱。
二、探索
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
foreach (var item in e.Exception.InnerExceptions)
{
Logger.Error("未捕获的Task异常 " + item.InnerException.Message + " " + item.GetType().Name);
}
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception exception = (Exception)e.ExceptionObject;
Logger.Error("未捕获的Domain异常 : " + exception.Message + "," + exception.StackTrace);
Logger.Error("Runtime terminating: {0}", e.IsTerminating);
}
给AppDomain和TaskScheduler注册了两个未处理异常的方法,等系统抛出异常时,可以捕获。没想到,程序一天之内崩溃了两次,比之前几个月崩溃一次,频率不知高了都少倍。下面是崩溃时的信息:
这堆栈信息,得仔细看,才能看出门道,否则,可能会把重要的信息遗漏掉。猛的一看,程序哪里有未将对象引用到实例了?在业务代码中苦苦思索,没有找到。第二天早晨,仔细查看这个错误信息,发现这个异常竟然是TaskScheduler注册的这个方法里面报出来的。于是我再次修改代码:
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
if (e.Exception?.InnerException != null)
{
foreach (var item in e.Exception.InnerExceptions)
{
Logger.Error("未捕获的Task异常 " + item.InnerException.Message + " " + item.GetType().Name);
}
}
else
{
Logger.Error("[Exception]未捕获的Task异常 " + e.Exception?.Message + " " + e.Exception?.StackTrace);
}
//将异常标识为已经观察到
e.SetObserved();
}
代码是修改好了,在本地如何调试呢?网上说,GC回收Task的时候,会触发Task里的异常,这个说法,应该是正确的,请看上面的堆栈信息,回收的时候,会报异常发布出去。好,那我就人为制造一个异常:
Task.Run(() =>
{
throw new Exception("测试异常");
});
Thread.Sleep(2000);
GC.Collect();
可是代码跑起来,没有捕获到任何异常。我以为GC没有运行,我在网上搜索答案,类似这样的写法:
Task.Run(() =>
{
throw new Exception("测试异常");
});
while(true){
//不停地给数组分配内存
//调用GC
}
这次代码运行起来,不仅异常没有捕获到,程序直接崩溃,说内存不足,最后笔记本发烫,导致了蓝屏。我不得不重启电脑。
三、处理
网上一篇文章说,在Debug模式下,捕获不到异常。Release下可以。于是,我切换了模式,果然可以。
Logger.Error("未捕获的Task异常 " + item.InnerException.Message + " " + item.GetType().Name);
在处理全局异常的方法里,我记录了日志,就这一句引发了未将对象引用到实例,调试发现 itm.InnerException为null,所以调用Message就异常了。下面,我们来处理:
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
foreach (var item in e.Exception.InnerExceptions){
Logger.Error("未捕获的Task异常 " + item.InnerException?.Message + " " + item.GetType().Name);
}
}
处理好了,日志输出:未捕获的Task异常 Exception,从调试角度看,这样的信息,就是个废话,改改代码:
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
foreach (var item in e.Exception.InnerExceptions)
{
Logger.Error("未捕获的Task异常 " + item.Message + "," + item.StackTrace);
}
}
调试结果如下:
这样代码就好了吗?我担心尽管处理好后,进程还会退出,网上搜了下,可以加入这句:
//将异常标识为已经观察到
e.SetObserved();
经过调试,发现少了这句,也不会有问题,这句意思是不让异常继续往上冒泡,到此为止。这样,程序就好了吗?还是有所担心,终极版的代码:
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
try
{
foreach (var item in e.Exception.InnerExceptions)
{
Logger.Error("未捕获的Task异常 " + item.Message + "," + item.StackTrace);
}
}
catch (Exception ex)
{
Logger.Error($"TaskScheduler_UnobservedTaskException处理异常:{ex.Message}");
}
//阻止异常冒泡
e.SetObserved();
}
这里之所以加上try..catch,因为担心Logger出现异常,进程照样会崩溃。所以,既想捕获应用程序中Task中的异常,又不想因此把程序整垮。
四、后记
网上的代码,仅供参考和学习,要上服务器,还得经过本地严格测试,谁知道会什么时候会引发灾难。
.netcore全局异常处理的更多相关文章
- ASP.NET Core 中间件自定义全局异常处理
目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...
- mvc自定义全局异常处理
异常信息处理是任何网站必不可少的一个环节,怎么有效显示,记录,传递异常信息又成为重中之重的问题.本篇将基于上篇介绍的html2cancas截图功能,实现mvc自定义全局异常处理.先看一下最终实现效果: ...
- 在.NET Core程序中设置全局异常处理
以前我们想设置全局异常处理只需要这样的代码: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledExc ...
- springMvc全局异常处理
本文中只测试了:实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器 对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提 ...
- MVC 全局异常处理及禁用显示头
MVC网站的global.asax中的Application_Start方法里,有这样一段代码: public class MvcApplication : System.Web.HttpApplic ...
- Spring MVC 解决无法访问静态文件和"全局异常处理"
我们都知道,Spring MVC的请求都会去找controller控制器,若果我们页面中引入了一个外部样式,这样是没效果的, 我们引入样式的时候是通过<like href="...&q ...
- Spring Boot 2.x 系列教程:WebFlux REST API 全局异常处理 Error Handling
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 本文内容 为什么要全局异常处理? WebFlux REST 全 ...
- .NET MVC全局异常处理(二)
目录 .NET MVC全局异常处理(二) MVC过滤器Filter .NET MVC全局异常处理(二) 对上节的内容进行了补充 MVC过滤器Filter MVC有四种过滤器:Authorization ...
- .NET MVC全局异常处理(一)
目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关的配置,但没有实际做过,以为改下设定就 ...
- Spring Boot 全局异常处理
Spring Boot版本 1.5 @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExcept ...
随机推荐
- Semaphore信号量源码解析(基于jdk11)
目录 1.Semaphore信号量源码解析(基于jdk11) 1.1 Semaphore概述 1.2 Semaphore的原理 1.2.1 基本结构(jdk11) 1.2.2 可中断获取信号量 1.2 ...
- RFN-Nest_ An end-to-end residual fusion network for infrared and visible images 论文解读
RFN-Nest 2021 研究 图像融合分为三步:特征提取,融合策略,图像重建. 当前端到端的图像融合方法:基于GAN的.还有本文提出的 研究背景:当前设计的融合策略在为特定任务生成融合图像方面是比 ...
- SQL注入漏洞原理与利用
SQL注入漏洞原理与利用 SQL注入漏洞流程 判断注入类型 判断字段个数 查询回显位 查询数据库名 查询表.字段名 查询内容 判断注入类型 1.数字型注入点判断 当要输入的参数x为数字型时,后端脚本中 ...
- 【精选】前端JS面试题35个
1.问:什么是匿名函数?作用是什么? 答:没有名字的函数就是匿名函数,作用有三,把函数当作变量赋值,把函数当作参数(回调函数),把函数当作另一个函数的返回值(闭包) ...
- linux常用命令精讲
一.虚拟机三种网卡模式 1 桥接 相当于虚拟机和真机之间架了一座桥 2 NAT 虚拟系统借助 NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网(常用vm8) 3 仅主机 虚拟机和物理机在一 ...
- PyTorch复现LeNet-5手写识别学习笔记
用PyTorch搭建LeNet-5手写识别 首先申明,这篇博客用于记录本人看完LeNet-5论文,并对其中的算法进行复现的记录,可以看成是学习笔记 这里只介绍复现的工作,如果想了解更多有关网络的细节, ...
- 基于ZR.VUE 前端的改造,页面刷新报错
问题描述: 前后端分离开发,分开部署. 页面刷新 直接报404 错误的解决办法 提示: 先在 .env.development 中 配置 VUE_APP_BASE_API , 将 '/' 替换为 后 ...
- Android的诞生
Android操作系统最初由Andy Rubin开发,刚开始主要支持手机,被Google收购后,对Android进行了改良,使其可以用于平板电脑等其它领域. 1.1.1 Android的发展史Andr ...
- 跟光磊学Java-Windows版Java8开发环境搭建
Java语言核心技术 如果想要开发Java程序/Java项目之前,必须要安装和配置JDK,这里的JDK表示Java8\JDK8,不过下载软件的时候,强烈推荐大家一定要去软件的官网下载,因为官网提供的软 ...
- Hadoop详解(06) - Yarn平台架构和资源调度器
Hadoop详解(06) - Yarn平台架构和资源调度器 Yarn平台架构 Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程 ...