是否可以防止子 AppDomain 中的未处理异常导致主进程崩溃?

2023-11-27

我正在编写一个小型插件库,它使用应用程序域来隔离使用 .Net Framework 4.0 的插件。因此,每个插件中的代码超出了我的控制范围。当其中一个插件中引发未处理的异常时,我观察到结果是好坏参半。它们如下。

当插件的主线程中抛出未处理的异常时,调用插件的执行方法的主可插拔应用程序能够干净地捕获并处理它。那里没有问题。然而,

  1. 如果插件在插件的 Execute 方法中为基于 WinForms 的应用程序启动消息循环,并且在 WinForm 应用程序(即在表单中)中抛出未处理的异常,则可插入应用程序只能在从 Visual Studio 调试器内部运行时捕获异常。否则(当在 VS 外部调用时)主可插拔应用程序将与插件一起崩溃。

  2. 如果未处理的异常在插件的 Execute 方法生成的单独线程中引发,则可插入应用程序没有机会捕获异常并且会崩溃。

我在下面的链接中创建了一个简单的 VS 2010 项目来模拟这种行为。http://www.mediafire.com/file/1af3q7tzl68cx1p/PluginExceptionTest.zip

其中可插入应用程序的主要方法如下所示

namespace PluginExceptionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press enter to load plugin");
            Console.ReadLine();

            Assembly entryAsm = Assembly.GetEntryAssembly();
            string assemblyFileName = Path.Combine(Path.GetDirectoryName(entryAsm.Location), "EvilPlugin.exe");


            AppDomainSetup domainSetup = new AppDomainSetup();
            AppDomain domain = AppDomain.CreateDomain("PluginDomain", null, domainSetup);
            PluginBase plugin = (PluginBase)domain.CreateInstanceFromAndUnwrap(assemblyFileName, "EvilPlugin.Plugin");

            Console.WriteLine("Plugin Loaded.");

            //SCENARIO 1: WinForms based plugin
            Console.WriteLine("Press Enter to execute winforms plugin. (Remember to click on the button in the form to raise exception)");
            Console.ReadLine();

            try
            {
                plugin.ExecuteWinApp();
            }
            catch (Exception)
            {
                //The exception is caught and this gets executed only when running in visual studio debugger. Else application exits. Why?
                Console.WriteLine("WinForms plugin exception caught. However same does not happen when run out of visual studio debugger. WHY?");
            }

            //SCENARIO 2: WinForms based plugin
            Console.WriteLine("Press Enter to execute threading plugin, wait for 3 seconds and the app will exit. How to prevent app from exiting due to this?");
            Console.ReadLine();
            try
            {
                plugin.ExecuteThread();
            }
            catch (Exception)
            {
                //This never gets executed as the exception is never caught. Application exits. Why?
                Console.WriteLine("WinForms plugin exception caught");
            }

            Console.ReadLine();
        }
    }
}

这是插件项目的代码。它继承自上面可插入应用程序项目中的PluginBase 类。

namespace EvilPlugin
{
    public class Plugin:PluginBase
    {
        public Plugin():base()
        {

        }

        public override void ExecuteWinApp()
        {            
            Application.Run(new Form1());            
        }

        public override void ExecuteThread()
        {
            Thread t = new Thread(new ThreadStart(RaiseEx));           
            t.Start();
        }

        private void RaiseEx()
        {
            Thread.Sleep(3000);
            throw new Exception("Another Evil Exception in a seperate thread");
        }
    }
}

最后这是插件中表单的代码

namespace EvilPlugin
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnException_Click(object sender, EventArgs e)
        {
            throw new Exception("Evil Exception");
        }
    }
}

如何防止主进程由于上述两种情况(1和2)而退出?

提前致谢。


用于处理 WinForms 异常。您可以在 PluginBase 类中为此类 ThreadException 设置“陷阱”:

public abstract class PluginBase:MarshalByRefObject
{
    protected PluginBase()
    {
        System.Windows.Forms.Application.ThreadException +=
            (o, args) =>
            {
                throw new Exception("UntrappedThread Exception:" + args.Exception);
            };

    }

    public abstract void ExecuteWinApp();
    public abstract void ExecuteThread();
}

默认情况下,它将显示“异常窗口”。但如果提供的话,将到达此处理程序。

至于从其他线程捕获异常。不可能。您能做的最好的事情就是收到有关抛出异常的通知。

    AppDomain domain = AppDomain.CreateDomain("PluginDomain", null, domainSetup);
    domain.UnhandledException +=
        (o, eventArgs) =>
            {
                Console.WriteLine("Exception was caught from other AppDomain: " + eventArgs.ExceptionObject);
                Console.WriteLine("CLR is terminating?: " + eventArgs.IsTerminating);
            };
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以防止子 AppDomain 中的未处理异常导致主进程崩溃? 的相关文章

  • 如何使用 .net 2.0 中的 WebBrowser 控件检查 ajax 更新?

    我有一个网页正在使用 WebBrowser 控件在 winform 应用程序中显示 我需要在网页中的 HTML 发生变化时执行一个事件 但是 我找不到通过 Ajax 更新页面时触发的事件 DocumentComplete FileDownl
  • C++/CLI 中的 Lambda 表达式

    如何在 C CLI 中使用 lambda 表达式 在 C 中 lambda 实际上只是用于创建委托的语法糖 C CLI支持代表 http www functionx com cppcli classes Lesson15c htm 因此您仍
  • 如何在 IIS 中手动配置虚拟目录

    我正在尝试让外部 Visual Studio 解决方案在 Visual Studio Professional 2010 的本地副本中工作 当我打开该解决方案时 我看到一条错误消息 指出本地 IIS URL 尚未配置 我想创建一个虚拟目录吗
  • GetEventLogs() 返回没有设置事件日志?

    采取以下 C 代码 EventLog eventLogs eventLogs EventLog GetEventLogs computername foreach EventLog evt in eventLogs statusMessag
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • Rx.NET 中是否有一个Subject 实现,其功能类似于BehaviourSubject,但仅在值发生更改时才发出?

    有没有Subject https learn microsoft com en us previous versions dotnet reactive extensions hh229699 v vs 103 Rx NET 中的实现在功能
  • 假装 .NET 字符串是值类型

    在 NET 中 字符串是不可变的 并且是引用类型变量 这通常会让新的 NET 开发人员感到惊讶 因为他们的行为可能会将它们误认为是值类型对象 然而 除了使用实践StringBuilder对于长连接 尤其是 在循环中 在实践中是否有任何理由需
  • 从共享网络文件夹运行的 .NET 应用程序的性能损失

    从共享网络文件夹运行 NET 4 0 应用程序是否有任何性能损失 我发现哪个应用程序启动速度较慢 但 在使用时没有注意到任何变慢 但不确定 当通过网络运行可执行文件时 Windows 不会在应用程序启动时通过网络传输整个应用程序 这样做是为
  • 父进程和子进程如何进行信号量操作?

    semget 调用是否在父进程和子进程之间共享信号量 我有这段代码 对于相同的代码 我观察到如果父进程首先运行 子进程有时会获得更改后的信号量值 但是当子进程首先运行时 父进程似乎永远不会携带更改后的信号量 为什么会发生这种情况 谁能向我解
  • Visual Studio '17 未在参考管理器中显示程序集

    我遇到的问题是 我似乎无法弄清楚如何添加对某些解决方案的引用 在我从 Visual Studio 17 开始的大多数解决方案中 我在解决方案资源管理器中看到 引用 但例如对于 asp net core web api 我得到 依赖项 每当解
  • 获取 Windows 窗体应用程序的执行目录的路径

    我想获取 Windows 窗体应用程序的执行目录的路径 即可执行文件所在的目录 有谁知道 NET 中的内置方法可以做到这一点 在VB NET中 Dim directory as String My Application Info Dire
  • 如何在嵌套列表视图中编辑数据

    我使用列表视图来显示项目列表 并使用嵌套列表视图来显示每个项目的功能列表 父列表视图和子列表视图都需要能够进行插入 编辑和删除操作 它适用于父列表视图 但是 当我尝试编辑子项目时 编辑按钮不会将其带入编辑模式 您能建议我代码中缺少什么吗
  • 按字母顺序对列表进行排序

    我有以下课程 class Detail public Detail details new List
  • ASP.NET AJAX 进度条:从代码隐藏更新?

    我在应用程序中具有 Excel 电子表格的导入功能 目前它使用 FileUpload 控件 我上传文件 然后对该文件运行操作 我想通知用户正在完成的操作以及完成的百分比 我认为我可以获取从 Excel 电子表格中提取的总行数 并在将每条记录
  • 杀死使用popen2创建的进程

    我正在使用函数 popen2 已在 stackoverflow 上的其他地方推荐 以编程方式创建一个必须在一段时间后再次终止的进程 popen2 返回一个 PID 我认为这个 PID 可以用来杀死该进程 但这种方式行不通 为了杀死它 我必须
  • .NET:SqlDataReader.Close 或 .Dispose 导致超时过期异常

    当尝试在 SqlDataReader 上调用 Close 或 Dispose 时 我收到超时过期异常 如果您有到 SQL Server 的 DbConnection 您可以使用以下命令自行重现它 String CRLF r n String
  • Ajax 函数在重定向后不保存滚动位置

    正如标题所述 我编写了一个 ajax 函数 该函数应该滚动到用户在重定向之前所在的位置 我写了一个alert对于测试场景 它确实触发了 但滚动不断回到顶部 我在这里做错了什么 JavaScript ajax type GET url Adm
  • DataContractJsonSerializer 包含元素类型子类型的通用列表

    我要使用DataContractJsonSerializer用于 JSON 序列化 反序列化 我在 JSON 数组中有两种对象类型 并希望将它们都反序列化为相应的对象类型 具有以下类定义 DataContract public class
  • 如何将对 System.Data.DataSetExtensions 的引用添加到网站 ascx.cs 文件?

    我们正在处理一个网站项目并尝试参考System Data DataSetExtensions 使用 Web 应用程序会更好 不过 技术主管有她的理由 这是我们尝试过的 找到装配路径 打开 Visual Studio 命令提示符并运行sn e
  • 频繁插入已排序的集合

    我已经对集合 列表 进行了排序 并且我需要始终保持其排序 我目前在我的集合上使用 List BinarySearch 然后在正确的位置插入元素 我也尝试过在每次插入后对列表进行排序 但性能不可接受 有没有一种解决方案可以提供更好的性能 也许

随机推荐