Question

I have written a WinForms application which performs some sort of syncing work. I want it to keep running despite of any occurrence of exceptions so that syncing keeps on going with next attempts. Thus, I have written the app such a way that whenever an exception occurs, it logs the exception stack trace, performs some diagnostics, then logs the diagnostics information and continues with next syncing attempts.

For uncaught exceptions I added Exception handlers for Application.ThreadException and also for AppDomain.CurrentDomain.UnhandledException in my Main() thread:

static void Main(string[] args)
{    
    Application.ThreadException += new ThreadExceptionEventHandler(UIThreadExceptionHandler);
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler);


    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new myForm());
}


//exception handlers
 public static void UIThreadExceptionHandler(object sender, ThreadExceptionEventArgs t)
 {
     logger.Fatal("Fatal Windows Forms Error");
     logStackTrace(t.Exception);                    //logs the stack trace with some desired formatting  
     Application.Exit(new CancelEventArgs(true));
 }

 public static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs t) 
 {
     logger.Fatal("Fatal Application Error");
     logStackTrace((Exception)(t.ExceptionObject)); //logs the stack trace with some desired formatting           
     Application.Exit(new CancelEventArgs(true));
 }

I kept my app running for testing and realized that whenever Application.ThreadException is caught, the app correctly logs the string Fatal Windows Forms Error, followed by the exception stack trace and then the application exits.

I dont want the app to exit. I just want that it should log the exception stack trace and continue with next syncing attempt. The exception that is occurring in UI thread is not that severe one, since the same exception also occurred in the other/non-UI threads of the app, but it did not crashed the app (as I can see this in logs). However when the same exception occurs in the UI thread, the app crashes.

Was it helpful?

Solution

As it's windows forms app Application.ThreadException is used for unhanded exception: "This event allows your Windows Forms application to handle otherwise unhandled exceptions that occur in Windows Forms threads. Attach your event handlers to the ThreadException event to deal with these exception" (MSDN)

I think you must expect such behavior as at UIThreadExceptionHandler you have Application.Exit(new CancelEventArgs(true)). Exit methods description: "Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed." (MSDN)

AppDomain.CurrentDomain.UnhandledException event is used to handle non-UI thread exceptions.

EDIT 1:

AppDomain.CurrentDomain.UnhandledException is specifically designed to log an exception before the system will inform a user and terminates the process. You can not prevent terminating the process (unless you are using Net 1.1).

Application.ThreadException + UnhandledExceptionMode.CatchException allows you to keep your UI thread alive. But, it's really not a great idea. It's much better to enclose error prone code in try-catch blocks instead.

Thus if you want to catch exceptions coming from thread and keep your application alive, you have to do it inside using try-catch block.

You haven't issue with UnhandledExceptionHandler, because it's not fired at all, I suppose.

OTHER TIPS

Windows Forms isn't really designed for a scenario where an application needs to run indefinitely. As you've experienced, by the time you've intercepted certain exceptions, your application is already being sucked into a black hole and you can't stop your application dying.

I think a better approach is to use a Windows service that has two threads: a foreground monitor thread and a background worker thread (use the BackgroundWorker type). The worker thread is where your sychronisation work happens. When the worker thread dies due to an unhandled exception, the monitor thread logs the exception and restarts the worker thread.

If the situation is nasty enough that the monitor thread dies as well (eg OutOfMemoryException or ExecutionEngineException), then the service itself will die. But you can set the service control manager to restart the service in that event.

If you need some sort of user interactivity, you can also create a Windows Forms application that talks to the your new service and starts/stops it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top