BackgroundWorker dies unexpectedly - c#

I have the following code:
public Mainform()
{
...
// scheduler
scheduler.DoWork += new System.ComponentModel.DoWorkEventHandler(scheduler_DoWork);
scheduler.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(scheduler_RunWorkerCompleted);
scheduler.WorkerReportsProgress = false;
scheduler.WorkerSupportsCancellation = true;
...
...
scheduler_DoWork(this, null);
scheduler.RunWorkerAsync(1000);
...
}
void scheduler_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
scheduler_Enabled = false;
CustomExceptionHandler eh = new CustomExceptionHandler();
eh.HandleUnhandledException(e.Error, "scheduler");
}
if(scheduler_Enabled)
{
scheduler.RunWorkerAsync(1000);
}
}
void scheduler_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
try
{
...do some stuff
}
catch(MyException ex)
{
ThreadSafeShowError();
}
finally
{}
...do more stuff
}
finally
{
if (e != null && e.Argument != null)
{
Thread.Sleep((int)e.Argument);
}
}
}
The backgroundworker thread died unexpectedly without any exception being thrown. I did not encounter this problem during development and it seems to be hard to reproduce. I suspected that maybe a cross thread exception was occurring when I am doing work in the scheduler_DoWork. I have tried to explicitly update the UI without checking if InvokeRequired and the thread continues to run without problems in a release build. How can this be? (Cross thread exception should occur) How can I determine what causes the thread to die? Any suggestions on how to figure out what is going wrong or how to debug this issue will be appreciated?

The RunWorkerCompleted event might not be fired on the UI Thread. If it is not, then the thread will end and your scheduler object will be garbage collected, which will make it seem like it just quit with no error. See this post for more details. Here and here are SO posts about this.

Your sample doesn't show enough code to determine what's going on but:
Maybe an exception is being thrown from ThreadSafeShowError? Why are you trying to show an error from the worker thread anyway - the conventional thing to do is to show e.Error if not null in the RunWorkerCompleted event handler.
To debug the issue try putting the following around all the code in your DoWork handler:
try
{
// do work
// log a trace statement here
}
catch(Exception ex)
{
// log exception, e.g. with System.Diagnostics.Debug.Write
throw;
}
finally
{
// log a trace statement here
}

You can do several things to increase the possibility of catching the exception:
Enable Managed Debugging Assistants for all exceptions in VS. To do that, go to Debug menu -> Exceptions..., and put a check mark next to "Managed Debugging Assistants" to enable all exceptions to be caught using debugger. Also, depending on the code you are executing, expand the CLR Exceptions node and select nodes of interest ("System" node, for example, will catch all exceptions from the System namespace in the debugger).
Obviously, put a try/catch block around your code, with some logging. You can also do something like this, if you are in real trouble:
try
{
// do stuff
}
catch (Exception ex)
{
#if DEBUG
// break only in DEBUG builds
System.Diagnostics.Debugger.Break();
#endif
// log the exception and throw
throw;
}
Put a try/catch with logging around your Application.Run(...) code in the Main() method. Exceptions do propagate up there sometimes, and this can catch them (even if not coming from this specific part of your code).
Add an Application.ThreadException event handler in your Main() method, before calling Application.Run, like this:
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

In Mainform, you never call scheduler.RunWorkerAsync, so your BackgroundWorker does not start at all.

Related

Backgroundworker can't handle exception

I have a background worker that will throw an exception when there is a problem. I'm trying to catch the exception in the workcompleted event.
My code is roughly as follows:
void workerProcessReports_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//Work is here. The code here throws an exception
}
catch (Exception ex)
{
throw ex;
}
}
void workerProcessReports_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("There was a problem");
}
else
{
MessageBox.Show("No Problems");
}
}
The problem is that visual studio breaks on the throw ex in the dowork method with the Message
InvalidOperationException was unhandled by user code
What's going on?
Don't catch and rethrow your same exception, that's a waste and causes your stack trace to get messed up.
If you want the exact same exception to be thrown after catching it from a parent exception type, just write throw; in your catch block. If you plan on just throwing everything anyway, don't bother catching it in the first place.
If you do allow your exception to occur without handling it in the doWork method, then you can throw on the parent thread in your RunWorkerCompleted method.
Within your RunWorkerCompleted method you can throw it as such:
if(e.Error != null)
{
throw e.Error;
}
However, at this point if it's something you can handle you may just want to recover and continue, instead of throwing since you are already aware that an exception occured. Especially, if this parent thread is your UI thread, then this is the perfect opportunity to display an error message instead of throwing and potentially crashing your application for a non-fatal error.

Background worker doesn't catch errors from ThreadPool

I'm using a BackgroundWorker since I need to give a feedback in my UI. I also need to use ThreadPool in my class for it to run asynchronously but it seems that my background worker cannot catch the exception it throws.
It's intended to give a feedback on what task it's doing.
I made a simple application which reproduces the problem :
// MAIN UI CLASS
BackgroundWorker _bgWorker = new BackgroundWorker();
void _bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// Returns custom error
MessageBox.Show(e.Error.Message);
}
}
void _bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
try {
// Initialize test error class
var testClass = new TestClass();
}
catch (Exception ex)
{
MessageBox.Show("im from trycatch");
}
}
private void Window_ContentRendered(object sender, EventArgs e)
{
_bgWorker.DoWork += _bgWorker_DoWork;
_bgWorker.RunWorkerCompleted += _bgWorker_RunWorkerCompleted;
}
/////////////////////////////////////////////////////////////////////////
// TEST ERROR CLASS
public TestClass()
{
throw new Exception("im a custom error");
}
This works all right. With the try-catch, it catches the error as handled by the try-catch. Whereas, without the try-catch, it handles it in RunWorkerCompleted.
However, I really need to do these methods asynchronously (which is why I use ThreadPool) but the debugger always points at the exception. (it only crashes the program when I try it without the debugger)
// TEST ERROR CLASS
public TestClass()
{
ThreadPool.QueueUserWorkItem(delegate
{
throw new Exception("im a custom error");
}
}
I tried to rethrow the error using a try-catch statement (hoping it would pass the exception to the BackgroundWorker) but it didn't work.
Hope you can help me.
Thanks in advance.
You do not need to put code on the ThreadPool from the DoWork method. The BackgroundWorker will raise your _bgWorker_DoWork method on a ThreadPool thread automatically when you call RunWorkerAsync().
If you are trying to start SEVERAL MORE ThreadPool tasks from your background worker, then I suppose that could be a consideration, but in that case I would suggest using the TPL in .NET4 if at all possible...
http://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
If you can not use TPL, then you must wrap your ThreadPool code in a TryCatch and put the Exception some place that can be accessed outside of that method.
For example add a internal static List<Exception> backgroundExceptions; member to your UI class, the background worker add's any caught exceptions to this list, and then you must investigate this list after your background work has completed to see if there were any Exceptions present.
This is essentially what the TPL is doing for you ... giving you a place to 'observe' exceptions that happened on the background thread, but it is still your responsibility to look for those Exceptions, either in the Task.Exception property, or by calling a method that will re-throw the Exception for you.

Trying to step through BackgroundWorker code in debug but program ends unexpectedly

Here is the code I am working with:
try
{
mainWorker = new BackgroundWorker();
mainWorker.DoWork += (sender, e) =>
{
try
{
//stuff I want to have happen in the background
...
//I want to step through the lines in this try block
}
catch
{
//exception not being caught
}
};
mainWorker.RunWorkerCompleted += (sender, e) =>
{
//code to let user know that the background work is done
...
};
mainWorker.RunWorkerAsync();
mainWorker.Dispose();
}
catch
{
//exception not being caught
}
I do not see any exceptions being thrown. I have a breakpoint set inside the try block in DoWork. Sometimes it hits the breakpoint, but after stepping through a certain number of lines the program ends. It doesn't always end on the same line of code. Sometimes it doesn't hit the breakpoint at all.
The code steps through normally if I eliminate the background worker.
I haven't implemented background workers before and I'm trying to figure out what I'm missing that's preventing me from stepping through my code.
edit: forgot to mention that if I comment out Dispose() it still doesn't step through.
Try adding Console.Readline(); before mainWorker.Dispose();. It is possible that your application stops before BackgroundWorker does its job.
BackgroundWorker is runing as background thread, so it is terminated if main thread stops.
You can test it on simple example. This code will show only one number.
static void Main(string[] args)
{
BackgroundWorker mainWorker = new BackgroundWorker();
mainWorker.DoWork += (sender, e) =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
Thread.Sleep(500);
}
};
mainWorker.RunWorkerAsync();
}
but if you add stop your main thread by Console.Readline(); you will have all the numbers and can step through DoWork code in debug.
I found that in order for exceptions to be thrown so that I can debug through code running in a backgroundworker thread I need to turn on "Enable Just My Code" in Tools => Options => Debugging => General => Enable Just My Code.
Then make sure that in Debug => Exceptions the "Common Language Runtime Exceptions" checkbox is checked for both Thrown and User-unhandled exceptions.
Also check for exceptions which may exits your main thread.

Catch child background threads within calling method in foreground thread

I want to call a method once by a specified interval (e.g. 3 seconds), but I have problem catching exception within the calling method (e.g. Start) thrown by the called method (timer_Elapsed)
Update
public void Start()
{
Timer timer = new Timer(PingPeriod); //System.Timers
try
{
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
}
catch (Exception ex)
{
//I want to catch exception thrown by timer_Elapsed
}
//Logic here that keeps the method running
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
throw new exception("Catch this exception please");
}
Update:
Can anyone please confirm that the start() will NOT catch exception thrown from timer_Elapsed, or when trying to invoke timer_Elapsed if exception occurred.
Is there a better alternative, which can catch exception from a called method or get notified?
Any idea would be very much appreciated!
This just isn't possible, the Elapsed event handler runs later, well after your Start() method has exited. Furthermore, that event has the nasty habit of swallowing all exceptions without any diagnostic.
You'll need to handle exceptions within the event handler. Certainly not easy to do. Do consider using the System.Threading.Timer class instead. At least your program will terminate when the callback throws an exception.
This is not possible because the exception is thrown on a different execution context (thread) from the one that set up the timer.
You should handle any exceptions in your callback method. If you want your logic separated from your exception handling, simply create a separate method.
private void TimerElapsedCallback(object sender, ElapsedEventArgs e)
{
try
{
this.DoSomething();
}
catch (Exception ex)
{
// handle
}
}
private void DoSomething()
{
// logic goes here and can be agnostic of any exceptions it throws, if desired
}

Unhandled Exceptions from Managed C# User Control used in MFC Dialog

Our core application is built in MFC C++, but we are trying to write new code in .NET, and have created a User Control in .NET, which will be used on an existing MFC Dialog.
However, when a unexpected/unhandled exception is thrown from the User Control, it causes the MFC app to crash (illegal op style), with no ability to recover.
I've added
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
To the Constructor of the .NET user control, but it doesn't seem to catch anything.
Is there any way to add an event in MFC to handle these?
Quick google didn't return anything useful.
Thanks.
Edit: Still haven't been able to resolve this the way I'd like, looks like the best way to do it, is try and catch around all the .NET code, so no exceptions bubble up.
I asked this same question a while ago: Final managed exception handler in a mixed native/managed executable?
What I have found is that the managed unhandled exception events ONLY fire when running in a managed thread. The managed WndProc is where the magic happens.
You have a few options: you could place a low-level override in CWinApp and catch Exception^. This could have unintended side-effects. Or, you could go with Structured Exception Handling (SEH) which will give you a hack at /all/ unhandled exceptions. This is not an easy road.
I think you want to have the unhandled exception handler in the MFC side of things:
AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(&CurrentDomain_UnhandledException);
[same for Application.ThreadException]
Have a look at this similar question on the MSDN forums: Unhandled Exception in Mixed Mode application
Of course, the better idea would be either to handle the exception in the C# code, or else to find out what's causing it, and fix it so that the exception is never thrown. What's preventing that?
In every event handler of the user control, place a try/catch block:
private void btnOk_Click(object sender, EventArgs e) {
try {
// real code here
}
catch (Exception ex) {
LogException(ex);
// do whatever you must in order to shut down the control, maybe just
}
}
Here's what I use:
public static class UI
{
public static void PerformUIAction(Control form, Action action)
{
PerformUIAction(form, action, (string) null);
}
public static void PerformUIAction(
Control form, Action action, string message)
{
PerformUIAction(form, action, () => message);
}
public static void PerformUIAction(
Control form, Action action, Func<string> messageHandler)
{
var saveCursor = form.Cursor;
form.Cursor = Cursors.WaitCursor;
try
{
action();
}
catch (Exception ex)
{
MessageBox.Show(
messageHandler() ?? ex.Message, "Exception!",
MessageBoxButtons.OK, MessageBoxIcon.Error,
MessageBoxDefaultButton.Button1,
MessageBoxOptions.DefaultDesktopOnly);
Debug.WriteLine(ex.ToString(), "Exception");
throw;
}
finally
{
form.Cursor = saveCursor;
}
}
}
I call it like this:
private void _copyButton_Click(object sender, EventArgs e)
{
UI.PerformUIAction(
this, () =>
{
// Your code here
});
}
I added the unhandled exception handler to the constructor of the .NET user control
I don't think that will work; I believe the exception handler has to be setup before a call to Application.Run. Do you have any Application.Run calls in your app?
How about something like this on the MFC side of things before you initialize any .NET controls:
Application.SetUnhandledExceptionMode(System.Windows.Forms.UnhandledExceptionMode.CatchException);
Application.ThreadException += ...;
See if the ThreadException handler is called.

Categories