Prevent outer exception from being discarded when thrown from BeginInvoke

◇◆丶佛笑我妖孽 提交于 2019-12-03 12:01:30

I am assuming that you are seeing this behaviour on an x64 Windows system and this is a - rather unknown - implementation detail of x64 Windows. Read up on it here

The article goes into details on how to solve this problem by applying some hotfix, that was allegedly shipped with Win7 SP1, but I ran into this issue a few weeks back on Win7 SP1.

Additionally you could attach to AppDomain.FirstChanceException event which gives you access to every exception before it is passed to the CLR for handling

The recommended way to propagate the Exception to a higher layer (aside from implicitly rethrowing by Waiting on the Task) is to remove the catch-all in the Task body and instead register a Fault continuation on the Task using Task.ContinueWith, specifying TaskContinuationOptions.OnlyOnFaulted. If you're working through an intermediate layer and don't have access to the Task, you can further wrap this in your own UnhandledException events to pass the Exception object upward.

One way to do it is to put the inner-exception reference in a custom property or the Data dictionary -- i.e., leave the InnerException property null, and carry the reference some other way.

Of course, this requires establishing some kind of convention that can be shared between the throwing code and the handling code. The best would probably be to define a custom exception class with a custom property, in a project that's referenced by both pieces of code.

Sample code (though it needs more comments to explain why it's doing the crazy things it's doing):

public class ExceptionDecorator : Exception {
    public ExceptionDecorator(Exception exception) : base(exception.Message) {
        Exception = exception;
    }
    public Exception Exception { get; private set; }
}

// To throw an unhandled exception without losing its InnerException:
BeginInvoke(new Action(() => { throw new ExceptionDecorator(outer); }));

// In the ThreadException handler:
private void OnUnhandledException(object sender, ThreadExceptionEventArgs e) {
    var exception = e.Exception;
    if (exception is ExceptionDecorator)
        exception = ((ExceptionDecorator) exception).Exception;
    // ...
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!