C#, MAF, Unhandled Exception Management in separat

2019-07-07 09:34发布

问题:

Okay, so I have a MAF application which loads up each addin inside of a separate appdomain. This is working fantastic for what I need as it allows me to dynamically unload and reload my addins at runtime.

The problem is, I need to be able to take an unhandled exception in the child appdomain, catch it, and then let that appdomain fail gracefully without taking down the parent appdomain

How do I go about doing this? It seems like a trivial task and one of the main benefits of using isolated appdomains...

回答1:

I think my answer to this similar question should help you:

Application crash when anoter domain throws exception

Let me know if you need any more information.



回答2:

As far as I know, you cannot do that out of the box. You could use abstract classes for the add-in views and add try/catch blocks everywhere combined with the Template Method pattern (i.e. the Read method in the abstract add-in view calls a virtual ReadCore function which the add-in should implement). Still you cannot handle unhandled exceptions thrown from child threads of the child AppDomain. These will crash your app.

Again as far as I know, there are two ways to handle this problem:

  1. Use process isolation. This is the only way to be sure that the add-ins will not crash the host.
  2. Follow the approach described in the Using AppDomain Isolation to Detect Add-In Failures article from the System.AddIn team's blog. This approach cannot stop your app from crashing but your app will know which add-in caused the crash. This is valuable information because then your app can disable the unstable add-ins and avoid loading them the next time it starts. Or the app can inform the user and let him/her decide what to do.

Note that these two are complementary. You can start with 2. and then load unstable add-ins on different processes.



回答3:

Wound up going with an approach that appears to be working great today, though I still have some digging to do before I find out the ramifications of this approach...

The following blog post helped immensely: http://ikickandibite.blogspot.com/2010/04/appdomains-and-true-isolation.html

I simply enabled the legacy unhandled exception policy in the app.config:

(which, as an FYI, is still available even in .Net 4.5, which I was concerned about)

<?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>

...From which point I can use the AppDomain.UnhandledException event to intercept an unhandled exception and unload the sub-domain...(note that I say 'intercept' here loosely...I'm still not 'catching' the exception, just taking note of it an unloading the addin in the process)

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);
    }
}