Is there a way to show an MessageBox on any exception? [duplicate] - c#

Up until now, I just put a try/catch block around the Application.Run in the Program.cs entry point to the program. This catches all exceptions well enough in Debug mode, but when I run the program without the debug mode, exceptions don't get handled anymore. I get the unhandled exception box.
I don't want this to happen. I want all exceptions to be caught when running in non-debug mode. The program has multiple threads and preferably all exceptions from them get caught by the same handler; I want to log exceptions in the DB. Does anyone have any advice in how to do this?

Take a look at the example from the ThreadException documentation:
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new
ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);
// Set the unhandled exception mode to force all Windows Forms errors
// to go through our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
You might also want to not catch exceptions when debugging, as this makes it easier to debug. It is somewhat of a hack, but for that you can wrap the above code around with
if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe")) { ... }
To prevent catching the exceptions when debugging.
EDIT: An alternate way to check for your application running inside a debugger that feels cleaner than checking a filename.
(see comments by moltenform, Kiquenet and Doug)
if(!System.Diagnostics.Debugger.IsAttached) { ... }
This avoids the problem of using a different debugger than vshost.exe.

In NET 4, certain exceptions are no longer caught by default; these tend to be exceptions that indicate a (possibly fatal) corrupted state of the executable, such as an AccessViolationException.
Try using the [HandleProcessCorruptedStateExceptions] tag in front of your main method, e.g.
using System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions
[HandleProcessCorruptedStateExceptions]
public static int Main()
{
try
{
// Catch any exceptions leaking out of the program
CallMainProgramLoop();
}
catch (Exception e) // We could be catching anything here
{
System.Console.WriteLine(e.Message);
return 1;
}
return 0;
}

A nice example can be found at http://www.csharp-examples.net/catching-unhandled-exceptions/
Basically, change your main to:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
}

You can use NBug library for that. With minimal setup like this:
NBug.Settings.Destination1 = "Type=Mail;From=me#mycompany.com;To=bugtracker#mycompany.com;SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;
You can start collecting information on all unhandled bugs in your application, even when it's deployed to the clients. If you don't want to use a 3rd party library, you should attach to below events:
// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());

Related

Should UnhandledException notify all unhandled exceptions? [duplicate]

I wanted to set some handler for all the unexpected exceptions that I might not have caught inside my code. In Program.Main() I used the following code:
AppDomain.CurrentDomain.UnhandledException
+= new UnhandledExceptionEventHandler(ErrorHandler.HandleException);
But it didn't work as I expected. When I started the application in debugging mode and threw an exception it did call the handler, but afterwards the exception helper in Visual Studio popped up as if the exception occurred without any handling. I tried Application.Exit() inside the handler but it didn't work as well.
What I would like to achieve is that the exception is handled with my handler and then the application closes nicely. Is there any other way to do it or am I using the code above in the wrong way?
Normally I use something like this to try and catch all unexpected top-level exceptions.
using System;
static class Program
{
[STAThread]
static void Main(string[] argv)
{
try
{
AppDomain.CurrentDomain.UnhandledException += (sender,e)
=> FatalExceptionObject(e.ExceptionObject);
Application.ThreadException += (sender,e)
=> FatalExceptionHandler.Handle(e.Exception);
// whatever you need/want here
Application.Run(new MainWindow());
}
catch (Exception huh)
{
FatalExceptionHandler.Handle(huh);
}
}
static void FatalExceptionObject(object exceptionObject) {
var huh = exceptionObject as Exception;
if (huh == null) {
huh = new NotSupportedException(
"Unhandled exception doesn't derive from System.Exception: "
+ exceptionObject.ToString()
);
}
FatalExceptionHandler.Handle(huh);
}
}
Maybe it is something you find helpful too? This main code routes all three ways of catching unexpected top-level exceptions through one method call. All you now need is a static class FatalExceptionHandler that includes your top-level exception handling in its Handle method.
And really, any application developer knows there are really just two things to do there:
Show/log the exception like you see fit
Make sure you exit/kill the application process
If you think item two is strange, remember that we only bother to do this in the first place for really exceptional situations. These things are probably bugs that need changes to your application to be accurately addressed. Any other exception handling - the functional kind - should be lower down inside your actual program code, catching specific kinds of exceptions where this makes sense and handling them there in the way that makes sense. Anything else should bubble up to your FatalExceptionHandler to make itself known and stop the possibly crippled program from working from corrupted state
Dead programs tell no lies... ;-)
It's because you're running it through Visual Studio in Debug mode. If you release and install your app somewhere else, nothing but your global exception handler will be processed.
Note that unhandled exceptions are still pretty fatal; you can only really use this for logging, or maybe some hasty close-down. Neither this nor Application.ThreadException can be used as a global sink for errors.
The better approach is to add proper handling - for example, around your entire Main() logic. Note that even this can't catch a few exceptions, such as errors during form-load (which get particularly nasty - you can catch them with a debugger attached, but not without).
Perhaps what you're looking for is Environment.Exit(int errorcode)
That behavior is by design.
But there is a work-around.
Either you call Process.GetCurrentProcess().Kill(); within the handler, or simply do not let the handler end.
Check out the example:
class Program
{
void Run()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Console.WriteLine("Press enter to exit.");
do
{
(new Thread(delegate()
{
throw new ArgumentException("ha-ha");
})).Start();
} while (Console.ReadLine().Trim().ToLowerInvariant() == "x");
Console.WriteLine("last good-bye");
}
int r = 0;
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Interlocked.Increment(ref r);
Console.WriteLine("handled. {0}", r);
Console.WriteLine("Terminating " + e.IsTerminating.ToString());
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Dead thread";
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
//Process.GetCurrentProcess().Kill();
}
static void Main(string[] args)
{
Console.WriteLine("...");
(new Program()).Run();
}
}
This should not be a default sink for exceptions, surely.
But this should be done to report exceptions gracefully.
Note: if you're application is a Windows Forms application, don't forget to:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
... or else the application will terminate, even if you handle the exceptions with the handlers specified by the other answers.

Runtime exception catching different between inside and outside of MSVS

I am calling the following function some where in program that will throw an exception
public static List<Templates> LoadTemplates()
{
// ...
// System.Threading.Thread.CurrentThread.ManagedThreadId == 1 // ID written to log file
System.IO.Directory.GetFiles("does_not_exist_directory");
// ...
}
And I try to catch the exception in the default Program.cs
try
{
// System.Threading.Thread.CurrentThread.ManagedThreadId == 1
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
catch (Exception ex)
{
MessageBox.Show("ERROR CAUGHT");
}
finally { // do clean up }
When run in MSVS, the exception get caught as expected. But when run by double-clicking the .exe in the output directory the exception display in a message dialog stating
EDIT:
To catch the error when running the .exe from output directory, the code must be compiled with handling the Application.ThreadException event
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new Form());
But then MSVS will behave undesirably by showing the MSVS native "Troubleshooting Tips" borderless message dialog "Unhandled Exception".
How can I ensure that it behaves the same in and out of MSVS?
The code you have shown will only catch exceptions in the same thread. It's really hard to tell without seeing the offending code and it's context.
You can subscribe to a couple of events to catch all of those:
AppDomain.UnhandledException
Application.ThreadException
please read/note the docs (the first one should do) - there are some caveats.
It looks like your LoadTemplates call is made in an own Thread. I assume you don't see the MessageBox in Debug mode. You will see the Visual Studio exception window.
To solve this problem try to use the AppDomain.CurrentDomain.UnhandledException event:
[STAThread]
static void Main() {
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
MessageBox.Show("Unhandled exception");
}
Pertaining to the behaviour of exceptions in and out of MSVS, Carsten was right to point me to the code in MSDN but woni helped me realise the situation better.
(It might be otherwise, but) It appears that MSVS hooks its internal event handler to the application when it is run from inside MSVS and that handler is run before my handler in the application. Hence when a unhandled exception occurs, MSVS will show its native "troubleshooting tips" dialog box pointing to the error line.
At this point, if I click continue (F5) to continue execute the code, MSVS will re-throw the exception and this time it will be caught by my own handlers.
Outside of MSVS, no other handlers are subscribed so it just runs my handlers directly.

Does anyone have a proven formula for global exception handing in a C# Windows Forms application?

Global meaning "in one place" e.g. not multiple try...catches e.g. on each event handler. Proven meaning "known to work" - I'm aware covering both .NET and other exceptions is not straightforward.
Thanks.
Solution coded from answers below.
Note: this is believed to cover exceptions from additional threads.
static class Program
{
static void MyHandler(Exception e)
{ MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
static void MyThreadExceptionEventHandler(object sender, ThreadExceptionEventArgs args)
{ MyHandler(args.Exception);
// App continues.
}
static void MyAppExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{ MyHandler((Exception)args.ExceptionObject);
// There follows a OS "needs to close" dialog, terminating app.
}
static void Main()
{
// For UI thread exceptions
Application.ThreadException +=
new ThreadExceptionEventHandler(MyThreadExceptionEventHandler);
// Force all Windows Forms errors to go through our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// For non-UI thread exceptions
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(MyAppExceptionHandler);
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
The default behavior when it displays error dialog on unhandled exception and terminates is a good formula. If you don't like the look and feel of this dialog you can show your own instead but the principle is the same (good example is here):
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException
+= new ThreadExceptionEventHandler(/* YOUR OWN HANDLER */);
// Set the unhandled exception mode to force all
// Windows Forms errors to go through our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(/* YOUR OWN HANDLER */);
// Runs the application.
Application.Run(new /* YOUR MAIN FORM*/);
}
Generally there is no magic 'solution' to exception handling - you have to think about handling specific exceptions before calling any method. There is nothing special about Windows Forms in this regard.
Handle the AppDomain.CurrentDomain.UnhandledException and the Application.ThreadException you should be good!
Use Exception Handling Application Block and exception policy that may be adjusted in config file. I like it but it might be 'too heavy' for someone when considering very small projects.

How can I make something that catches all 'unhandled' exceptions in a WinForms application?

Up until now, I just put a try/catch block around the Application.Run in the Program.cs entry point to the program. This catches all exceptions well enough in Debug mode, but when I run the program without the debug mode, exceptions don't get handled anymore. I get the unhandled exception box.
I don't want this to happen. I want all exceptions to be caught when running in non-debug mode. The program has multiple threads and preferably all exceptions from them get caught by the same handler; I want to log exceptions in the DB. Does anyone have any advice in how to do this?
Take a look at the example from the ThreadException documentation:
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new
ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);
// Set the unhandled exception mode to force all Windows Forms errors
// to go through our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
You might also want to not catch exceptions when debugging, as this makes it easier to debug. It is somewhat of a hack, but for that you can wrap the above code around with
if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe")) { ... }
To prevent catching the exceptions when debugging.
EDIT: An alternate way to check for your application running inside a debugger that feels cleaner than checking a filename.
(see comments by moltenform, Kiquenet and Doug)
if(!System.Diagnostics.Debugger.IsAttached) { ... }
This avoids the problem of using a different debugger than vshost.exe.
In NET 4, certain exceptions are no longer caught by default; these tend to be exceptions that indicate a (possibly fatal) corrupted state of the executable, such as an AccessViolationException.
Try using the [HandleProcessCorruptedStateExceptions] tag in front of your main method, e.g.
using System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions
[HandleProcessCorruptedStateExceptions]
public static int Main()
{
try
{
// Catch any exceptions leaking out of the program
CallMainProgramLoop();
}
catch (Exception e) // We could be catching anything here
{
System.Console.WriteLine(e.Message);
return 1;
}
return 0;
}
A nice example can be found at http://www.csharp-examples.net/catching-unhandled-exceptions/
Basically, change your main to:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
}
You can use NBug library for that. With minimal setup like this:
NBug.Settings.Destination1 = "Type=Mail;From=me#mycompany.com;To=bugtracker#mycompany.com;SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;
You can start collecting information on all unhandled bugs in your application, even when it's deployed to the clients. If you don't want to use a 3rd party library, you should attach to below events:
// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());

Handling unhandled exceptions problem

I wanted to set some handler for all the unexpected exceptions that I might not have caught inside my code. In Program.Main() I used the following code:
AppDomain.CurrentDomain.UnhandledException
+= new UnhandledExceptionEventHandler(ErrorHandler.HandleException);
But it didn't work as I expected. When I started the application in debugging mode and threw an exception it did call the handler, but afterwards the exception helper in Visual Studio popped up as if the exception occurred without any handling. I tried Application.Exit() inside the handler but it didn't work as well.
What I would like to achieve is that the exception is handled with my handler and then the application closes nicely. Is there any other way to do it or am I using the code above in the wrong way?
Normally I use something like this to try and catch all unexpected top-level exceptions.
using System;
static class Program
{
[STAThread]
static void Main(string[] argv)
{
try
{
AppDomain.CurrentDomain.UnhandledException += (sender,e)
=> FatalExceptionObject(e.ExceptionObject);
Application.ThreadException += (sender,e)
=> FatalExceptionHandler.Handle(e.Exception);
// whatever you need/want here
Application.Run(new MainWindow());
}
catch (Exception huh)
{
FatalExceptionHandler.Handle(huh);
}
}
static void FatalExceptionObject(object exceptionObject) {
var huh = exceptionObject as Exception;
if (huh == null) {
huh = new NotSupportedException(
"Unhandled exception doesn't derive from System.Exception: "
+ exceptionObject.ToString()
);
}
FatalExceptionHandler.Handle(huh);
}
}
Maybe it is something you find helpful too? This main code routes all three ways of catching unexpected top-level exceptions through one method call. All you now need is a static class FatalExceptionHandler that includes your top-level exception handling in its Handle method.
And really, any application developer knows there are really just two things to do there:
Show/log the exception like you see fit
Make sure you exit/kill the application process
If you think item two is strange, remember that we only bother to do this in the first place for really exceptional situations. These things are probably bugs that need changes to your application to be accurately addressed. Any other exception handling - the functional kind - should be lower down inside your actual program code, catching specific kinds of exceptions where this makes sense and handling them there in the way that makes sense. Anything else should bubble up to your FatalExceptionHandler to make itself known and stop the possibly crippled program from working from corrupted state
Dead programs tell no lies... ;-)
It's because you're running it through Visual Studio in Debug mode. If you release and install your app somewhere else, nothing but your global exception handler will be processed.
Note that unhandled exceptions are still pretty fatal; you can only really use this for logging, or maybe some hasty close-down. Neither this nor Application.ThreadException can be used as a global sink for errors.
The better approach is to add proper handling - for example, around your entire Main() logic. Note that even this can't catch a few exceptions, such as errors during form-load (which get particularly nasty - you can catch them with a debugger attached, but not without).
Perhaps what you're looking for is Environment.Exit(int errorcode)
That behavior is by design.
But there is a work-around.
Either you call Process.GetCurrentProcess().Kill(); within the handler, or simply do not let the handler end.
Check out the example:
class Program
{
void Run()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Console.WriteLine("Press enter to exit.");
do
{
(new Thread(delegate()
{
throw new ArgumentException("ha-ha");
})).Start();
} while (Console.ReadLine().Trim().ToLowerInvariant() == "x");
Console.WriteLine("last good-bye");
}
int r = 0;
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Interlocked.Increment(ref r);
Console.WriteLine("handled. {0}", r);
Console.WriteLine("Terminating " + e.IsTerminating.ToString());
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Dead thread";
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
//Process.GetCurrentProcess().Kill();
}
static void Main(string[] args)
{
Console.WriteLine("...");
(new Program()).Run();
}
}
This should not be a default sink for exceptions, surely.
But this should be done to report exceptions gracefully.
Note: if you're application is a Windows Forms application, don't forget to:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
... or else the application will terminate, even if you handle the exceptions with the handlers specified by the other answers.

Categories