27

I am using the following event to catch unhandled exceptions in the main UI thread.

Application.ThreadException 

Unfortunately, it does not catch those unhandled errors in seperate threads. I am aware of

AppDomain.CurrentDomain.UnhandledException

However, this seems to shut down the application upon triggering, where as the former does not.

Is there a way to deal with unhandled exceptions on separate threads, without the application closing?

Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
Darren Young
  • 10,972
  • 36
  • 91
  • 150
  • 6
    Yes, make sure your threads don't throw unhandled exception. As Eric Lippert puts it: "the safest thing to do is to assume that every unhandled exception is either a fatal exception or an unhandled boneheaded exception. In both cases, the right thing to do is to take down the process immediately." http://blogs.msdn.com/b/ericlippert/archive/2010/11/23/asynchrony-in-c-5-part-eight-more-exceptions.aspx – Ani Nov 26 '10 at 11:46
  • 4
    You forgot the best part of that article: "As Ripley said, when things go wrong you should take off and nuke the entire site from orbit; it's the only way to be sure" – Mike Caron Nov 26 '10 at 12:03
  • 1
    For those interested in finding the article, the previous link doesn't work anymore but you can go here: https://web.archive.org/web/20101124205815/http://blogs.msdn.com/b/ericlippert/archive/2010/11/23/asynchrony-in-c-5-part-eight-more-exceptions.aspx – John Thoits Sep 14 '20 at 20:15

3 Answers3

26

@Ani have already answered your question. Although I don't agree that unhandled exceptions in threads should terminate applications. Using threads usually means that you have some kind of server application. Bringing it down could result in a lot of angry users.

I've written a small piece about proper exception handling: https://coderr.io/exception-handling

You should always catch exceptions for threads. I usually use the following pattern:

  void ThreadMethod(object state)
  {
      try
      {
          ActualWorkerMethod();
      }
      catch (Exception err)
      {
          _logger.Error("Unhandled exception in thread.", err);
      }
  }

  void ActualWorkerMethod()
  {
      // do something clever
  }

It's a whole lot easier to find thread methods that doesn't handle exceptions properly by moving the logic into a seperate method and just keep the try/catch block in the thread method.

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • 2
    what if the unhandled exception on another thread is raised by a private async method of a 3rd party component you are using, how do you get a catch around that? – MC5 Feb 15 '14 at 16:50
  • You can't unless the third party library provides some way. As for async methods (Begin/End) you need to use catch in them. You can however catch the exception (but not rescue the application) by using `AppDomain.UnhandledException` event. – jgauffin Feb 15 '14 at 18:07
4

Of course you should always handle all exceptions. But if you are currently incapable of doing so, you can try the following:

The application will crash/close after the UnhandledException event handler. You can just add a delay in the event handler to prevents this. Other threads with no exception (e.g. the main thread) can continue. So the application will not close and can continue. However, the thread with the exception will remain in sleep. And therefor you may get a "memory/thread leak".

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        // Log the exception, display it, etc
        Debug.WriteLine((e.ExceptionObject as Exception).Message);
        Thread.Sleep(100000000);
    }

At this moment there is not a better solution. You may find to change the config file, but i think that is just as dirty: https://stackoverflow.com/a/15348736

Fang
  • 2,199
  • 4
  • 23
  • 44
2

Yes, you have to manually catch exceptions on threads.

However, this code:

void ThreadMethod(object state)
{
    try
    {
        ActualWorkerMethod();
    }
    catch (Exception err)
    {
        _logger.Error("Unhandled exception in thread.", err);
    }
}

void ActualWorkerMethod()
{
    // do something clever
}

can be simplified to this using PostSharp:

[LogExceptions]
void ActualWorkerMethod()
{
    // do something clever
}
Martin Konicek
  • 39,126
  • 20
  • 90
  • 98