C#、MAF、单独 AppDomain 中的未处理异常管理

Posted

技术标签:

【中文标题】C#、MAF、单独 AppDomain 中的未处理异常管理【英文标题】:C#, MAF, Unhandled Exception Management in separate AppDomain 【发布时间】:2013-05-07 22:42:28 【问题描述】:

好的,所以我有一个 MAF 应用程序,它在单独的 appdomain 中加载每个插件。这非常适合我的需要,因为它允许我在运行时动态卸载和重新加载我的插件。

问题是,我需要能够在子 appdomain 中处理未处理的异常,捕获它,然后让该 appdomain 优雅地失败而不关闭父 appdomain

我该怎么做呢?这似乎是一项微不足道的任务,也是使用隔离应用程序域的主要好处之一......

【问题讨论】:

MAF != MEF??... 听起来很有趣 大声笑,希望我可以使用 MEF,但缺少模块重新加载功能很糟糕 =( 【参考方案1】:

我认为我对这个类似问题的回答应该对您有所帮助:

Application crash when anoter domain throws exception

如果您需要更多信息,请告诉我。

【讨论】:

【参考方案2】:

据我所知,您无法开箱即用。您可以将抽象类用于加载项视图,并结合模板方法模式在任何地方添加 try/catch 块(即,抽象加载项视图中的 Read 方法调用加载项应实现的虚拟 ReadCore 函数)。您仍然无法处理从子 AppDomain 的子线程抛出的未处理异常。这些会使您的应用崩溃。

再次,据我所知,有两种方法可以处理这个问题:

    使用进程隔离。这是确保加载项不会使主机崩溃的唯一方法。 遵循System.AddIn 团队博客中的Using AppDomain Isolation to Detect Add-In Failures 文章中描述的方法。这种方法不能阻止您的应用程序崩溃,但您的应用程序会知道哪个加载项导致了崩溃。这是有价值的信息,因为这样您的应用程序可以禁用不稳定的加载项并避免在下次启动时加载它们。或者应用可以通知用户并让他/她决定做什么。

请注意,这两者是互补的。您可以从 2. 开始,然后在不同的进程上加载不稳定的加载项。

【讨论】:

【参考方案3】:

最终选择了一种在今天看来效果很好的方法,尽管在我发现这种方法的后果之前我还有一些工作要做......

以下博文帮助很大: http://ikickandibite.blogspot.com/2010/04/appdomains-and-true-isolation.html

我只是在 app.config 中启用了遗留的未处理异常策略:

(作为一个仅供参考,即使在 .Net 4.5 中仍然可用,我很担心)

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
    <runtime>
        <legacyUnhandledExceptionPolicy enabled="true"/>
    </runtime>
</configuration>

...从那时起,我可以使用 AppDomain.UnhandledException 事件来拦截未处理的异常并卸载子域...(请注意,我在这里松散地说“拦截”...我仍然不是'捕捉'异常,只需注意它在过程中卸载插件)

Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(IApplicationAddIn), pipelineStoreLocation, addInPath);

foreach (AddInToken token in tokens)

    AppDomain domain = AppDomain.CreateDomain(token.Name);
    domain.UnhandledException += (sender, args) =>
        
            AppDomain _domain = (AppDomain) sender;
            AppDomain.Unload(_domain);
        ;
    Console.WriteLine("Initializing add-in '0'", token.Name);
    IAddIn addin = token.Activate<IAddIn>(domain);

    try
    
        addin.Initialize(this);
    
    catch (Exception ex)
    
        Console.WriteLine("Problem initializing add-in '0': 1", token.Name, ex.Message);
    

【讨论】:

@JamesThurley 你比我答得好,我给你功劳哈哈

以上是关于C#、MAF、单独 AppDomain 中的未处理异常管理的主要内容,如果未能解决你的问题,请参考以下文章

C# - 从另一个 AppDomain 中的方法返回值

C#:进程线程应用程序域(AppDomain)与上下文分析

C# 截获某个域中未捕获的异常

受限 AppDomain 中的加载项应如何访问升级服务

C#]插件编程框架 MAF 开发总结

受限 AppDomain 中的 C# 类继承自位于主 AppDomain 中的其他类