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.
精彩评论