We seem to be having some "interesting" behavior with unhandled exceptions in WPF.
In a nutshell, the same exception thrown twice on the dispatcher thread in a short period of time will bypass the dispatcher unhandled exception handler and bring down the application.
Now add a button, and in the click handler add the following:
SynchronizationContext.Current.Post(s => { throw new Exception(); }, null);
SynchronizationContext.Current.Post(s => { throw new Exception(); }, null);
You will notice that the DispatcherUnhandledException handler is raised twice, both exceptions handled, and all is well.
However, change the code above to the following:
var ex = new Exception();
SynchronizationContext.Current.Post(s => { throw ex; }, null);
SynchronizationContext.Current.Post(s => { throw ex; }, null);
And you will find that AppDomain.CurrentDomain.UnhandledException handler is raised and the application will crash with the typical windows "would you like to debug" dialog.
It may seem that this example is contrived, which it is just to simplify the question. This scenario can happen however if say you have two RX subscribers to a stream which errors. In this case both subscribers raise the same exception causing the same behavior as above. For instance, the following RX code in the button click handler will also reproduce the issue (also contrived but you can get into equivalent situations):
var o = Observable.Start(() => { throw new Exception(); }).Publish();
o.ObserveOnDispatcher().Subscribe(_ => { });
o.ObserveOnDispatcher().Subscribe(_ => { });
o.Connect();
It seems that this is Dispatcher behaviour, it will check to see if it has "seen" the exception before (by adding a tag into the exception's data) and only handle it if it hasn't:
private bool ExceptionFilter(Exception e)
{
// see whether this dispatcher has already seen the exception.
// This can happen when the dispatcher is re-entered via
// PushFrame (or similar).
if (!e.Data.Contains(ExceptionDataKey))
{
// first time we've seen this exception - add data to the exception
e.Data.Add(ExceptionDataKey, null);
}
else
{
// we've seen this exception before - don't catch it
return false;
}
....
What this means is we are likely going to have to catch and re-wrap exceptions (i.e creating new exception objects so the dispatcher doesn't see them as the same) so that they do not bring the application down.