Catch child background threads within calling method in foreground thread - c#

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
}

Related

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.

Winforms app still crashes after unhandled exception handler

I've applied these handlers in a test application:
Application.ThreadException += Application_ThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
I then create an exception on a nested Task/Async await on the form:
Despite the handler being fired - CurrentDomain.UnhandledException - the app still crashes.
Why would it crash and not show the dialog and stay running?
System.Exception was unhandled
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 each async method with Task and not void thus exception handling works predictably now. The only thing I still do not know is why - if I stop handling the exception in the button event - when the exception is caught Application_ThreadException is fired and not TaskScheduler_UnobservedTaskException
Your original code does something that you should never do: calling async void methods. And problematic exception handling is one reason for that.
Let's look at the event handlers one by one:
Application.ThreadException only handles exceptions on the Winforms UI thread. The exception never got to the UI thread, so this event doesn't fire.
TaskScheduler.UnobservedTaskException only handles exceptions from Tasks that are unobserved (and even then, it does so when they are finalized, which might take a long time if you're not allocating much memory). But the unobserved exception is not tied to any Task, so this doesn't fire either.
AppDomain.CurrentDomain.UnhandledException handles all exceptions that are still considered unobserved after the previous two event handlers. But it can't be used to set the exception as observed, so the application still terminates. This is the only handler that actually fires.
Why exactly don't the first two handlers fire? In your code, you have Task.Run(() => new IGetRun().Run1()), where Run1() is an async void method that throws an exception.
When there is an unobserved exception in an async void method, the exception is rethrown on the current synchronization context. But since the method is running on a thread pool thread (because of the Task.Run()), there is no synchronization context. So the exception is thrown on a thread pool thread, which is not observable by the first two event handlers.
As you already discovered, the fix for this issue is to use async Task methods and await them properly.
In your updated code, Run1() is now an async Task method. That Task is unwrapped by Task.Run() and then awaited, so the exception is transferred to the Hello() Task. That in turn is awaited from the async void button1_Click handler on the UI thread.
This all means that there are no unobserved Task exceptions and that the exception is rethrown on the UI synchronization context. In Winforms, that means Application.ThreadException is raised, which is exactly what you're observing.
I'm not sure if you solved your problem ?
If the point was to catch your unhandeld exceptions, you could do this.
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 ...
}

Exception not caught when using BackgroundWorker

I have a WPF window with a BackgroundWorker. I get an exception in Send() method here:
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
smtpClient.Send(mail);
}
which in turn is invoked in a Click Event for some button like this:
private async void SendClickAsync(object sender, RoutedEventArgs e)
{
using (MessageServiceClient client = new MessageServiceClient())
{
try
{
[...]
worker.RunWorkerAsync();
}
catch (Exception ex)
{
MessageBox.Show("Error! Check your sender data!", "!", MessageBoxButton.OK, MessageBoxImage.Error);
[...]
}
}
}
Why does this exception doesn't get handled? When I was doing it not asynchronously (everything was in SendClickAsync() method) the message box popped up nicely.
When you call worker.RunWorkerAsync() method, your main thread continue execution and exits try..catch block. To handle exception use RunWorkerCompleted event handler. RunWorkerCompletedEventArgs arguement has property Error which will contain exception object:
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("Error", "!", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
The BackgroundWorker is using thread pool threads, so it doesn't want your code to be able to do something weird on the worker thread. That's why the BackgroundWorker swallows your exception that happened during DoWork and lets you know that it happened through RunWorkerCompletedEventArgs.Error.
The reason the exception is not handled is because it is thrown on a different thread.
The call to worker.RunWorkerAsync(); does not block, rather it starts the job on the threadpool and returns control immediately in the main thread - this is the whole point to doing it asynchronously.
But this also means that after the call to worker.RunWorkerAsync() the main thread exits your try-catch block, so the exception doesn't get handled (on your main thread).

How to avoid error message window

we're having an application on server instance and quite rarely, but we have out of memory exception (program is not leaking, just instance is quite small and it operates with quite big amounts of data).
That would be not a problem, as we monitor processes on that server instance and if some of the processes are not found in process list, alert email is sent.
Now the problem is with this:
That prevents process from disappearing from process list, so we don't get alert email about it's failure. Is it possible to disable this message, that if program fails on something we don't catch, it would close without user interaction?
Assuming Windows Forms, I typically do multiple steps to prevent this message box.
First, I connect several handlers in the Main function:
[STAThread]
private static void Main()
{
Application.ThreadException +=
application_ThreadException;
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
currentDomain_UnhandledException;
Application.Run(new MainForm());
}
Those handlers are being called when an otherwise unhandled exception occurs. I would define them something like:
private static void application_ThreadException(
object sender,
ThreadExceptionEventArgs e)
{
doHandleException(e.Exception);
}
private static void currentDomain_UnhandledException(
object sender,
UnhandledExceptionEventArgs e)
{
doHandleException(e.ExceptionObject as Exception);
}
The actual doHandleException function that is then called does the actual error handling. Usually this is logging the error and notifying the user, giving him the options to continue the application or quit it.
An example from a real-world application looks like:
private static void doHandleException(
Exception e)
{
try
{
Log.Instance.ErrorException(#"Exception.", e);
}
catch (Exception x)
{
Trace.WriteLine(string.Format(
#"Error during exception logging: '{0}'.", x.Message));
}
var form = Form.ActiveForm;
if (form == null)
{
MessageBox.Show(buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show(form, buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
With the helper function:
public static string buildMessage(Exception exception)
{
var result = new StringBuilder();
while (exception != null)
{
result.AppendLine(exception.Message);
result.AppendLine();
exception = exception.InnerException;
}
return result.ToString().Trim();
}
If you are using not Windows Forms but e.g. a Console application or WPF, some handlers are not present, while others are present instead.
The idea stays the same: Subscribe to event handlers that are being called if you have no try...catch around your code blocks.
Personally, I try to have as few of those try...catch blocks as possible (ideally none).
don't know if you can deactivate this - but I think you should not.
Find the bug/problem in your application and handle the problem with a craceful shutdown or by preventing the problem in first case.
Everything else will be a real crude workaround and I don't think your client will be pleased to have such a behavior (after all won't there be data lost? If not this has allways the buggy / not finished touch)
You could put a global try/catch block in your program and exit the program on any unexpected exception.
If using WPF you can try-catch the following two exceptions in your app.xaml.cs. There may be other/complementary exceptions to handle, but this are the two I am usually looking for:
AppDomain.CurrentDomain.UnhandledException - "This event provides notification of uncaught exceptions. It allows the application to log information about the exception before the system default handler reports the exception to the user and terminates the application. If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery. Caution is advised, because program data can become corrupted when exceptions are not handled."
Dispatcher.UnhandledException - "Occurs when a thread exception is thrown and uncaught during execution of a delegate by way of Invoke or BeginInvoke."
ie:
public partial class App : Application
{
public App()
{
this.Dispatcher.UnhandledException += DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
}
private void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// log and close gracefully
}
private new void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
// log and close gracefully
}
}

BackgroundWorker dies unexpectedly

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.

Categories