Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unhandled exceptions in BackgroundWorker

I have a small WinForms app that utilizes a BackgroundWorker object to perform a long-running operation.

The background operation throws occasional exceptions, typically when somebody has a file open that is being recreated.

Regardless of whether the code is run from the IDE or not .NET pops up an error dialog informing the user that an Unhandled exception has occurred. Compiling the code using the Release configuration doesn't change this either.

According to MSDN:

If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel..::.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.

I expect these exceptions to be thrown on occasion and would like to handle them in the RunWorkerCompleted event rather than in DoWork. My code works properly and the error is handled correctly within the RunWorkerCompleted event but I can't for the life of me figure out how to stop the .NET error dialog complaining about the "Unhandled exception" from occurring.

Isn't the BackgroundWorker supposed to catch that error automagically? Isn't that what the MSDN documentation states? What do I need to do to inform .NET that this error is being handled while still allowing the exception to propage into the Error property of RunWorkerCompletedEventArgs?

like image 524
Andy Avatar asked Jun 25 '09 15:06

Andy


People also ask

How do I restart my BackgroundWorker?

By creating a Task , the backgroundworker is can be stopped with the CancelAsync and restarted inside the Task. Not making a Task wil start the backgroundworker again before it is cancelled, as the OP describes.

What is use of BackgroundWorker in C#?

BackgroundWorker makes the implementation of threads in Windows Forms. Intensive tasks need to be done on another thread so the UI does not freeze. It is necessary to post messages and update the user interface when the task is done.

What is BackgroundWorker in Winforms?

A BackgroundWorker component executes code in a separate dedicated secondary thread. In this article, I will demonstrate how to use the BackgroundWorker component to execute a time-consuming process while the main thread is still available to the user interface.

What is BackgroundWorker?

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running.


2 Answers

What you're describing is not the defined behavior of BackgroundWorker. You're doing something wrong, I suspect.

Here's a little sample that proves BackgroundWorker eats exceptions in DoWork, and makes them available to you in RunWorkerCompleted:

var worker = new BackgroundWorker(); worker.DoWork += (sender, e) =>      {          throw new InvalidOperationException("oh shiznit!");      }; worker.RunWorkerCompleted += (sender, e) =>     {         if(e.Error != null)         {             MessageBox.Show("There was an error! " + e.Error.ToString());         }     }; worker.RunWorkerAsync(); 

My psychic debugging skills are revealing your problem to me: You are accessing e.Result in your RunWorkerCompleted handler -- if there's an e.Error, you must handle it without accessing e.Result. For example, the following code is bad, bad, bad, and will throw an exception at runtime:

var worker = new BackgroundWorker(); worker.DoWork += (sender, e) =>      {          throw new InvalidOperationException("oh shiznit!");      }; worker.RunWorkerCompleted += (sender, e) =>     {         // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an         // error. You can check for errors using e.Error.         var result = e.Result;      }; worker.RunWorkerAsync(); 

Here's a proper implementation of the RunWorkerCompleted event handler:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e) {     if (e.Error == null)     {        DoSomethingWith(e.Result); // Access e.Result only if no error occurred.     } } 

VOILA, you won't receive runtime exceptions.

like image 102
Judah Gabriel Himango Avatar answered Sep 18 '22 12:09

Judah Gabriel Himango


I would add to the MSDN text:

If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel..::.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.

... AND the debugger will report the exception as "~Exception was unhandled by user code"

Solution: Don't run under the debugger and it works as expected: Exception caught in e.Error.

like image 39
Mark Cranness Avatar answered Sep 18 '22 12:09

Mark Cranness