C# AppDomain,处理异常

C# AppDomain,处理异常,c#,.net,C#,.net,我正在开发一个由许多较小的插件/应用程序组成的大型应用程序 它们不够大,不能成为一个完整的进程,但太小,不能在一个线程中运行,在一个进程下运行,我希望它基于插件。 如果该插件的更新版本可用,则应卸载、更新并重新启动该插件 在我搜索解决方案的过程中,我可以使用神奇的词AppDomain,我引用: “使用应用程序域隔离可能导致系统崩溃的任务 如果正在执行任务的AppDomain的状态变为 不稳定,AppDomain可以在不影响进程的情况下卸载。 当一个进程必须长时间运行而不发生故障时,这一点很重要

我正在开发一个由许多较小的插件/应用程序组成的大型应用程序

它们不够大,不能成为一个完整的进程,但太小,不能在一个线程中运行,在一个进程下运行,我希望它基于插件。 如果该插件的更新版本可用,则应卸载、更新并重新启动该插件

在我搜索解决方案的过程中,我可以使用神奇的词AppDomain,我引用:

“使用应用程序域隔离可能导致系统崩溃的任务 如果正在执行任务的AppDomain的状态变为 不稳定,AppDomain可以在不影响进程的情况下卸载。 当一个进程必须长时间运行而不发生故障时,这一点很重要 正在重新启动。您还可以使用应用程序域隔离 不应共享数据。”

因此,这正是我想要的。然而,我猜他们的“状态变得不稳定”与我的观点不同。我正在考虑一个问题,其中一个插件抛出异常,不管是出于什么原因。我希望这是捕捉,电子邮件,卸载和重新启动(如果可能的话)

所以我创建了一个应用程序,它可以启动,在它的文件夹中查找所有的.dll。检查dll是否包含插件。为该插件创建一个新的AppDomain,加载所有内容后,它将启动每个插件。(每个插件可以由多个线程组成,彼此相邻地共存)

因此,我还添加了一个超时,它在5秒后触发,以抛出一个新的异常();在AppDomain上添加了一个未处理的异常事件来处理它。但是,它捕捉到了它,并且在引导之后,仍然“崩溃”了整个过程,包括所有额外的子应用程序域


但它在引文中明确指出“隔离那些“可能”拖垮流程的任务”。我是不是错过了一些重要的东西?我对引用的看法是否有误?

AppDomain更常用于卸载程序集(如您的建议)和控制启动参数,如.NET访问级别、配置等。如果您确实想要“隔离”,那么最好的选择始终是工作进程;然而,这需要做更多的工作

我在几个项目中做了大量的工作。为了提供一个概括性的画面,我们在大多数通信中使用()over a。对于工作进程管理,我们在很大程度上依赖于命名事件,我最近发布了一篇仅用于此目的的文章。

自.NET 2.0以来。从事件文档中:

此事件提供未捕获异常的通知。它允许 应用程序在系统启动之前记录有关异常的信息 默认处理程序向用户报告异常并终止 应用程序

这同样适用于:

此事件仅为通知。处理此事件不会处理 异常或异常会以任何方式影响后续的异常处理

你们需要考虑你们将如何处理异常,就像你们在普通应用程序中一样。仅仅使用AppDomains是没有帮助的。如果在给定的AppDomain中未处理该异常,则它将在调用AppDomain时重新处理,直到该异常得到处理或进程崩溃。处理异常是非常好的,不要让它们使您的进程崩溃

AppDomain是程序集和内存(而不是线程)的逻辑容器。AppDomain的隔离意味着:

  • 域B无法直接访问在域A中创建的对象(无封送处理)。这允许卸载域A而不影响域B中的任何内容。卸载“拥有”域时,这些对象将自动删除

  • 可以使用AppDomain自动卸载程序集。这是从进程中卸载托管dll的唯一方法。这对于DLL热交换非常有用

  • AppDomain安全权限和配置可以与其他AppDomain隔离。当您加载不受信任的第三方代码时,这会很有帮助。它还允许您覆盖程序集的加载方式(版本绑定、卷影复制等)

使用AppDomain的最常见原因是运行不受信任的第三方代码。或者您有非托管代码,希望托管CLR或需要dll热交换。我认为在场景中,当第三方代码抛出未经处理的异常时,您将避免崩溃

另外,您可能不想查看自己的基础架构。

未处理的异常存在两个问题。AppDomain只解决其中一个问题。你在试着对付另一个

首先是好消息。处理异常时,必须恢复程序状态,就好像从未发生异常一样。在代码运行之前,所有内容都必须重新缠绕到状态。您通常有一组catch和finally子句,用于撤消代码执行的状态突变。当然不是很简单。但如果异常未处理,则完全不可能。你不知道到底是什么发生了变异,以及如何恢复它。AppDomain冷静地处理这个非常困难的问题。你卸载它,剩下的状态就消失了。不再有垃圾收集堆,不再有装载器堆(静态)。整个enchilada将重置为创建AppDomain之前的任何状态

太好了。但还有一个问题也很难解决。您的程序被要求执行作业。线程开始做那项工作。但它心脏病发作了。第一个大问题:线程死了。如果您的程序只有一个线程开始,这将是一个非常坏的消息。没有线程了,程序终止。很高兴AppDomain先卸载了,但这真的没有什么区别,反正它已经卸载了

还有一个大问题:完成这项工作真的相当重要。没有。这很重要,比如说,这份工作是给b的