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

本文主要是介绍调用别人提供的接口无法通过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事件方法的重新注册,等同事修改了代码,我这边就会把参数进行关闭,这算是留了一手吧

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

这篇关于调用别人提供的接口无法通过try catch捕获异常(C#),见鬼了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/477178

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

三国地理揭秘:为何北伐之路如此艰难,为何诸葛亮无法攻克陇右小城?

俗话说:天时不如地利,不是随便说说,诸葛亮六出祁山,连关中陇右的几座小城都攻不下来,行军山高路险,无法携带和建造攻城器械,是最难的,所以在汉中,无论从哪一方进攻,防守方都是一夫当关,万夫莫开;再加上千里运粮,根本不需要打,司马懿只需要坚守城池拼消耗就能不战而屈人之兵。 另一边,洛阳的虎牢关,一旦突破,洛阳就无险可守,这样的进军路线,才是顺势而为的用兵之道。 读历史的时候我们常常看到某一方势

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

Thymeleaf:生成静态文件及异常处理java.lang.NoClassDefFoundError: ognl/PropertyAccessor

我们需要引入包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>sp

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中, "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时,经常听到第一范式(1NF)、第二范式(2NF)、第三范式(3NF)以及 BCNF(Boyce-Codd范式)。这些范式都旨在通过消除数据冗余和异常来优化数据库结构。然而,当我们谈到 4NF(第四范式)时,事情变得更加复杂。本文将带你深入了解 多值依赖 和 4NF,帮助你在数据库设计中消除更高级别的异常。 什么是

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“