调用别人提供的接口无法通过try catch捕获异常(C#),见鬼了

前几天做CA签名这个需求时发现一个很诡异的事情,CA签名调用的接口是由另外一个开发部门的同事(比较难沟通的那种人)封装并提供到我们这边的。我们这边只需要把数据准备好,然后调他封装的接口即可完成签名操作。但在测试过程中,发现他提供的接口在某些边界条件时,会报错。通过反编译调试后,把报错的堆栈及要如何修改都发给了那个同事,但是他没鸟我,项目经理他不懂技术,也不想管这个事情(所以以后跳槽一定要跳到一个好一点的团队)。我该做的都已经做了,没办法,毕竟是我负责的功能需求,到时候报错了也是第一时间找到我。我这边就try catch捕获一下异常呗,神奇的事情出现了,没捕获到,而是被Application.ThreadException事件注册的方法给捕获到了(这里捕获这个词不算很恰当,即触发Application.ThreadException事件对应的方法)。我们都知道,UI线程中未捕获的异常,如果在程序的Main方法入口注册了Application.ThreadException事件对应的方法,UI线程发生异常如果未捕获并处理该异常就会触发Application.ThreadException事件对应的方法。这就说明我try catch不到他那个接口的异常信息。

我这边处理的业务逻辑代码大概可以描述为:

通过反编译看了一下"调用封装CA签名接口的代码块"对应的代码,它的大概处理流程是这样的:先通过Spring.Net接口调用CA签名的业务逻辑,记为业务逻辑A,业务逻辑A的实现流程如下:通过反射,拿到对应的CA签名的实现类(因为我们这边的代码需要兼容多个CA签名的厂商),我们这边对接的是网政通的CA,我这边就只介绍一下它的大概流程:先获取提供接口的CA用户的用户信息,记为步骤1;如果有用户信息,则需要再次调用获取用户token信息接口,记为步骤2;获取token用户信息成功后,再调用获取CA用户二维码信息的接口,获取到签章并以二维码的形式显示出来让用户进行扫码操作,记为步骤3。如果前面的步骤1不成功,后面的步骤2,3都不用继续操作了,直接返回CA签名失败,走普通签名逻辑。同事的接口报错就发生在步骤1中,没有CA用户信息时,某些代码逻辑写得不够严谨,就报错了。

至于我这边为何try catch步骤1中发生的异常信息,我做了如下的猜测并进行了验证

1   是不是spring.net的框架把它给处理了,结合前面使用过spring.net的经验,排除了这种可能性

2   是不是被反射的方法里面报错,调用方就抓不到异常,不太确定,那就用代码验证一下,后面验证过了,反射的虽然拿不到具体的报错堆栈信息,但还是能通过try catch捕获到异常信息的。

3  是不是他的代码里面有我不知道的异常处理方式,但是看了好久,也没看出哪里有特别的地方

4  是不是在不同的AppDomain的异常,就捕获不到,后面也尝试过了,也是能捕获的

前面的猜测无果后,就一路在网上查询C#中try catch不到异常的情况:

网上说的情况(未验证):有说调用非托管的代码就捕获不到异常

其它靠谱一点的捕获不到异常的情况:

文章链接1 (未做验证):Exception not caught using catch block

StackOverflowException:堆栈溢出异常

ThreadAbortedException:线程停止异常

OutOfMemoryException:堆栈溢出异常

ExcutionEngineException:执行引擎异常

BadImageFormatException:错误图片类型异常

文章链接2 (未做验证):The Uncatchable Exception

情况1:出现死递归导致内存异常的异常:

情况2:处理的异常中人工调用了Environment.FailFast,捕获不到异常,程序直接退出

不过都不是我要的解决方案,当看到Environment.FailFast时,突然灵光一闪,是不是winform框架给捕获了,然后再手工调用某个方法,会触发Application.ThreadException事件对应的方法。有了思路后,再来反调试代码,发现同事重写了winfrom窗体的OnLoad方法,在重新的OnLoad方法中完成步骤1操作,而在反编译调试中,看到winfrom窗体调用OnLoad方法的调用方捕获了异常,并调用Application.OnException触发Application.ThreadException事件对应的方法,如下图:

下面我们就一起验证一下这种情况:

测试环境:

.net framework 4.0

visual studio 2017

具体步骤如下:

1   新增名为TestMain的winfrom项目

2   编辑默认的Program类如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;namespace TestMain
{static class Program{/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.ThreadException += Application_ThreadException;Application.Run(new Form1());}private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e){MessageBox.Show("Main方法中的Application_Thread输出,详细错误信息如下:" + e.Exception.Message + e.Exception.StackTrace);}}
}

这里我注册了Application.ThreadException事件回调的方法Application_ThreadException,如果UI线程中有没有处理的异常,就会触发这个方法。

3  新增winform窗体,名为QRCodeFrm,对应的UI界面设计如下:

对应的后台代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;namespace TestMain
{public partial class QRCodeFrm : Form{public QRCodeFrm(){InitializeComponent();}protected override void OnLoad(EventArgs e){bool flag = true;if (flag){int a = 1;int b = 0;//这里会抛出异常int c = a / b;}}}
}

在这里,我们重写了OnLoad方法,然后再进行a/b的除以0操作,这里运行时会报异常

4   在默认的Form1窗体中拖入一个按钮,UI界面如下图:

button1按钮对应的逻辑如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using TestApi;namespace TestMain
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){try{QRCodeFrm frm = new QRCodeFrm();frm.ShowDialog();}catch (Exception ex){MessageBox.Show("捕获到异常,异常信息如下:"+ex.Message+ex.StackTrace);}}}
}

在button1_Click我们进行捕获异常

5  生成项目并运行,结果如下:

可以看到Application.ThreadException事件回调的方法Application_ThreadException已经被调用,接着后弹出QRCodeFrm对应的窗体,如下图:

可以看到,已经按照猜想那样进行了输出显示。

回到最初的那个问题,我们要怎么处理才能捕获到同事接口的那个异常信息呢,有个不是很靠谱的方法是,我们在合适的地方重新注册Application.ThreadException事件方法,我们都知道,通过+=的方式注册的Application.ThreadException事件方法,前面已经注册过的事件方法就会被覆盖。修改前面演示的例子中的Form1,并编辑如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using TestApi;namespace TestMain
{public partial class Form1 : Form{bool isCatch = false;string errorMessage = string.Empty;public Form1(){InitializeComponent();Application.ThreadException += New_Application_ThreadException;}private void New_Application_ThreadException(object sender, ThreadExceptionEventArgs e){errorMessage = e.Exception.Message + e.Exception.StackTrace;isCatch = true;}private void button1_Click(object sender, EventArgs e){try{QRCodeFrm frm = new QRCodeFrm();frm.ShowDialog();}catch (Exception ex){MessageBox.Show("捕获到异常,异常信息如下:"+ex.Message+ex.StackTrace);}if (isCatch){MessageBox.Show("被捕获的异常:"+errorMessage);}}}}

运行结果如下:

接着会弹出粗我提示框如下:

可以看到,Main方法中注册的Application.ThreadException事件方法的已经被新注册的方法给覆盖了

注意:这种解决方案风险比较大,我这边新增了一个参数进行控制是否进行Application.ThreadException事件方法的重新注册,等同事修改了代码,我这边就会把参数进行关闭,这算是留了一手吧

本文的内容到此结束,内容仅代表个人观点,如有写得不对的地方,望指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/211341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[后端卷前端2]

绑定class 为什么需要样式绑定呢? 因为有些样式我们希望能够动态展示 看下面的例子: <template><div><p :class"{active:modifyFlag}">class样式绑定</p></div> </template><script>export default {name: "goo…

人力资源服务展示网站作用有哪些

就业劳务问题往往是不少人群关注的问题&#xff0c;每个城市都聚集着大量求业者&#xff0c;而人力资源管理公司每年也会新增不少&#xff0c;对求业者来说&#xff0c;通过人力资源公司可以快速便捷的找到所需工作&#xff0c;而对公司来说&#xff0c;市场大量用户可以带来收…

C语言第十八集(动态内存管理)

1.malloc函数可以开辟一块空间,具体搜: 2.malloc函数申请的空间在内存的堆区 而且它只负责帮你申请空间,不负责帮你清理空间 3.free函数可以释放内存 4.free函数释放的是内存中的堆区,具体搜: 5.在free函数调用完后记得把对应的指针设为空指针 6.calloc函数跟malloc函数差…

揭秘字符串的奥秘:探索String类的深层含义与源码解读

文章目录 一、导论1.1 引言&#xff1a;字符串在编程中的重要性1.2 目的&#xff1a;深入了解String类的内部机制 二、String类的设计哲学2.1 设计原则&#xff1a;为什么String类如此重要&#xff1f;2.2 字符串池的概念与作用 三、String类源码解析3.1 成员变量3.2 构造函数3…

[今来] 神话故事:金马和碧鸡

文章目录 金马山和碧鸡山神话传说金马坊和碧鸡坊金马碧鸡 金马山和碧鸡山 昆明山明水秀&#xff0c;北枕蛇山&#xff0c;南临滇池&#xff0c;金马山和碧鸡山则东西夹峙&#xff0c;隔水相对&#xff0c;极尽湖光山色之美。金马山逶迤而玲珑&#xff0c;碧鸡山峭拔而陡峻&…

clickhouse数据库磁盘空间使用率过高问题排查

一、前言 clickhouse天天触发磁盘使用率过高告警&#xff0c;所以需要进行排查&#xff0c;故将排查记录一下。 二、排查过程 1、连接上进入clickhouse 2、执行语句查看各库表使用磁盘情况 SELECT database, table, formatReadableSize(sum(bytes_on_disk)) as disk_space F…

蓝桥杯物联网竞赛_STM32L071_8_ADC扩展模块

原理图&#xff1a; 扩展模块原理图&#xff1a; RP1和RP2分别对应着AIN1和AIN2&#xff0c;扭动它们&#xff0c;其对应滑动变阻器阻值也会变化 实验板接口原理图&#xff1a; 对应实验板接口PB1和PB0 即AN1对应PB1, AN2对应PB0 CubMx配置&#xff1a; ADC通道IN8和IN9才对…

uniApp项目的创建,运行到小程序

一、项目创建 1. 打开 HBuilder X 2. 右击侧边栏点击新建&#xff0c;选择项目 3. 填写项目名&#xff0c;点击创建即可 注&#xff1a;uniapp中如果使用生命周期钩子函数&#xff0c;建议使用哪种 ?(建议使用Vue的) 二、运行 1. 运行前先登录 2. 登录后点击 manifest.js…

基于lambda简化设计模式

前言 虽说使用设计模式可以让复杂的业务代码变得清晰且易于维护&#xff0c;但是某些情况下&#xff0c;开发可能会遇到我为了简单的业务逻辑去适配设计模式的情况&#xff0c;本文笔者就以四种常见的设计模式为例&#xff0c;演示如何基于lambda来简化设计模式的实现。 策略…

WorkPlus高效助力企业沟通的专业级即时通讯软件

在当今高度信息化和全球化竞争的世界&#xff0c;企业需要一个高效便捷的沟通工具来促进团队协作、提高工作效率。在这样的背景下&#xff0c;WorkPlus作为一款专业级的即时通讯软件应运而生。让我们一起深入了解WorkPlus&#xff0c;探讨其在企业沟通中的领先优势和卓越能力。…

平衡二叉树

AVL简称平衡二叉树&#xff0c;缩写为BBST&#xff0c;由苏联数学家 Adelse-Velskil 和 Landis 在 1962 年提出。 二叉树是动态查找的典范&#xff0c;但在极限情况下&#xff0c;二叉树的查找效果等同于链表&#xff0c;而平衡二叉树可以完美的达到 log ⁡ 2 n \log_2 n log2…

ElementPlus table 中嵌套 input 输入框

文章目录 需求分析 需求 vue3 项目中 使用UI组件库 ElementPlus 时&#xff0c;table 中嵌入 input输入框 分析 <template><div class"p-10"><el-table :data"tableData" border><el-table-column prop"date" label&qu…

课堂练习4.1:段式内存管理

4-1 课堂练习4.1&#xff1a;段式内存管理 段式内存管理以段为单位分配内存空间&#xff0c;段内连续&#xff0c;段间可以不连续。段可以很大&#xff0c;比如数据段、代码段、栈段等。本实训分析 Linux 0.11 的段式内存管理技术。 第1关1 号进程 mynext 变量的逻辑地址与线性…

cache教程 3.HTTP服务器

上一节我们实现了单机版的缓存服务&#xff0c;但是我们的目标是分布式缓存。那么&#xff0c;我们就需要把缓存服务部署到多态机器节点上&#xff0c;对外提供访问接口。客户端就可以通过这些接口去实现缓存的增删改查。 分布式缓存需要实现节点间通信&#xff0c;而通信方法…

【面试经典150 | 二叉树】翻转二叉树

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;递归方法二&#xff1a;迭代 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题…

4-SpringMVC

文章目录 项目源码地址回顾-MVC什么是MVC&#xff1f;MVC各部分组成 回顾-ServletMaven创建Web项目1、创建Maven父工程pom&#xff0c;并导入依赖2、用Maven新建一个Web Module3、代码&#xff1a;HelloServlet.java3、代码-hello.jsp3、代码-web.xml4、配置Tomcat5、浏览器测试…

github使用方法【附安装包】

如果你是一枚Coder&#xff0c;但是你不知道Github&#xff0c;那么我觉的你就不是一个菜鸟级别的Coder&#xff0c;因为你压根不是真正Coder&#xff0c;你只是一个Code搬运工。说明你根本不善于突破自己&#xff01;为什么这么说原因很简单&#xff0c;很多优秀的代码以及各种…

高级系统架构设计师之路

前言&#xff1a;系 统 架 构 设 计 师 (System Architecture Designer)是项目开发活动中的众多角色之 一 &#xff0c;它可 以是 一个人或 一个小组&#xff0c;也可以是一个团队。架构师 (Architect) 包含建筑师、设计师、创造 者、缔造者等含义&#xff0c;可以说&#xff0…

边缘计算系统设计与实践:引领科技创新的新浪潮

文章目录 一、边缘计算的概念二、边缘计算的设计原则三、边缘计算的关键技术四、边缘计算的实践应用《边缘计算系统设计与实践》特色内容简介作者简介目录前言/序言本书读者对象获取方式 随着物联网、大数据和人工智能等技术的快速发展&#xff0c;传统的中心化计算模式已经无法…

基于ssm人力资源管理系统论文

摘 要 随着企业员工人数的不断增多&#xff0c;企业在人力资源管理方面负担越来越重&#xff0c;因此&#xff0c;为提高企业人力资源管理效率&#xff0c;特开发了本人力资源管理系统。 本文重点阐述了人力资源管理系统的开发过程&#xff0c;以实际运用为开发背景&#xff0…