Winforms application still crashes after handling an unhandled exception handler

I applied these handlers in a test application :

Application.ThreadException += Application_ThreadException; Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 

Then I create an exception for the nested / Async task in the form:

Despite the dismissal of the handler - CurrentDomain.UnhandledException - the application still crashes.

Why should he fail, and not show a dialogue and work?

System.Exception error was not processed Message: An unhandled exception of type "System.Exception" occurred in mscorlib.dll Additional information: dd

 private async void button1_Click(object sender, EventArgs e) { Console.WriteLine("Main " + Thread.CurrentThread.ManagedThreadId); try { await Hello(); } catch (Exception ex) { Console.WriteLine("Exception on main " + Thread.CurrentThread.ManagedThreadId); } } private async static Task Hello() //changed from void { await Task.Run(() => new IGetRun().Run1()); } internal class IGetRun { public async Task Run1() //changed from void { Console.WriteLine("Run1 " + Thread.CurrentThread.ManagedThreadId); await Task.Run(() => new IGetRun2().Run2()); } } internal class IGetRun2 { public void Run2() { Console.WriteLine("Run2 " + Thread.CurrentThread.ManagedThreadId); throw new Exception("dd"); } } 

EDIT: Looks like I forgot to declare every asynchronous method using Task, not void, so exception handling works predictably now. The only thing I still don’t know is why - if I stop processing the exception in the button event - when the exception is caught Application_ThreadException is TaskScheduler_UnobservedTaskException and not TaskScheduler_UnobservedTaskException

+6
source share
2 answers

Your source code does what you never need to do: calling async void methods. And the problem for handling exceptions is one of the reasons for this.

Look at the event handlers one by one:

  • Application.ThreadException handles only exceptions in the Winforms UI thread. The exception never got into the user interface thread, so this event does not fire.
  • TaskScheduler.UnobservedTaskException handles exceptions from Task that are unobservable (and even then it does it when they are completed, which can take a long time if you do not allocate a lot of memory). But an inconspicuous exception is not tied to any Task , therefore it also does not work.
  • AppDomain.CurrentDomain.UnhandledException handles all exceptions that are still considered unobservable after the previous two event handlers. But it cannot be used to set an exception, as it is, so the application still terminates. This is the only handler that really fires.

Why exactly the first two handlers do not work? In your code, you have Task.Run(() => new IGetRun().Run1()) , where Run1() is the async void method that throws an exception.

If there is an invisible exception in the async void method, the exception returns to the current synchronization context. But since this method works in a thread pool thread (due to Task.Run() ), there is no synchronization context. Thus, an exception is thrown into the thread pool thread, which is not observed for the first two event handlers.

As you already found out, the fix for this problem is to use the async Task and await methods correctly.


Updated Run1() code now uses the async Task method. This Task deployed by Task.Run() and then await ed, so the exception is thrown to Hello() Task . This, in turn, is await ed from the async void button1_Click in the user interface thread.

All of this means that there are no invisible Task exceptions and that the exception is returned in the context of user interface synchronization. In Winforms, this means that Application.ThreadException raised, which is exactly what you are observing.

+7
source

I'm not sure if you solved your problem? If you wanted to catch your exceptions, you could do it. Add to program.cs before Application.Run

 Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException); 

Create 2 voids to handle the exception data.

 static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception"); // here you can log the exception ... } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception"); // here you can log the exception ... } 
0
source

All Articles