Search code examples
c#exceptionappdomainunhandled

UnhandledExceptionMode.ThrowException for AppDomain.UnhandledException


I want to set UnhandledExceptionMode.ThrowException for the current AppDomain and not only for the Application-Thread. An exception from another thread should be handled by my CurrentDomain_UnhandledException event handler, too. Is this possible? Here is my code:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        File.AppendAllText("Log.txt", ((Exception)e.ExceptionObject).Message + Environment.NewLine);
    }
}

Solution

  • Perhaps you are looking for the behaviour provided by Application.ThreadException? http://msdn.microsoft.com/en-us/library/system.windows.forms.application.threadexception%28v=vs.80%29.aspx

    One way to achieve the behaviour you want, according to your comment, is to enable the old unhandled exception policy from .Net 1.

    In App.config:

    <runtime>
        <legacyUnhandledExceptionPolicy enabled="1" />
    </runtime>
    

    Then modify your main method like this:

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            try
            {
                AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    
                ThreadPool.QueueUserWorkItem((object state) =>
                {
                    throw new Exception("Exception thrown on Background Thread");
                });
    
                throw new Exception("Exception at the end of Main");
            }
            catch (Exception exception)
            {
                // Exceptions thrown on the Main Thread will pass through here
                HandleUnhandledException(exception);
            }
        }
    
        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            // Exceptions thrown on Background Threads will pass through here
            HandleUnhandledException((Exception)e.ExceptionObject);
        }
    
        static void HandleUnhandledException(Exception exception)
        {
            // TODO: Write your Unhandled Exception routine here
            Console.WriteLine(exception.Message);
        }
    }
    

    Enabling the legacy exception policy causes exceptions on background threads to be ignored by the main thread. They will only ever be seen by the unhanded exception event listener. Exceptions on the main thread do need to be handled in order to prevent the .NET Unhandled Exception dialog but, by using a shared method, you can re-use the exception handling code.


    The event handler that you attach to AppDomain.UnhandledException will catch all unhandled exceptions that originate on all the threads in the AppDomain. If you remove Windows-Forms from the picture, here is some code that illustrates it:

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    
            ThreadPool.QueueUserWorkItem((object state) =>
            {
                throw new Exception("Exception thrown on Background Thread");
            });
    
            throw new Exception("Exception at the end of Main");
        }
    
        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine(((Exception)e.ExceptionObject).Message);
        }
    }
    

    If you run this, you will see that both exception messages are written to the console immediately before the application crashes due to the unhandled exception at the end of Main. (Note: this does illustrate that the event handler works for both exceptions but it has a race condition - in real life, an unhandled exception will kill the AppDomain before the next one could be raised)