We use the Dispatcher to catch any unhandled exceptions in our WPF app. This is defined in our app.xaml.cs file and it works very well. However we have a situation where we want to detect and trap any unhandled exceptions that happen in a specific WPF User Control. We would like to be able to intercept any unhandled erros related to that control prior to them being received and handled by the handler at the app level. When we try to set up a handler for the User Control dispatcher the unhandled erro always seems to get handled at the application level first and then at the user control level. Even though we put Handled=True in both of the handlers. No worker threads are being used.
We know we can go into the user control and all the code it calls and setup try{}catch{} blocks and throw custom exceptions but we were hoping for a bit more of a turn key solution.
Any Ideas?
Hope this question makes sense..
There's no such thing as a "User Control dispatcher". There's always at most one active dispatcher per thread. Thus, the order in which your handlers for Dispatcher.UnhandledException events will be processed is defined only by the order in which they are registered.
Related
If I put AppDomain.CurrentDomain.UnhandledException code in console application apart from usual try-catch to catch unhandled exceptions. That means, is it sure that any exception will not force application to terminate in between?
If not, what type of exceptions are out of scope of it?
No. It means that you will have the chance to run some code before your application crashes, but you will not be able to prevent the crash. Documentation:
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.
Trying to make the application "crash-proof" by blindly catching all exceptions is a fool's errand: since you don't really know what went wrong, how do you know that it's OK for the program to continue running?
Theoretically speaking, anything you do inside the event handler might go wrong in any possible manner (since an unhandled exception was thrown, and you don't know what it is, it could be anything). So not only is it impossible to prevent the application from crashing, but you should also be very careful about what you do inside the handler.
No, the application will be terminated anyway, but it gives you a chance to log the exception properly before the application exits. See here: http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx
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.
When debugging my application I see messages like this all the time:
An exception of type 'xxxx.xxxxx' occurred in xxxxx.exe
but was not handled in user code.
The problem is that I have BackgroundWorkers that throw exceptions in their DoWork, these that are then handled by checking the RunWorkerCompletedEventArgs.Error in the RunWorkerCompleted event - and it works great at runtime.
Is there any way to prevent visual studio from showing these as "unhandled"?
Is this not the correct way to return errors from DoWork back to the UI?
I tried making my exception extend ApplicationException and unticking the box next to ApplicationException in the exceptions dialog but it still shows up.
You need to catch and handle exceptions inside the methods that your DoWork method calls. My recommendation would be to catch the exception and then use the ReportProgress event to report it back to the interface for smooth handling/notification. You don't ever want to "swallow" an exception, but this reporting will allow you to gracefully log the exception or notify the user in a less intrusive manner.
Keep in mind, you'll need to to use the overload of ReportProgress that allows the use of a custom userState so that you can either report proper progress or attach the full exception.
I'm looking for some guidance on best practices on handling exceptions in events. Currently, when exceptions are thrown in my application, the exception message is displayed in a pop up dialog and then the application restarts after hitting ok. The issue I'm seeing is that a lot of exceptions are occurring in the event handlers of some third party libraries and these exceptions are swallowed and never displayed since they are on a background thread. Here are a few solutions that various people have thought of and I would like to know of any of these are the best approach.
Forward the background thread to the UI thread in every event handler in the application.
Wrap the events in another class which has a try/catch around every method that invokes the event. The catch will then forward the exception to the UI thread if one occurs.
Get access to the third party libraries and put try/catch around where the events are being invoked, which could then be forwarded to the main application by a global event.
Lets discuss your options the way you listed them:
1) Forward the background thread to the UI thread in every event
handler in the application.
You should not and you can't! because:
You can't pretend if that event "which may comes from a third party" starts another background thread
or timer.
The whole point of having background threads is not
to freeze the UI, you will then struggle the user interface by a long execution codes.
2) Wrap the events in another class which has a try/catch around every method that invokes the event. The catch will then forward the exception to the UI thread if one occurs.
The same point as the previous. you can't pretend it that event starts another thread..
3) Get access to the third party libraries and put try/catch around where the events are being invoked, which could then be forwarded to the main application by a global event.
This is a bad choice, really, You should not change that code of third party libraries even if you can. because:
You are not the author for those libraries.
Whenever you want to update the library version or even change the libraries, you have to rewrite there code..
So what you have to do? The answer is some sort of what you are currently doing:
Whenever any exception thrown, log the exception restart your process, and at some point in your process send the logged bugs to your email and then start fixing them.
None of the above. Instead hook up the events on the Application and AppDomain for unhandled exceptions.
AppDomain.CurrentDomain.UnhandledException Event
Application.DispatcherUnhandledException Event
Further Information: The global exception handling event for WPF applications Application.DispatcherUnhandledException fires only for exceptions thrown on the main UI thread. However the AppDomain.CurrentDomain.UnhandledException should fire on any unhandled exception in any thread (unfortunately there is no preventing the application from shutting down after ward it reaches here).
Did some quick research on best practices and found that it is recommend that you manually handle exceptions on the background threads with try\catch block. Read the exception part on this page http://www.albahari.com/threading/ and also take a look at this StackOverflow question Catching unhandled exception on separate threads
If you're hooking the AppDomain.UnhandledException event, then the issue isn't the fact that they might be calling back on a background thread, but rather than the third-party library is explicitly swallowing exceptions thrown by the handlers. This is a badly behaving library, but, since you're writing the event handler code, you can catch the exceptions in the event handler and force the application to shut down.
Since the third-party library can't be stopped by throwing an exception, you can force the thread to terminate by calling:
Thread.CurrentThread.Abort();
Thread.Abort() is generally considered a bad practice, but it's slightly less dangerous here, as you are aborting yourself and therefore won't be injecting the exception into potentially nasty locations (you also know that the thread is not in an unmanaged context, so it will abort right away.) It's still a nasty hack, but the third-party application isn't giving you much choice. ThreadAbortException cannot be 'stopped', so the third-party code will terminate its thread as soon as it reaches the end of its exception handlers (even if they try to swallow it). If the third-party library is really nasty, it might invoke lots of code in its catch or finally blocks, even using dirty tricks to stay alive like launching other threads, but it would have to be pretty malicious to do this.
To get the friendly error message behavior, you can marshal the Exception to your UI thread using a SynchronizationContext or Dispatcher to call your exception-handler display (the easiest way may be to just re-throw the exception; I recommend embedding it as an InnerException so that you don't lose stack trace.)
If you really distrust the library (and don't want to give it the opportunity to stay alive even through its catch and finally blocks), you can explicitly marshal to the UI thread with a blocking invoke (to display your error message in a friendly way) and then call Environment.FailFast() to kill your process. This is a particularly harsh way to terminate (it will not call any cleanup code and literally tears down the process as quickly as possible), but it minimizes the possibility for any potentially damaging side effects if application state has become very corrupted. One possible thing to watch for here is that the UI thread could be blocked by some other UI invocation tied to the third-party code. If this happens, the application will deadlock. Again, this would be a pretty malicious thing for it to do, so you can probably ignore it.
I apologize if this is a simple question (my Google-Fu may be bad today).
Imagine this WinForms application, that has this type of design: Main application -> shows one dialog -> that 1st dialog can show another dialog. Both of the dialogs have OK/Cancel buttons (data entry).
I'm trying to figure out some type of global exception handling, along the lines of Application.ThreadException. What I mean is:
Each of the dialogs will have a few event handlers. The 2nd dialog may have:
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
AllSelectedIndexChangedCodeInThisFunction();
}
catch(Exception ex)
{
btnOK.enabled = false; // Bad things, let's not let them save
// log stuff, and other good things
}
}
Really, all the event handlers in this dialog should be handled in this way. It's an exceptional-case, so I just want to log all the pertinent information, show a message, and disable the okay button for that dialog.
But, I want to avoid a try/catch in each event handler (if I could). A draw-back of all these try/catch's is this:
private void someFunction()
{
// If an exception occurs in SelectedIndexChanged,
// it doesn't propagate to this function
combobox.selectedIndex = 3;
}
I don't believe that Application.ThreadException is a solution, because I don't want the exception to fall all the way-back to the 1st dialog and then the main app. I don't want to close the app down, I just want to log it, display a message, and let them cancel out of the dialog. They can decide what to do from there (maybe go somewhere else in the app).
Basically, a "global handler" in between the 1st dialog and the 2nd (and then, I suppose, another "global handler" in between the main app and the 1st dialog).
Yes, the default handling of Application.ThreadException was a mistake. Unfortunately, it was a necessary mistake, needed to not immediately discourage and despair hundreds of thousands of programmers writing their first Windows Forms application.
The fix you are contemplating is not a fix, it has a lot of potential to make it worse. While a user clicking the Continue button on the exception dialog is a questionable outcome, swallowing exceptions in a global exception handler is much worse.
Yes, do write a replacement handler for ThreadException. Have it display the value of e.Exception.ToString() in a message box so the user has some idea what blew up. Then fire off an email or append to an error log so you know what went wrong. Then call Environment.FailFast() so no more damage can be done.
Do the same for AppDomain.CurrentDomain.UnhandledException. It won't get much of a workout.
Use the feedback to improve your code. You'll find out where validation is required. You can help the customer's IT staff diagnose trouble with their LAN and equipment. And you'll find the very few cases where your own try/catch blocks might be able to recover from the exception.
You may be able to use the AppDomain.CurrentDomain.UnhandledException handler to intercept the errors on the main UI thread and handle them per-dialog. From MSDN:
In applications that use Windows
Forms, unhandled exceptions in the
main application thread cause the
Application.ThreadException event
to be raised. If this event is
handled, the default behavior is that
the unhandled exception does not
terminate the application, although
the application is left in an unknown
state. In that case, the
UnhandledException event is not
raised. This behavior can be changed
by using the application configuration
file, or by using the
Application.SetUnhandledExceptionMode
method to change the mode to
UnhandledExceptionMode.ThrowException
before the ThreadException event
handler is hooked up. This applies
only to the main application thread.
The UnhandledException event is raised
for unhandled exceptions thrown in
other threads.
You may like to rethink the design of your application slightly if you're doing stuff in combobox event handlers that might throw exceptions.
An alternative would be to initialise the dialog with all the information it needs before showing it to the user. The user then makes selections, and presses OK, and then the parent dialog could process the information in the dialog.
The exception handling could then be done in the parent dialog.
Of course this wouldn't be appropriate if you need to dynamically update the data in the dialog based on user actions...
e.g.
MyDialog myDialog = new MyDialog();
myDialog.Init(//data for the user to choose/manipulate);
if(myDialog.ShowDialog() == DialogResult.OK)
{
try{
ProcessDialogData(myDialog.SomeDataObject);
}
catch(/*...*/}
}
HTH
Global exception handling in WinForms application is done using two handlers: Application.ThreadException and AppDomain.CurrentDomain.UnhandledException. ThreadException catches unhandled exceptions in the main application thread, while CurrentDomain.UnhandledException catches unhandled exceptions in all other threads. Global exception handling may be used for the following purposes: showing user-friendly error message, logging the stack trace and other useful information, cleanup, sending error report to developer. After unhandled exception is catched, application should be terminated. You may want to restart it, but it is impossible to correct an error and continue, at least, in non-trivial applications.
Global exception handling is not replacement for local exception handling, which still should be used. Local exception handlers should never use catch Exception, because this effectively hides programming bugs. It is necessary to catch only expected exceptions in every case. Any unexpected exception should crash the program.
Sounds like you want aspects. PostSharp could help you out.
I'm maintaining a .NET 1.1 application and one of the things I've been tasked with is making sure the user doesn't see any unfriendly error notifications.
I've added handlers to Application.ThreadException and AppDomain.CurrentDomain.UnhandledException, which do get called. My problem is that the standard CLR error dialog is still displayed (before the exception handler is called).
Jeff talks about this problem on his blog here and here. But there's no solution. So what is the standard way in .NET 1.1 to handle uncaught exceptions and display a friendly dialog box?
Jeff's response was marked as the correct answer because the link he provided has the most complete information on how to do what's required.
Oh, in Windows Forms you definitely should be able to get it to work. The only thing you have to watch out for is things happening on different threads.
I have an old Code Project article here which should help:
User Friendly Exception Handling
Unhandled exception behavior in a .NET 1.x Windows Forms application depends on:
The type of thread that threw the exception
Whether it occurred during window message processing
Whether a debugger was attached to the process
The DbgJitDebugLaunchSetting registry setting
The jitDebugging flag in App.Config
Whether you overrode the Windows Forms exception handler
Whether you handled the CLR’s exception event
The phase of the moon
The default behavior of unhandled exceptions is:
If the exception occurs on the main thread when pumping window messages, it's intercepted by the Windows Forms exception handler.
If the exception occurs on the main thread when pumping window messages, it will terminate the app process unless it's intercepted by the Windows Forms exception handler.
If the exception occurs on a manual, thread-pool, or finalizer thread, it's swallowed by the CLR.
The points of contact for an unhandled exception are:
Windows Forms exception handler.
The JIT-debug registry switch DbgJitDebugLaunchSetting.
The CLR unhandled exception event.
The Windows Form built-in exception handling does the following by default:
Catches an unhandled exception when:
exception is on main thread and no debugger attached.
exception occurs during window message processing.
jitDebugging = false in App.Config.
Shows dialog to user and prevents app termination.
You can disable the latter behavior by setting jitDebugging = true in App.Config. But remember that this may be your last chance to stop app termination. So the next step to catch an unhandled exception is registering for event Application.ThreadException, e.g.:
Application.ThreadException += new
Threading.ThreadExceptionHandler(CatchFormsExceptions);
Note the registry setting DbgJitDebugLaunchSetting under HKEY_LOCAL_MACHINE\Software.NetFramework. This has one of three values of which I'm aware:
0: shows user dialog asking "debug or terminate".
1: lets exception through for CLR to deal with.
2: launches debugger specified in DbgManagedDebugger registry key.
In Visual Studio, go to menu Tools → Options → Debugging → JIT to set this key to 0 or 2. But a value of 1 is usually best on an end-user's machine. Note that this registry key is acted on before the CLR unhandled exception event.
This last event is your last chance to log an unhandled exception. It's triggered before your Finally blocks have executed. You can intercept this event as follows:
AppDomain.CurrentDomain.UnhandledException += new
System.UnhandledExceptionEventHandler(CatchClrExceptions);
AppDomain.UnhandledException is an event, not a global exception handler. This means, by the time it is raised, your application is already on its way down the drain, and there is nothing you can do about it, except for doing cleanup and error logging.
What happened behind the scenes is this: The framework detected the exception, walked up the call stack to the very top, found no handlers that would recover from the error, so was unable to determine if it was safe to continue execution. So, it started the shutdown sequence and fired up this event as a courtesy to you so you can pay your respects to your already-doomed process. This happens when an exception is left unhandled in the main thread.
There is no single-point solution to this kind of error. You need to put a real exception handler (a catch block) upstream of all places where this error occurs and forward it to (for example) a global handler method/class that will determine if it is safe to simply report and continue, based on exception type and/or content.
Edit: It is possible to disable (=hack) the error-reporting mechanism built into Windows so the mandatory "crash and burn" dialog does not get displayed when your app goes down. However, this becomes effective for all the applications in the system, not just your own.
Is this a console application or a Windows Forms application? If it's a .NET 1.1 console application this is, sadly, by design -- it's confirmed by an MSFT dev in the second blog post you referenced:
BTW, on my 1.1 machine the example from MSDN does have the expected output; it's just that the second line doesn't show up until after you've attached a debugger (or not). In v2 we've flipped things around so that the UnhandledException event fires before the debugger attaches, which seems to be what most people expect.
It sounds like .NET 2.0 does this better (thank goodness), but honestly, I never had time to go back and check.
It's a Windows Forms application. The exceptions that are caught by Application.ThreadException work fine, and I don't get the ugly .NET exception box (OK to terminate, Cancel to debug? who came up with that??).
I was getting some exceptions that weren't being caught by that and ended up going to the AppDomain.UnhandledException event that were causing problems. I think I've caught most of those exceptions, and I am displaying them in our nice error box now.
So I'll just have to hope there are not some other circumstances that would cause exceptions to not be caught by the Application.ThreadException handler.
The Short Answer,
Looks like, an exception occurring in Form.Load doesn't get routed to Application.ThreadException or AppDomain.CurrentDomain.UnhandledException without a debugger attached.
The More accurate Answer/Story
This is how I solved a similar problem. I can't say for sure how it does it, but here is what I think. Improvement suggestions are welcome.
The three events,
AppDomain.CurrentDomain.FirstChanceException
AppDomain.CurrentDomain.UnhandledException
and Application.ThreadException
accumulatively catch most of the exceptions but not on a global scope (as said earlier). In one of my applications, I used a combination of these to catch all kinds of exceptions and even the unmanaged code exceptions like DirectX exception (through SharpDX). All exceptions, whether they are caught or not, seem to be invoking FirstChanceException without a doubt.
AppDomain.CurrentDomain.FirstChanceException += MyFirstChanceExceptionHandler;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); // not sure if this is important or not.
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; // can't use Lambda here. need to Unsub this event later.
Application.ThreadException += (s, e) => MyUnhandledExceptionHandler(e.Exception);
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MyUnhandledExceptionHandler((Exception)e.ExceptionObject);
}
private void CurrentDomain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs eventArgs)
{
// detect the pattern of the exception which we won't be able to get in Fatal events.
if (eventArgs.Exception.Message.StartsWith("HRESULT"))
MyUnhandledExceptionHandler(eventArgs.Exception);
}
and the handler looks like
static void MyUnhandledExceptionHandler(Exception ex)
{
AppDomain.CurrentDomain.UnhandledException -= MyUnhandledExceptionHandler; // this is important. Any exception occuring in the logging mechanism can cause a stack overflow exception which triggers the window's own JIT message/App crash message if Win JIT is not available.
// LogTheException()
// Collect user data
// inform the user in a civil way to restart/close the app
Environment.Exit(0);
}
Unmanaged code exceptions like DirectX exceptions appeared only in FirstChanceException where I had to decide for myself if the exception was fatal or not. I then use MyUnhandledExceptionHandler to log and let the user know in a friendly way that everything was "under control".
IMPORTANT NOTE!
The scheme still didn't catch one kind of exception. It did appear in FirstChanceException, but it was hard to distinguish it from other kinds of exceptions hitting this handler. Any exception occurring directly in Form.Load had this different behavior. When the VS debugger was attached, these were routed to the UnhandledException event. But without a debugger, an old-school windows message will pop up, showing the stack trace of the exception that occurred. The most annoying thing was that it didn't let MyUnhandledExceptionHandlerr get kicked once it was done and the app continued to work in an abnormal state. The final solution I did was to move all the code from Form_load to another thread using MyForm.Load += (s,e) => new Thread(()=>{/* My Form_Load code*/ }).Start();. This way, Application.ThreadException gets triggered which is routed to MyUnhandledExceptionHandler, my safe exit.