抑制Application.ThreadException和AppDomain.CurrentDomain.UnhandledException

时间:2014-04-18 11:34:51

标签: c# winforms exception unhandled-exception

我编写了一个WinForms应用程序,它执行某种同步工作。我希望它能够继续运行,尽管出现异常,以便同步继续进行下一次尝试。因此,我编写了应用程序,只要发生异常,它就会记录异常堆栈跟踪,执行一些诊断,然后记录诊断信息并继续下一次同步尝试。

对于未捕获的异常,我在Application.ThreadException主题中为AppDomain.CurrentDomain.UnhandledExceptionMain()添加了异常处理程序:

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));
 }

我保持我的应用程序运行以进行测试,并意识到只要捕获Application.ThreadException,应用程序就会正确记录字符串Fatal Windows Forms Error,然后是异常堆栈跟踪,然后应用程序退出。

我不希望该应用退出。我只是希望它应该记录异常堆栈跟踪并继续下一次同步尝试。 UI线程中发生的异常并不严重,因为在应用程序的其他/非UI线程中也发生了同样的异常,但它没有崩溃应用程序(我在日志中可以看到这一点)。但是,当UI线程中发生相同的异常时,应用程序崩溃。

2 个答案:

答案 0 :(得分:0)

因为它的Windows窗体应用程序Application.ThreadException用于非公开异常:"此事件允​​许您的Windows窗体应用程序处理Windows窗体线程中出现的其他未处理的异常。将事件处理程序附加到ThreadException事件以处理这些异常" (MSDN

我认为你必须期望在UIThreadExceptionHandler这样的行为你有Application.Exit(new CancelEventArgs(true))。退出方法说明:"通知所有消息泵必须终止,然后在处理完消息后关闭所有应用程序窗口。" (MSDN

AppDomain.CurrentDomain.UnhandledException事件用于处理非UI线程异常。

编辑1:

AppDomain.CurrentDomain.UnhandledException 专门用于在系统通知用户并终止进程之前记录异常。您无法阻止终止该过程(除非您使用的是Net 1.1)。

Application.ThreadException + UnhandledExceptionMode.CatchException 允许您保持UI线程的活动。但是,这真的不是一个好主意。将错误倾向代码包含在try-catch块中会好得多。

因此,如果你想捕获来自线程的异常并使应用程序保持活动状态,你必须使用try-catch块来实现它。

我还没有问过UnhandledExceptionHandler,因为它根本没有被解雇,我想。

答案 1 :(得分:0)

Windows Forms并非真正针对应用程序需要无限期运行的场景而设计。正如您所经历的那样,当您截获某些例外情况时,您的应用程序已经陷入了黑洞,您无法阻止您的应用程序死亡。

我认为更好的方法是使用具有两个线程的Windows服务:前台监视器线程和后台工作线程(使用BackgroundWorker类型)。工作线程是您的同步工作发生的地方。当工作线程由于未处理的异常而死亡时,监视器线程会记录异常并重新启动工作线程。

如果情况非常糟糕,监视器线程也会死掉(例如OutOfMemoryException或ExecutionEngineException),那么服务本身就会死掉。但您可以将服务控制管理器设置为在该事件中重新启动服务。

如果您需要某种用户交互性,您还可以创建一个与您的新服务对话并启动/停止它的Windows窗体应用程序。