简体   繁体   English

抑制 Application.ThreadException 和 AppDomain.CurrentDomain.UnhandledException

[英]Suppressing Application.ThreadException and AppDomain.CurrentDomain.UnhandledException

I have written a WinForms application which performs some sort of syncing work.我编写了一个执行某种同步工作的 WinForms 应用程序。 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:对于未捕获的异常,我在Main()线程中为Application.ThreadExceptionAppDomain.CurrentDomain.UnhandledException添加了异常处理Application.ThreadException

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.我保持我的应用程序运行以进行测试,并意识到每当Application.ThreadException被捕获时,应用程序都会正确记录字符串Fatal Windows Forms Error ,然后是异常堆栈跟踪,然后应用程序退出。

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). UI 线程中发生的异常并不那么严重,因为在应用程序的其他/非 UI 线程中也发生了相同的异常,但它并没有使应用程序崩溃(正如我在日志中看到的那样)。 However when the same exception occurs in the UI thread, the app crashes.但是,当 UI 线程中发生相同的异常时,应用程序会崩溃。

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 )由于它是 Windows 窗体应用程序 Application.ThreadException 用于未处理的异常:“此事件允许您的 Windows 窗体应用程序处理 Windows 窗体线程中发生的其他未处理的异常。将您的事件处理程序附加到 ThreadException 事件以处理这些异常”( MSDN )

I think you must expect such behavior as at UIThreadExceptionHandler you have Application.Exit(new CancelEventArgs(true)).我认为你必须期待这样的行为,比如在 UIThreadExceptionHandler 你有 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. AppDomain.CurrentDomain.UnhandledException 事件用于处理非 UI 线程异常。

EDIT 1:编辑 1:

AppDomain.CurrentDomain.UnhandledException is specifically designed to log an exception before the system will inform a user and terminates the process. AppDomain.CurrentDomain.UnhandledException专门用于在系统通知用户并终止进程之前记录异常。 You can not prevent terminating the process (unless you are using Net 1.1).您无法阻止终止进程(除非您使用的是 Net 1.1)。

Application.ThreadException + UnhandledExceptionMode.CatchException allows you to keep your UI thread alive. Application.ThreadException + UnhandledExceptionMode.CatchException允许您保持 UI 线程处于活动状态。 But, it's really not a great idea.但是,这真的不是一个好主意。 It's much better to enclose error prone code in try-catch blocks instead.最好将容易出错的代码包含在 try-catch 块中。

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.因此,如果您想捕获来自线程的异常并使应用程序保持活动状态,则必须使用 try-catch 块在内部进行。

You haven't issue with UnhandledExceptionHandler, because it's not fired at all, I suppose.你对 UnhandledExceptionHandler 没有问题,因为我想它根本没有被触发。

Windows Forms isn't really designed for a scenario where an application needs to run indefinitely. Windows 窗体并不是真正为应用程序需要无限期运行的场景而设计的。 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).我认为更好的方法是使用具有两个线程的 Windows 服务:一个前台监视器线程和一个后台工作线程(使用 BackgroundWorker 类型)。 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.如果情况严重到监视器线程也死掉(例如 OutOfMemoryException 或 ExecutionEngineException),那么服务本身就会死掉。 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.如果您需要某种用户交互,您还可以创建一个 Windows 窗体应用程序来与您的新服务对话并启动/停止它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Application.ThreadException 和 AppDomain.CurrentDomain.UnhandledException 都不受尊重 - Neither Application.ThreadException nor AppDomain.CurrentDomain.UnhandledException are respected 通过Application.ThreadException和AppDomain.CurrentDomain.UnhandledException的异常 - Exception getting past Application.ThreadException and AppDomain.CurrentDomain.UnhandledException Application.ThreadException 和 AppDomain.CurrentDomain.UnhandledException 有什么区别? - What's the difference between Application.ThreadException and AppDomain.CurrentDomain.UnhandledException? Application.ThreadException 与 AppDomain.UnhandledException - Application.ThreadException vs AppDomain.UnhandledException AppDomain.CurrentDomain.UnhandledException不起作用 - AppDomain.CurrentDomain.UnhandledException Not working 控制台应用程序未在 AppDomain.CurrentDomain.UnhandledException 中使用 NLOG 记录错误 - Console application not logging error with NLOG in AppDomain.CurrentDomain.UnhandledException 不会调用AppDomain.CurrentDomain.UnhandledException - AppDomain.CurrentDomain.UnhandledException does not get called 处理AppDomain.CurrentDomain.UnhandledException中的异常 - Handle exceptions in AppDomain.CurrentDomain.UnhandledException Revit Addin中的AppDomain.CurrentDomain.UnhandledException - AppDomain.CurrentDomain.UnhandledException in Revit Addin 在Windows服务中处理AppDomain.CurrentDomain.UnhandledException - Handling AppDomain.CurrentDomain.UnhandledException in windows service
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM