经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
.netcore全局异常处理
来源:cnblogs  作者:micDavid  时间:2023/3/3 8:54:47  对本文有异议

一、背景

某天,应用程序进程无缘无故退出,也就是我们通常说的崩溃。通常情况下,windows事件会记录一条消息。但是有时候,我们发现这样的信息,对于查找问题,还是远远不够的,因为它说RunTime报错。这时,我就想能不能自己捕获全局未处理的异常。之所以有这样的想法,因为之前在客户端程序中写过。这次我要在.netcore中处理,网上搜了一段代码,高高兴兴地贴上去了,觉得上了保险箱。

二、探索

  1. AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
  2. TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
  3. private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  4. {
  5. foreach (var item in e.Exception.InnerExceptions)
  6. {
  7. Logger.Error("未捕获的Task异常 " + item.InnerException.Message + " " + item.GetType().Name);
  8. }
  9. }
  1. private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
  2. {
  3. Exception exception = (Exception)e.ExceptionObject;
  4. Logger.Error("未捕获的Domain异常 : " + exception.Message + "," + exception.StackTrace);
  5. Logger.Error("Runtime terminating: {0}", e.IsTerminating);
  6. }

给AppDomain和TaskScheduler注册了两个未处理异常的方法,等系统抛出异常时,可以捕获。没想到,程序一天之内崩溃了两次,比之前几个月崩溃一次,频率不知高了都少倍。下面是崩溃时的信息:

 

 

 这堆栈信息,得仔细看,才能看出门道,否则,可能会把重要的信息遗漏掉。猛的一看,程序哪里有未将对象引用到实例了?在业务代码中苦苦思索,没有找到。第二天早晨,仔细查看这个错误信息,发现这个异常竟然是TaskScheduler注册的这个方法里面报出来的。于是我再次修改代码:

  1. private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  2. {
  3. if (e.Exception?.InnerException != null)
  4. {
  5. foreach (var item in e.Exception.InnerExceptions)
  6. {
  7. Logger.Error("未捕获的Task异常 " + item.InnerException.Message + " " + item.GetType().Name);
  8. }
  9. }
  10. else
  11. {
  12. Logger.Error("[Exception]未捕获的Task异常 " + e.Exception?.Message + " " + e.Exception?.StackTrace);
  13. }
  14. //将异常标识为已经观察到
  15. e.SetObserved();
  16. }

代码是修改好了,在本地如何调试呢?网上说,GC回收Task的时候,会触发Task里的异常,这个说法,应该是正确的,请看上面的堆栈信息,回收的时候,会报异常发布出去。好,那我就人为制造一个异常:

  1. Task.Run(() =>
  2. {
  3. throw new Exception("测试异常");
  4. });
  5. Thread.Sleep(2000);
  6. GC.Collect();

可是代码跑起来,没有捕获到任何异常。我以为GC没有运行,我在网上搜索答案,类似这样的写法:

  1.  
  1. Task.Run(() =>
  2. {
  3. throw new Exception("测试异常");
  4. });
  1. while(true){
  2. //不停地给数组分配内存
  3. //调用GC
  4. }

这次代码运行起来,不仅异常没有捕获到,程序直接崩溃,说内存不足,最后笔记本发烫,导致了蓝屏。我不得不重启电脑。

三、处理

网上一篇文章说,在Debug模式下,捕获不到异常。Release下可以。于是,我切换了模式,果然可以。

  1. Logger.Error("未捕获的Task异常 " + item.InnerException.Message + " " + item.GetType().Name);

在处理全局异常的方法里,我记录了日志,就这一句引发了未将对象引用到实例,调试发现  itm.InnerException为null,所以调用Message就异常了。下面,我们来处理:

  1. private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  2. {
    foreach (var item in e.Exception.InnerExceptions){
  1. Logger.Error("未捕获的Task异常 " + item.InnerException?.Message + " " + item.GetType().Name);
  2. }
    }

处理好了,日志输出:未捕获的Task异常    Exception,从调试角度看,这样的信息,就是个废话,改改代码:

  1. private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  2. {
  3. foreach (var item in e.Exception.InnerExceptions)
  4. {
  5. Logger.Error("未捕获的Task异常 " + item.Message + "," + item.StackTrace);
  6. }
  7. }

调试结果如下:

 

 这样代码就好了吗?我担心尽管处理好后,进程还会退出,网上搜了下,可以加入这句:

  1. //将异常标识为已经观察到
  2. e.SetObserved();

经过调试,发现少了这句,也不会有问题,这句意思是不让异常继续往上冒泡,到此为止。这样,程序就好了吗?还是有所担心,终极版的代码:

  1. private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  2. {
  3. try
  4. {
  5. foreach (var item in e.Exception.InnerExceptions)
  6. {
  7. Logger.Error("未捕获的Task异常 " + item.Message + "," + item.StackTrace);
  8. }
  9. }
  10. catch (Exception ex)
  11. {
  12. Logger.Error($"TaskScheduler_UnobservedTaskException处理异常:{ex.Message}");
  13. }
  14. //阻止异常冒泡
  15. e.SetObserved();
  16. }

这里之所以加上try..catch,因为担心Logger出现异常,进程照样会崩溃。所以,既想捕获应用程序中Task中的异常,又不想因此把程序整垮。

四、后记

网上的代码,仅供参考和学习,要上服务器,还得经过本地严格测试,谁知道会什么时候会引发灾难。

 

原文链接:https://www.cnblogs.com/wangqiang3311/p/17168491.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号