Unhandled exceptions in BackgroundWorker - c#

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?

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.

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.

[Edit]
Judah has a great point. My example pointed out the specifics of handling the error but my code would actually cause another exception if an exception was never hit in the DoWork method. This example is OK due to the fact that we are specifically showing the error handling capabilities of the BackgroundWorker. However if you are not checking the error parameter against null then this could be your issue.
[/Edit]
I don't see the same results. Can you post a little code? Here is my code.
private void Form1_Load(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Will cause another exception if an exception didn't occur.
// We should be checking to see if e.Error is not "null".
textBox1.Text = "Error? " + e.Error;
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10; i++)
{
if (i < 5)
{
Thread.Sleep(100);
}
else
{
throw new Exception("BOOM");
}
}
}
Program Output:
Error? System.Exception: BOOM at
BackgroundException.Form1.worker_DoWork(Object
sender, DoWorkEventArgs e) in
D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs:line
43 at
System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs
e) at
System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object
argument)
An interesting article that looks similar to your question. It has a section on handling exceptions.
http://www.developerdotstar.com/community/node/671

This is an old question, but I found it while Googling the same symptoms. Posting this in case someone else finds it for the same reason.
Judah's answer is right, but it isn't the only reason the "unhandled exception in user code" dialog can appear. If an exception is thrown from inside a constructor on the background thread then that exception will cause the dialog immediately, and won't be passed to the RunWorkerCompleted event. If you move the offending code outside of any constructors (to any other method) it works as expected.

I had the same problem and i was already applying the Judah answer before i found this topic after some googling.
Well, imo the Judah answer is partially correct. I found a better answer here
The debugger is making the work well, if you run the application in "real-world conditions", the RunWorkerCompleted deals with the exception as expected and the application behavior is also the expected.
I hope this answer helps.

Related

C# Catching exception which is occurring on ThreadPool

I am investigating some crashes in my application caused by a Win32 exception, and I have narrowed it down that it must be occurring in the threadpool which is taking care of the EventLog.EntryWrittenEventHandler event handler in my application. I set this up like this:
// Create the event log monitor
eventLog.Log = "Application";
eventLog.EnableRaisingEvents = true;
eventLog.EntryWritten += new EntryWrittenEventHandler(EventLogMonitor);
EventLogMonitor is the handler for my event. I am wondering does anybody have any ideas as to where I could find out whats causing this exception. It seems that to listen for events a ThreadPoolWaitOrTimerCallback is being set up, which wouldn't have any of my code on it, and if the exception is occurring on this I just cant see how to deal with this problem. Any help is really appreciated!!
Here is the output of !clrstack in WinDBG:
0:008> !clrstack
OS Thread Id: 0x106c (8)
ESP EIP
049df1c8 7756f871 [HelperMethodFrame: 049df1c8]
049df26c 73ce6fa0 System.Diagnostics.EventLog.get_OldestEntryNumber()
049df27c 73bf24ed System.Diagnostics.EventLog.CompletionCallback(System.Object)
049df2c4 73bf0fe4 System.Diagnostics.EventLog.StaticCompletionCallback(System.Object, Boolean)
049df2f4 744fc3b8 System.Threading._ThreadPoolWaitOrTimerCallback.WaitOrTimerCallback_Context(System.Object, Boolean)
049df300 744fc373 System.Threading._ThreadPoolWaitOrTimerCallback.WaitOrTimerCallback_Context_f(System.Object)
049df304 7400027f System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
049df31c 744fc477 System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(System.Object, Boolean)
049df4ac 74991b5c [GCFrame: 049df4ac]
In case it helps, my application is just checking the event ID of every entry written to the event log, and if it matches one of a certain set of ID's then I log it. The crashes happen quiet rarely, and the exception is a System.ComponentModel.Win32 exception with message 'Access is denied'. That sounds like it could be a permissions issue but why would it work ok for a certain period and then suddenly crash with this.
If I understand you correctly (it would help if you pass the stacktrace that leads you to the conclusion that the exception is happening inside a threadpool thread), then just wrap your code of EventLogMonitor in a try/catch block.
Example:
void EventLogHandler(object sender, EventArgs args)
{
try
{
// Your original code.
}
catch (Exception ex)
{
// Log or Write "ex" to the console. Set a breakpoint, whatever.
throw;
}
}
UPDATE: after your update it looks as if the exception is indeed not raised from inside your handler, but before it is even called inside the EventLog class.
You could try registering a handler with the AppDomain.UnhandledException event and do your logging/handling in there. Note that this will not allow you to suppress or "change" or wrap the exception, but merely to log it somewhere for diagnostic purposes.
If you just want to inspect the exception once (or on occasion), you should try using the SOS-extension's !PrintException command in WinDBG.
UPDATE 2: after further investigation I find it rather strange that the exception bubbles up all. Your stacktrace suggests you're using .NET 3.5 (or earlier, but not 4.) and looking at the EventLog class in Reflector you can see that the whole handling of the EventWrittenHandler, including the preamble code that seems to cause the exception, is wrapped in one big "try/catch(Exception)/catch" block. Funny.
Subscribe to Application.ThreadException in your Program.cs as follows to be able to catch the exceptions that are not in main thread.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += Application_ThreadException;
try
{
Application.Run(new MainForm());
}
catch (Exception e)
{
HandleException(e);
}
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
HandleException(e.Exception);
}
If you can, use Tasks in System.Threading.Tasks.
Try, where action is performing what you want.
ThreadPool.QueueUserWorkItem(state =>
{
try
{
action();
}
catch (Exception ex)
{
OnException(ex);
}
});
Not sure what kind of Application this is, so in a general case, if you're having no luck, try hooking into the AppDomain in which the code is running. If you don't have multiple domains, you can try:
AppDomain.CurrentDomain.FirstChanceException += Handler
or
AppDomain.CurrentDomain.UnhandledException += Handler

How can I get WinForms to stop silently ignoring unhandled exceptions?

This is getting extremely irritating. Right now I have a winforms application, and things were not working right, but no exceptions were being thrown as far as I could tell. After stepping through almost all pieces of relevant code, it turns out that an exception was being thrown at the start of my application.
Long story short, in WinForms, being as awesome as it is, if an exception occurs the WinForms library ignores it. No "an unhandled exception has occurred" JIT message is thrown, it just stops processing the current event and goes back to the GUI.
This is causing random bugs, because code to load data isn't being called due to the exception occurring prior to this data being loaded.
To see this in action I created a brand new WinForms application, and entered the following code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string blah = null;
blah.Trim();
}
}
Press F5 and the form loads without any errors showing, even though a null reference is being thrown.
I then tried to go to my Program.cs main method and add Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); to it. Still my form loads without causing any errors to be thrown.
Even though I know that I can tell VS to break on all exceptions, I find this situation really bad. It causes really wierd issues that are hard to debug in production, and as this is an internal tool I really want to have it so it actually errors out when an exception occurs, and not silently disregards it.
Does anyone know how to do this?
Update: Just to update on things I have learned from the comments.
This does appear to be a 64-bit issue with windows, as I learned from this question which I did not see before posting. In that question it pointed to a Microsoft bug report about this, which had this to say:
Hello,
This bug was closed as "External" because this behavior results from how x64 version of Windows handle exceptions. When a user mode exception crosses a kernel transition, x64 versions of Windows do not allow the exception to propagate. Therefore attached debuggers are unaware of the fact that an exception occured resulting in the debugger failing to break on the unhandled exception.
Unfortunately where is nothing that the Visual Studo team can do to address this, it is the result of operating system design. All feedback regarding this issue should be addressed to the Windows team; however the Windows team considers this to be the "correct" operating system design, and considers the x86 behavior to be "incorrect".
Best Regards,
Visual Studio Debugger
That being said, builds not run through visual studio (or using Ctrl+F5 to run) does seem to show the JIT exception message box EXCEPT if you have the following code in your Program.cs:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
That code will cause windows to ignore the exception.
However, if you (instead) subscribe to the Application.ThreadException event, not only will your exceptions be caught, visual studio's debugger will break on unhandled exceptions!
In your Program.cs' Main function you should also ensure that you've wrapped your call to open the form in a try/catch. Additionally use the AppDomain.UnhandledException to catch exceptions. We also add Application.ThreadException too.
I believe the following will give you hooks into all the exceptions that can be thrown...
static void Main()
{
try
{
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
System.Windows.Forms.Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(OnGuiUnhandedException);
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
var form = new MainForm();
form.ShowDialog();
}
catch (Exception e)
{
HandleUnhandledException(e);
}
finally
{
// Do stuff
}
}
private static void HandleUnhandledException(Object o)
{
// TODO: Log it!
Exception e = o as Exception;
if (e != null)
{
}
}
private static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs e)
{
HandleUnhandledException(e.ExceptionObject);
}
private static void OnGuiUnhandedException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
HandleUnhandledException(e.Exception);
}
Try the following.
Handle exceptions in your main application entry point.
Also, manage unhandled thread exceptions using a ThreadExceptionEventHandler
This is the code snippet:
[STAThread]
public static void Main(string[] args)
{
try
{
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
//your program entry point
}
catch (Exception ex)
{
//manage also these exceptions
}
}
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
ProcessException(e.Exception);
}
An easy fix is not to run under the debugger.
The debugger is masking the exception for some reason. If you run your app normally (Ctrl+F5), you'll get the usual "Unhandled exception has occurred in your application... Continue/Quit?" dialog.
Having experienced this often and identified the issue regarding 64 bit OS and the Form.Load event, I always just make a point of doing all my start up functions in the Form.Shown event. For all practical purposes this is the same thing (aside from a few rare, exceptional circumstances), and the JIT message is produced in the Shown event.

Why is Method.Invoke generating unhandled exceptions? Unable to catch even with TargetInvocationException

I'm trying to use Method.Invoke to call a windows form dialog, have a user perform some selections/interaction and continue execution. This invoke call is happening in an asynchronous method.
While everything works fine, should an error occur on the windows form, an unhandled exception is thrown, even when trying to catch TargetInvocationException or just Exception.
Both forms are in the same winforms project. I realize where are other ways to perform an async call but this is just to illustrate the issue.
The form dialog is as follows:
public partial class FakeDialog : Form
{
public FakeDialog()
{
InitializeComponent();
}
private void btnOK_Click(object sender, EventArgs e)
{
throw new Exception("oh noes!");
this.DialogResult = DialogResult.OK;
this.Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
public new DialogResult ShowDialog()
{
base.ShowDialog();
return this.DialogResult;
}
}
And here is the calling code. None if the catch blocks are being executed, even when not debugging (my problem is not debugging exceptions in the IDE as mentioned here. The following results in an unhandled exception).
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MethodInvoker simpleDelegate = new MethodInvoker(InvokeForm);
IAsyncResult tag = simpleDelegate.BeginInvoke(null, null);
simpleDelegate.EndInvoke(tag);
MessageBox.Show("All done");
}
private void InvokeForm()
{
try
{
Type t = typeof(FakeDialog);
MethodInfo showDialogMethod = t.GetMethod("ShowDialog", new Type[] { });
object dialog = Activator.CreateInstance(t);
System.Windows.Forms.DialogResult result = (System.Windows.Forms.DialogResult)showDialogMethod.Invoke(dialog, new object[] { });
MessageBox.Show(result.ToString());
}
catch (TargetInvocationException tie)
{
MessageBox.Show("Tie exception");
}
catch (Exception ex)
{
MessageBox.Show("general exception");
}
}
}
UPDATE:
Strangely, I'm able to catch the exception when running with debugging (I'm sure the IDE is helping here). Running without debugging causes the unhandled exception.
Also, invoking via an async call doesnt seem to make a difference. If i just call InvokeForm() (ignore all the methodInvoker stuff), I can achieve the same result.
Operating on .NET 2.0 using Visual Studio 2008.
Ok, figured it out.
The result from the code was unhandled exceptions. And while using Method.Invoke for a simple method in another class would behave correctly, the environment changes with the source of the exception occurring in a form. A form event. And I eventually found on Microsoft Support that unhandled exceptions in Windows Form events are not propagated up call stack. There's some pretty interesting reasons for this ("Windows Forms applications have a top-level exception handler that allows the program to continue to run if it can recover").
It also gives credence to what Marc mentioned over putting things in the Load event. Sigh. So the reason for all this is pretty obvious now.
As for the code running fine while debugging (as opposed to without), I think I can thank the JIT debugger for that. #fluf pointed to me that specifically enabling the JIT debugger gave the same result as running with debugging. #Marc Gravell, depending on VS settings this might explain only I and fluf could reproduce. There's some more info on it here but it's not a production fix.
So the real solution is either handling the exceptions in the event handlers themselves or use the solution as mentioned in the Microsoft Support article above, which solves my issues.
I can't actually repro from your code, but: the Load event is.... different, and some odd things can happen if you get an exception inside the Load event. Simply my advice would be: move this code out of the Load event. It also doesn't help that attaching a debugger here changes the behaviour (a Heisenbug).
Without seeing MethodInvoker's declaration i can only guess, but it is possible that InvokeForm() method is executed on non-UI thread.
MethodInvoker simpleDelegate = new MethodInvoker(InvokeForm);
IAsyncResult tag = simpleDelegate.BeginInvoke(null, null);
To show a dialog you may consider to rewrite this as follows:
Action simpleDelegate = new Action(InvokeForm);
this.BeginInvoke(simpleDelegate);

Can someone please explain how to Handle Application Wide Exceptions properly

I cant seem to make heads or tails of how I am supposed to properly handle unexpected exceptions.
Consider the following application:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SomeForm());
}
class SomeForm : Form
{
public SomeForm()
{
Button btn = new Button();
btn.Text = "Click ME";
btn.Location = new System.Drawing.Point(20, 20);
btn.Click += new EventHandler(btn_Click);
Controls.Add(btn);
}
void btn_Click(object sender, EventArgs e)
{
throw new Exception("This is an Exception");
}
}
If I run this application and click the button I get an unhandled exception as expected. At first I tried surrounding the Application.Run with a try catch block like so:
try { Application.Run(new SomeForm()); }
catch { MessageBox.Show("Exception caught in try catch"); }
At first this seems to work, until I ran the application outside of the Debugger. When you run the application outside of the Debugger, the exception is reported as an unhandled error. After doing some reading I discovered I should be looking at the Application.ThreadException event. So I do the following:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
try { Application.Run(new SomeForm()); }
catch { MessageBox.Show("Exception caught in try catch"); }
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("Exception caught in event");
}
Now when I run my application outside of the debugger the exception is handled and the MessageBox indicates it was caught in the event handler. Then I go back into the debugger and run it. Now the Debugger kicks it up as an unhandled exception even though I have surrounded it in a try catch AND I am tied onto the Application.ThreadException event. If I do not tie up the to Application.ThreadException event the exception is caught correctly by the try catch block.
Now to the questions:
What the heck is going on here?
Is there a way that I can catch/handle all exceptions in my application that works both in the debugger and outside of the debugger?
Am I just doing the completely wrong thing here?
You can handle them using AppDomain.CurrentDomain.UnhandledException and Application.ThreadException, look for more.
What's the difference between Application.ThreadException and AppDomain.CurrentDomain.UnhandledException?
The debugger considers exceptions that propagate to Application_ThreadException to be unhandled exceptions, since that event handler is used as a final location to log and terminate gracefully. This allows you to stop at the point of the exception when running the debugger, which is often very helpful.
It's not possible to handle all exceptions in one global place because there is not enough context to know how to actually handle them. You can catch all exceptions (even the unhandled ones) using Application_ThreadException (and AppDomain.UnhandledException for exceptions on other threads), but the next thing you should do in that case is shut down your application.
You should handle exceptions in each method separately, based on the information you have and the knowledge of the types of exceptions that can occur. Exceptions you don't know how to handle should not be caught and will percolate to the 'global' event handlers, which should log the details and politely shut down the application.

BackgroundWorker & Exceptions

The MSDN Docs says
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
But when I tried
_workers[i].DoWork += (s, args) =>
{
throw new Exception("Error!");
};
I get Exception Unhandled error ... The code doesn't seem to go to RunWorkerCompleted. How are errors supposed to be handled?
UPDATE
I have setup simple handlers
_workers[i].DoWork += (s, args) =>
{
throw new Exception("Error!");
}
...
_workers[i].RunWorkerCompleted += (s, args) =>
{
if (args.Error != null) {
string dummy = args.Error.Message;
}
...
};
The code never leaves DoWork
If an exception is thrown and passes through user frames but is then not caught by user code, it is considered "user-unhandled".
So I think there are 3 possibilities:
This is a first-chance exception - so if you press F5, the exception will propagate as normal.
Click "edit code" in the Exception Assistant. Then do some Edit and Continue to solve the problem.
Go to Debug->Exceptions and de-select the "user-unhandled" column.
If you are running through the debugger, Visual Studio will stop on exceptions in the BackgroundWorker.DoWork event handler rather than silently passing the exception to the RunWorkerCompleted event which is what happens when not in the debugger.
1) You can just hit F5 and continue execution to follow the exception (as RoadWarrior mentioned)
2) If that is too annoying, for DoWork don't use delegates/lambdas but use named methods and decorate with [DebuggerStepThrough] Attribute. This will let the debugger ignore that method and not stop on exception so you can view the "normal" behavior of the Backgroundworker.
See: Visual Studio 2008 Debugging - Skipping code
I've done exception handling in BackgroundWorker yesterday. I didn't add any throw in Worker's DoWork handler. If exception happens, you will be able to get it in RunWorkerCompleted without throwing it. Just don't forget to cancel you Worker if exception occurs.

Categories

Resources