94

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?

demonplus
  • 5,613
  • 12
  • 49
  • 68
Isaac Bolinger
  • 7,328
  • 11
  • 52
  • 90

4 Answers4

130

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.

Jesse Chisholm
  • 3,857
  • 1
  • 35
  • 29
Can Gencer
  • 8,822
  • 5
  • 33
  • 52
  • 1
    I made a background worker, and in the dowork event handler I intentially caused a null reference exception. However it didn't get caught by the AppDomain.CurrentDomain.UnhandledException in spite of setting these: Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); – Isaac Bolinger Apr 23 '11 at 08:25
  • 5
    @IsaacB, background worker catches exceptions itself. You can check the exception in the RunWorkerCompleted even, looking at the RunCompletedEventArgs.Error property. – Can Gencer Apr 23 '11 at 08:33
  • 1
    You can test the exception handling for additional threads by putting this into the OnLoad of your main form. new Thread(() => { throw new Exception(); }).Start(); – Can Gencer Apr 23 '11 at 08:36
  • Unfortunately handling UnhandledException will not stop application from terminating :( – Nazar Grynko Jul 09 '13 at 23:52
  • 7
    Instead of the FriendlyName.EndsWith hack, try Debugger.IsAttached which is cleaner. – moltenform Mar 21 '16 at 19:59
  • IMHO, ***add notes in your answer***, **use** `Debugger.IsAttached` for _prevent catching the exceptions when debugging_ and _handling UnhandledException will not stop application from terminating_ ( [reference](http://stackoverflow.com/a/15348805/501082) by @NazarGrynko) – Kiquenet Mar 01 '17 at 11:22
  • Can I combine `AppDomain.CurrentDomain.UnhandledException and Application.ThreadException` with `[HandleProcessCorruptedStateExceptions]` tag ? http://stackoverflow.com/a/5763158/206730 [CLR Inside Out - Handling Corrupted State Exceptions](https://msdn.microsoft.com/en-us/magazine/dd419661.aspx) certain exceptions are [no longer caught by default](https://msdn.microsoft.com/en-us/magazine/dd419661.aspx); these tend to be exceptions that indicate a (possibly fatal) corrupted state of the executable, such as an AccessViolationException. – Kiquenet Mar 01 '17 at 12:05
  • In order to not catch exceptions while debugging, you can check System.Diagnostics.Debugger.IsAttached property value. It's more elegant than checking the running executable name. – Doug Mar 19 '18 at 20:31
  • There's also usually the preprocessor variable DEBUG, for readers in the future. – person27 May 16 '20 at 16:04
  • @person27 re: `DEBUG` using that conditional protects you from running this in a DEBUG compile. The recommended techniques let you catch the otherwise unhandled exceptions regardless of DEBUG or RELEASE compile, but protect from trying to double catch them in your code AND in the debugger code. – Jesse Chisholm Aug 14 '21 at 00:11
27

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;
  } 
Carlos P
  • 3,928
  • 2
  • 34
  • 50
  • Can I use `AppDomain.CurrentDomain.UnhandledException` and `Application.ThreadException` too with `[HandleProcessCorruptedStateExceptions]` tag ? – Kiquenet Mar 01 '17 at 10:03
22

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");
    }
Seb
  • 839
  • 8
  • 13
9

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());
Loren Pechtel
  • 8,945
  • 3
  • 33
  • 45
Teoman Soygul
  • 25,584
  • 6
  • 69
  • 80
  • 1
    You're welcome. Use the NBug project discussion forum if you have further questions (http://www.nbusy.com/forum/f11/) or use the [nbug] tag here. – Teoman Soygul Apr 23 '11 at 06:11
  • Of course, you can also subscribe a "regular" event handler to the UnhandledException event. See http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx – neo2862 Apr 23 '11 at 06:38
  • Guys on Win7 + VS10, if I subscribe to these events the subscription doesn't run, instead the regular Windows Vista/7 dialog shows up `Check Online for a Solution` Or `Close the Program`.. etc. But if I do NOT subscribe, I get the regular generic .NET Unhandled Exception Window. This happens on Both Release and Debug builds, also tried setting `Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);` Doesn't change anything. – gideon Apr 23 '11 at 06:52
  • @giddy, after handling the exceptions you should exit the application with Environment.Exit(1); if you don't want the error window displayed. – Teoman Soygul Apr 23 '11 at 07:11
  • @Teo thanks for your reply. I want my own error form to show up and then I want the app to exit. But the event subscription never runs, it just shows the generic Win Vista/7 dialog when it encounters exceptions. But if I don't subscribe the generic .NET unhandled exception dialog appears! – gideon Apr 23 '11 at 07:18
  • @giddy Try hooking up to all possible unhandled exception events: UnhandledException, ThreadException (WinForms), DispatcherUnhandledException (WPF), UnobservedTaskException (Threading.Tasks). It is possible that you've missed one of these unhandled exception sources. – Teoman Soygul Apr 23 '11 at 07:33
  • I'm on winforms, and subscribed to both Unhandled and Thread Exception. – gideon Apr 23 '11 at 07:52
  • Try something like this one: `Application.ThreadException += (sender, e) => { new MyErrorForm(); Environment.Exit(0); };` note that I changed Environment.Exit(1); to Environment.Exit(0); which should prevent Vista/7 dialog. – Teoman Soygul Apr 23 '11 at 07:58
  • GitHub is the new source repo. Send pull requests there: https://github.com/soygul/NBug – Kiquenet Mar 01 '17 at 10:06
  • I dont know the **good patterns and practices**. ***Be careful when using the AppDomain.UnhandledException event*** `Revision note:` I was pointed by ***Phillip Haack*** of this important omission. `Other common source of mistakes is the Application.ThreadException event. There are lots of caveats when using them,` – Kiquenet Mar 01 '17 at 10:07