In winforms, if an unhandled exception is encountered, a dialogue pops up alerting you that an exception occurred. This has buttons to continue execution or quit the application. What I was wondering is what state the app continues from if you select the continue button. My instinct would have been that it operated like in a debugger, continuing on the next statement after the exception, but this doesn't seem to be the case. To demonstrate this, I made a winforms app with a TextBox textBox1 and a button button1 with the following functions:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void button1_Click(object Sender, EventArgs e) {
textBox1.Text = "Line before exception";
throw_Exception();
textBox1.Text = "Line after exception";
}
private void throw_Exception() => throw new Exception();
}
With this you see "Line before exception", then the exception dialogue (yay), but even if you hit continue, you do not reach "Line after exception". Obviously this is a silly example, but I am still unclear on what the continue button is actually doing. If the exception was thrown at the bottom of a large hierarchy does execution of everything up to the UI level stop? Does garbage collection run on any objects created before the exception? What if the exception is thrown on one thread of a multithreaded program?
Disclaimer: Yes, I know that there shouldn't be unhandled exceptions, and I certainly should not be throwing a general System.Exception. I am just asking how the continue operation works under the hood and how to determine what state a system is in if the continue button is pressed.
Related
I started a blank WPF application (shown below) to implement HockeyApp crash reporting. When the program starts, a window popups up with a single button for the user to press. When the user clicks it the handler attempts to divide by zero and crashes the app. I was receiving crash reports and everything was running smoothly UNTIL I mimicked our bigger system's error catching method, which was to use the DispatcherUnhandledException Event Handler to catch "uncaught" exceptions and then call System.Environment.Exit(0) to gracefully end anything in the background. Now the HockeyApp api isn't sending crash reports. I'm wondering if catching the exceptions at a higher level makes HockeyApp think "Oh, they got things under control" and won't register a "crash."
I'm currently talking to the HockeyApp support staff about this, but I'm wondering if anyone else has had this problem. Should I take out the Exit(0) line, or is there a better practice for exiting an app when we have an uncaught exception? I've tried changing the error code from 0 to 574 (ERROR_UNHANDLED_EXCEPTION) with no result. I don't believe there's any data that we need to save, other than what the HockeyApp api already has.
App class:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
RegisterHockeyAppCrashReporting();
Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
}
private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
System.Environment.Exit(0);
}
private async void RegisterHockeyAppCrashReporting()
{
HockeyClient.Current.Configure(AppConstants.APP_ID)
.SetContactInfo(AppConstants.USER_NAME, AppConstants.USER_EMAIL);
await HockeyClient.Current.SendCrashesAsync(true);
}
}
MainWindow class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var zero = 0;
var number = 1;
var crash = number / zero;
}
}
Environement.Exit terminates your application immediately. So, I guess, there's nothing strange in the fact that Hockey does not do anything.
Exit terminates an application immediately, even if other threads are
running. If the return statement is called in the application entry
point, it causes an application to terminate only after all foreground
threads have terminated.
If Exit is called from a try or catch block, the code in any finally
block does not execute. If the return statement is used, the code in
the finally block does execute.
Best practices tend to be opinion based and situation dependent. We, for example, log stack trace on unhandled exceptions and then call Environement.FailFast in our UWP app (we do not use Hockey apps though). Our logic is simple - our logger facility is probably alive but we're not so sure about the rest of the app. If even the logger facility is not functional than we won't be able to do anything anyway. Imho Exit and FailFast are the last steps that should only be used when you have no hope of restoring some valid state.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I continue running after an unhandled exception?
I've seen tons of similar questions and anwsers on SO, but not the same.
I'm handling all uncaught exception in main like this:
In Main I set following:
Application.ThreadException += new ThreadExceptionEventHandler(MainForm_UIThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new MainForm());
If I run my programm in debugger, after the exception occured and I handled them in MainForm_UIThreadException or CurrentDomain_UnhandledException, the yellow debugger arrow points to the line, where this exception actually occured, so I can step over, which means (for me) that execution context isn't lost.
I know that I cant continue execution for unhandled exceptions, but this esception is actually handled, just somewhere else.
Is it possible to continue execution of current function?
Thank you
You don't. When you get an AppDomain unhandled exception, your app is
no longer in a stable state. Where exactly would you resume to? When
you've gotten to that point, your only option, with good reason, is to
exit. You could reasonably schedule yourself to run again to make sure
the app comes back, but a far better idea is to actually handle the
exception at its source and prevent it from being an
UnhandledException.
From: How do I continue running after an unhandled exception?
In a WinForms application, if you want to continue running, you need to handle exceptions in your UI event handlers.
For example:
private void saveButton_Click(object sender, EventArgs e)
{
try
{
... call BLL to save data
}
catch(Exception ex)
{
MessageBox.Show("Failed to save data");
}
}
In my App.xaml.cs I have events to handle DispatcherUnhandledExceptions (UI thread) and UnhandledException (Non UI thread). When I throw an exception inside dispatcher.Invoke, the dispatcherhandler catches the exception and handles it. I am setting e.Handled to true after logging the exception. Now the strange behaviour, if i throw the exception outside of the dispatcher.Invoke as a regualr statment, control is sent to the dispatcher exception handler,but after the method is processed the app basically loses control but I can tell its still running by looking at the stop button in vs.
one more thing, if i set e.handled to false, control is sent to the non-ui thread exception handler.
So what puzzles me is why is the application locking after handling the exceptiono in the dispatcher handler?
here's my code
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// log exception here
e.Handled = true;
} // control is lost after executing this block
private void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
Exception ex = e.ExceptionObject as Exception;
// log exception here
}
finally
{
Environment.Exit(-1);
}
}
An UnhandledException means that your application is effectively dead. If you get that event then it is too late to do anything to recover from the scenario. Typically you would use this event only to log errors for debugging purposes and maybe attempt to cleanup some unmanaged resources.
The following article gives a detailed explanation of exception handling in WPF.
It seems like the app is able to resume operation if the exception is raised after the OnStartup Event, if the exception is raised in between, the exception is caught and handled but the main window is never shown yet the debugger shows the app as running.
the closest solution I found is to remove complex logic from the constructor of main window to allow onstartup event to execute and do a lot of loading in my MainWindow load event.
How to track window form crashing ? Like any event is called or anything else is called or we can track that window form is crashed ? Like dispose is called window form is crashed. But anything else which is happened so we can track out crashing of window form ?
Like problem is I have one window application on that there is tutorial balloon on the main form which moves for each control on the main form and describes the application functionality by indicating control on the main form one by one. And each time balloon moves balloon is disposes and new balloon form is created.
Now I want to insert the step number in the database when that balloon was crashed. I cannot understand what should I do ? What is happened when that balloon window(window form) is crashed ? There is a dispose event which is occurred but it is happened each time balloon creates so is there any thing else to track crashing ?
EDIT: Sorry to all, I forgot to specify that it is with .net framework 2.0.
Use this: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.threadexception.aspx
If any undhandled exception occurs in a forms thread, it will get here. If it's null, you get the usual dialog (undhandled exception occurred, you can continue or close, and see the stack trace).
This is an excerpt from a small Windows Forms 2.0 program of mine:
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException +=
applicationThreadException;
// Set the unhandled exception mode to force all Windows Forms
// errors to go through our handler.
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
currentDomainUnhandledException;
...
}
With the two handlers
private static void currentDomainUnhandledException(
object sender,
UnhandledExceptionEventArgs e)
{
handleException(e.ExceptionObject as Exception);
}
and
private static void applicationThreadException(
object sender,
ThreadExceptionEventArgs e)
{
handleException(e.Exception);
}
The actual function to handle the exceptions does in my example:
private static void handleException(
Exception exception)
{
LogCentral.Current.LogError(
#"Exception occurred.",
exception);
if (ErrorForm.IsErrorFormShowing)
{
LogCentral.Current.LogInfo(
#"Error form already showing, not showing again.",
exception);
}
else
{
using (var form = new ErrorForm(exception))
{
var result = form.ShowDialog();
if (result == DialogResult.Abort)
{
Application.Exit();
}
}
}
}
I.e. it logs the error via log4net and then displays an error form to show the user further information (exception message) and allow to quit the application.
In your Program.cs file, place a try/catch block inside the Main() function. The idea is to have the Application.Run(yourformhere) inside such a block. Then inside the catch you can probably manage to save some state (like the step at which the balloon crashed the form) in the DB. Good Luck!
Consider the following simple application: a windows form created by a "new C# windows application" sequence in VS that was modified in a following way:
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
Application.Run(new Form1());
}
catch (Exception ex)
{
MessageBox.Show("An unexpected exception was caught.");
}
}
Form1.cs contains the following modifications:
private void Form1_Load(object sender, EventArgs e)
{
throw new Exception("Error");
}
If I press F5 in IDE, then, as I expect, I see a message box saying that exception was caught and the application quits.
If I go to Debug(or Release)/bin and launch the executable, I see the standard "Unhandled exception" window, meaning that my exception handler doesn't work.
Obviously, that has something to do with exception being thrown from a different thread that Application.Run is called from. But the question remains - why the behavior differs depending on whether the application has been run from IDE or from command line?
What is the best practice to ensure that no exceptions remain unhandled in the application?
Normally Application.ThreadException will handle the exception in the Load event. You'll get the ThreadExceptionDialog that offers the Quit and Continue options.
But not when a debugger is attached. The catch clause in the message loop that displays the dialog is intentionally disabled in that case. That's necessary because it would be very difficult to trouble-shoot exceptions if that dialog pops up when you debug a program. Which this catcher no longer active, your catch clause in the Main() method now gets a shot at the exception.
You can make it consistent by using Application.SetUnhandledExceptionMode() in the Main() method. You shouldn't, exceptions really are hard to debug if you do this. If you want to customize exception handling for the UI thread then you should register your own Application.ThreadException handler:
if (!System.Diagnostics.Debugger.IsAttached)
Application.ThreadException += myThreadException;
Trapping unhandled exceptions in worker threads requires a AppDomain.UnhandledException handler. They are not recoverable.
Also beware of a bug in 64-bit Windows, exceptions in the Load event are swallowed without diagnostic when a debugger is attached. Force AnyCPU mode to avoid that trap.
In addition to catching any exceptions thrown inside the Main method you must also handle AppDomain.CurrentDomain.UnhandledException and Application.ThreadException.
Not sure why the behavior differs with and without a debugger attached though.