Note that there are some explanatory texts on larger screens.

plurals
  1. PODealing with non-serializable unhandled exceptions from a child AppDomain
    primarykey
    data
    text
    <p>We are using System.AddIn to load add-ins into separate child AppDomains, and we unload the add-in AppDomain if it has an unhandled exception.</p> <p>Because the default behaviour of .NET from version 2.0 was to tear down the entire process if any AppDomain has an unhandled exception, we do this by using the "legacyUnhandledExceptionPolicy" option in our App.config and then manually tearing down the process if the unhandled exception was in the main AppDomain, or unloading the appropriate AppDomain if it was in an add-in.</p> <p>This is all working great, except for one small issue: Unhandled exceptions always bubble up from the child AppDomains to the main one, and if they aren't serializable they can't successfully cross the AppDomain boundary. </p> <p>Instead we get a SerializationException appearing as an UnhandledException in the main AppDomain, causing our application to tear itself down.</p> <p>I can think of a few possible solutions to this problem:</p> <ul> <li><p>We could not tear down the process for unhandled SerializationExceptions (yuck).</p></li> <li><p>We could stop exceptions from propagating from the child AppDomain to the main AppDomain.</p></li> <li><p>We could replace the unserializable exceptions with serializable ones, maybe using serialization surrogates and serialization binders. [Edit: see end for why this isn't possible using surrogates]</p></li> </ul> <p>However the first one is pretty horrible, and I've been unsuccessful in figuring out how to do either of the other options with cross-AppDomain remoting.</p> <p>Can anyone offer some advice? Any help is appreciated.</p> <p>To reproduce create a console application with the following App.config:</p> <pre><code>&lt;?xml version="1.0"?&gt; &lt;configuration&gt; &lt;runtime&gt; &lt;legacyUnhandledExceptionPolicy enabled="true"/&gt; &lt;/runtime&gt; &lt;/configuration&gt; </code></pre> <p>And the following code:</p> <pre><code>class Program { private class NonSerializableException : Exception { } static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += MainDomain_UnhandledException; AppDomain childAppDomain = AppDomain.CreateDomain("Child"); childAppDomain.UnhandledException += ChildAppDomain_UnhandledException; childAppDomain.DoCallBack( () =&gt; new Thread(delegate() { throw new NonSerializableException(); }).Start()); Console.ReadLine(); } static void MainDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Console.WriteLine("Main AppDomain Unhandled Exception: " + e.ExceptionObject); Console.WriteLine(); } static void ChildAppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Console.WriteLine("Child AppDomain Unhandled Exception: " + e.ExceptionObject); Console.WriteLine(); } } </code></pre> <p><br/></p> <hr> <p>EDIT: I used reflector to see if there was any way to gain access to the BinaryFormatter used in cross-AppDomain remoting, but it ends up in this code inside the CrossAppDomainSerializer class:</p> <pre><code>internal static void SerializeObject(object obj, MemoryStream stm) { BinaryFormatter formatter = new BinaryFormatter(); RemotingSurrogateSelector selector = new RemotingSurrogateSelector(); formatter.SurrogateSelector = selector; formatter.Context = new StreamingContext(StreamingContextStates.CrossAppDomain); formatter.Serialize(stm, obj, null, false); } </code></pre> <p>So it creates the formatter locally in the method, and there is clearly no way to attach my own surrogate... I think this makes any more efforts in that direction futile.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload