Why my exception is not making any difference in a wpf application? - c#

I have a WPF application that has a BackgroundWorker. I throw an exception in this BGW but it is not shown any where!, just the background worker fires its WorkerFinished event.
Where is it going?

Each thread has it's own call stack; exceptions can only move up their own call stack, there's no way for them to "bleed" over into another thread's call stack.
When your exception bubbles up to the BackgroundWorker's code that fires the DoWork event handler the exception will end up being explicitly caught and stored in the Error property rather than allowing it to reach the top of the call stack and crash the application.
If you want the program to end if your BGW throws an exception then you'll need to handle the completed event, check for an exception, and then re-throw it or throw a new exception.

Look here, there's a nice example. The exception in throwned in the RunWorkercompleted
Unhandled exceptions in BackgroundWorker
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();

Related

Inner Exception from async thread Owerwrites Outer Exception in .Net [duplicate]

I'm seeing some wierd behaviour when throwing exceptions and catching them in the Application.ThreadException event handler.
Basically whats happening in the sample below is that an exception is thrown in the DoWork event handler of a BackgroundWorker. The RunWorkerCompleted event handler rethrows a new exception with the original as the inner exception.
Why does the inner exception show up in the ThreadException event handler and not the acutal exception being thrown? If I do not provide an inner exception in the RunWorkerCompleted event handler, the correct exception will show up.
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace WierdExceptionApp
{
class WierdExceptionForm : Form
{
BackgroundWorker worker = new BackgroundWorker();
public WierdExceptionForm()
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
throw new Exception("worker_RunWorkerCompleted", e.Error);
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
throw new Exception("worker_DoWork");
}
[STAThread]
static void Main()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new WierdExceptionForm());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message);
}
}
}
The RunWorkerCompleted event is marshaled from the BGW thread to the UI thread by the WF plumbing that makes Control.Invoke() work. Essentially, there's a queue with delegates that is emptied by the message loop. The code that does this, Control.InvokeMarshaledCallbacks(), you'll see it on the call stack, has a catch (Exception) clause to catch unhandled exceptions. That clause calls Application.OnThreadException, passing the value of Exception.GetBaseException().
Well, that explains why you only see the inner exception. Why it is done this way is a bit unclear. Possibly to slice off the stack frames of the code in the UI thread that are otherwise pretty confusing since the real exception came from the background thread.
if (e.Error != null)
{
throw new Exception("worker_RunWorkerCompleted", new Exception("Inner", new Exception("Inner inner")));
}
You get "inner inner" at the end. It seems that this is the behavior of Application_ThreadException method to look at the inner-most exception.

Handling Unhandled Exception in WPF [duplicate]

This question already has answers here:
Globally catch exceptions in a WPF application?
(7 answers)
Closed 6 years ago.
Sometimes, under not reproducible circumstances, my WPF application crashes without any message. The application simply close instantly.
Where is the best place to implement the global Try/Catch block. At least I have to implement a messagebox with: "Sorry for the inconvenience ..."
You can trap unhandled exceptions at different levels:
AppDomain.CurrentDomain.UnhandledException From all threads in the AppDomain.
Dispatcher.UnhandledException From a single specific UI dispatcher thread.
Application.Current.DispatcherUnhandledException From the main UI dispatcher thread in your WPF application.
TaskScheduler.UnobservedTaskException from within each AppDomain that uses a task scheduler for asynchronous operations.
You should consider what level you need to trap unhandled exceptions at.
Deciding between #2 and #3 depends upon whether you're using more than one WPF thread. This is quite an exotic situation and if you're unsure whether you are or not, then it's most likely that you're not.
You can handle the AppDomain.UnhandledException event
EDIT: actually, this event is probably more adequate: Application.DispatcherUnhandledException
A quick example of code for Application.Dispatcher.UnhandledException:
public App() {
this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message);
MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
// OR whatever you want like logging etc. MessageBox it's just example
// for quick debugging etc.
e.Handled = true;
}
I added this code in App.xaml.cs
I use the following code in my WPF apps to show a "Sorry for the inconvenience" dialog box whenever an unhandled exception occurs. It shows the exception message, and asks user whether they want to close the app or ignore the exception and continue (the latter case is convenient when a non-fatal exceptions occur and user can still normally continue to use the app).
In App.xaml add the Startup event handler:
<Application .... Startup="Application_Startup">
In App.xaml.cs code add Startup event handler function that will register the global application event handler:
using System.Windows.Threading;
private void Application_Startup(object sender, StartupEventArgs e)
{
// Global exception handling
Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);
}
void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
\#if DEBUG // In debug mode do not custom-handle the exception, let Visual Studio handle it
e.Handled = false;
\#else
ShowUnhandledException(e);
\#endif
}
void ShowUnhandledException(DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
string errorMessage = string.Format("An application error occurred.\nPlease check whether your data is correct and repeat the action. If this error occurs again there seems to be a more serious malfunction in the application, and you better close it.\n\nError: {0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)",
e.Exception.Message + (e.Exception.InnerException != null ? "\n" +
e.Exception.InnerException.Message : null));
if (MessageBox.Show(errorMessage, "Application Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No) {
if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
Best answer is probably https://stackoverflow.com/a/1472562/601990.
Here is some code that shows how to use it:
App.xaml.cs
public sealed partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
// setting up the Dependency Injection container
var resolver = ResolverFactory.Get();
// getting the ILogger or ILog interface
var logger = resolver.Resolve<ILogger>();
RegisterGlobalExceptionHandling(logger);
// Bootstrapping Dependency Injection
// injects ViewModel into MainWindow.xaml
// remember to remove the StartupUri attribute in App.xaml
var mainWindow = resolver.Resolve<Pages.MainWindow>();
mainWindow.Show();
}
private void RegisterGlobalExceptionHandling(ILogger log)
{
// this is the line you really want
AppDomain.CurrentDomain.UnhandledException +=
(sender, args) => CurrentDomainOnUnhandledException(args, log);
// optional: hooking up some more handlers
// remember that you need to hook up additional handlers when
// logging from other dispatchers, shedulers, or applications
Application.Dispatcher.UnhandledException +=
(sender, args) => DispatcherOnUnhandledException(args, log);
Application.Current.DispatcherUnhandledException +=
(sender, args) => CurrentOnDispatcherUnhandledException(args, log);
TaskScheduler.UnobservedTaskException +=
(sender, args) => TaskSchedulerOnUnobservedTaskException(args, log);
}
private static void TaskSchedulerOnUnobservedTaskException(UnobservedTaskExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
args.SetObserved();
}
private static void CurrentOnDispatcherUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
// args.Handled = true;
}
private static void DispatcherOnUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
{
log.Error(args.Exception, args.Exception.Message);
// args.Handled = true;
}
private static void CurrentDomainOnUnhandledException(UnhandledExceptionEventArgs args, ILogger log)
{
var exception = args.ExceptionObject as Exception;
var terminatingMessage = args.IsTerminating ? " The application is terminating." : string.Empty;
var exceptionMessage = exception?.Message ?? "An unmanaged exception occured.";
var message = string.Concat(exceptionMessage, terminatingMessage);
log.Error(exception, message);
}
}
In addition to the posts above:
Application.Current.DispatcherUnhandledException
will not catch exceptions that are thrown from a thread other than the main thread. You have to catch those exceptions on the same thread they are thrown. But if you want to Handle them on your global exception handler you can pass it to the main thread:
System.Threading.Thread t = new System.Threading.Thread(() =>
{
try
{
...
//this exception will not be catched by
//Application.DispatcherUnhandledException
throw new Exception("huh..");
...
}
catch (Exception ex)
{
//But we can handle it in the throwing thread
//and pass it to the main thread wehre Application.
//DispatcherUnhandledException can handle it
System.Windows.Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action<Exception>((exc) =>
{
throw new Exception("Exception from another Thread", exc);
}), ex);
}
});
To supplement Thomas's answer, the Application class also has the DispatcherUnhandledException event that you can handle.
A complete solution is here
it's explained very nice with sample code. However, be careful that it does not close the application.Add the line
Application.Current.Shutdown();
to gracefully close the app.
As mentioned above
Application.Current.DispatcherUnhandledException will not catch
exceptions that are thrown from another thread then the main thread.
That actual depend on how the thread was created
One case that is not handled by Application.Current.DispatcherUnhandledException is System.Windows.Forms.Timer for which Application.ThreadException can be used to handle these
if you run Forms on other threads than the main thread you will need to set Application.ThreadException from each such thread

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 ...
}

NUnit secondary thread exception

I'm testing the code which starts a secondary thread. And this thread sometimes throws an exception. I'd like to write a test which fails if that exception isn't handled properly.
I've prepared that test, and what I'm seeing in NUnit is:
LegacyImportWrapperTests.Import_ExceptionInImport_Ok : PassedSystem.ArgumentException: aaaaaaaaaa
at Import.Legacy.Tests.Stub.ImportStub.Import() in ImportStub.cs: line 51...
But the test is marked as GREEN. So, NUnit knows about that exception, but why does it mark the test as Passed?
That you can see the exception details in the output does not necessarily mean that NUnit is aware of the exception.
I have used the AppDomain.UnhandledException event to monitor scenarios like this during testing (given that the exception is unhandled, which I assume is the case here):
bool exceptionWasThrown = false;
UnhandledExceptionEventHandler unhandledExceptionHandler = (s, e) =>
{
if (!exceptionWasThrown)
{
exceptionWasThrown = true;
}
};
AppDomain.CurrentDomain.UnhandledException += unhandledExceptionHandler;
// perform the test here, using whatever synchronization mechanisms needed
// to wait for threads to finish
// ...and detach the event handler
AppDomain.CurrentDomain.UnhandledException -= unhandledExceptionHandler;
// make assertions
Assert.IsFalse(exceptionWasThrown, "There was at least one unhandled exception");
If you want to test only for specific exceptions you can do that in the event handler:
UnhandledExceptionEventHandler unhandledExceptionHandler = (s, e) =>
{
if (!exceptionWasThrown)
{
exceptionWasThrown = e.ExceptionObject.GetType() ==
typeof(PassedSystem.ArgumentException);
}
};

Throwing an exception from a BackgroundWorker which calls an async. method (Webrequest)

My main application creates a new BackgroundWorker X
the DoWork event handler of X calls a method Y of my controller. This method creates the WebRequest (async.) instance and the callback using AsyncCallback.
When the response arrives the callback method Z gets called and the content will be analyzed. It can happen that the response has an unwanted content. At that moment callback Z will throw an exception.
I want to catch this exception in my main application.
I tried it in DoWork and RunWorkerCompleted but nothing can be caught from there.
Error in RunWorkerCompletedEventArgs is always null.
Dont know what you are doing wrong. But this works like charm.
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (o, s) => { throw new Exception("myMessage"); };
bw.RunWorkerCompleted += (o, s) => { Console.WriteLine(s.Error.Message); };
bw.RunWorkerAsync();
Console.ReadKey(true);
So this means that somewhere your exception must be getting caught, and thus is prevented from propagating to the BWWorkCompletedEventArgs

Categories