控制台应用程序中的.NET Global异常处理
问题:我想在控制台应用程序中为未处理的异常定义全局异常处理程序。 在asp.net中,可以在global.asax中定义一个,而在windows应用程序/服务中,可以定义如下
AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
但是我怎样才能定义一个控制台应用程序的全局异常处理程序?
currentDomain似乎不工作(.NET 2.0)?
编辑:
啊,愚蠢的错误。
在VB.NET中,需要在currentDomain前添加“AddHandler”关键字,否则在IntelliSense中不会看到UnhandledException事件。
这是因为VB.NET和C#编译器不同地处理事件处理。
不,这是正确的方法。 这工作完全按照它应该的,也许你可以从事的工作:
using System; class Program { static void Main(string[] args) { System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper; throw new Exception("Kaboom"); } static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) { Console.WriteLine(e.ExceptionObject.ToString()); Console.WriteLine("Press Enter to continue"); Console.ReadLine(); Environment.Exit(1); } }
请记住,您无法通过这种方式捕捉由抖动产生的类型和文件加载异常。 它们在您的Main()方法开始运行之前发生。 捕捉这些需要延迟抖动,将有风险的代码移动到另一个方法,并应用[MethodImpl(MethodImplOptions.NoInlining)]属性。
如果您有单线程应用程序,则可以在Main函数中使用简单的try / catch,但是,这不包括可能在其他线程上抛出Main函数以外的异常(例如注释)。 此代码演示了即使您尝试在Main中处理该异常也会导致应用程序终止的情况(请注意,如果您按下Enter键并允许应用程序在发生异常之前正常退出,程序将正常退出,但是如果让它运行,它相当不幸地终止):
static bool exiting = false; static void Main(string[] args) { try { System.Threading.Thread demo = new System.Threading.Thread(DemoThread); demo.Start(); Console.ReadLine(); exiting = true; } catch (Exception ex) { Console.WriteLine("Caught an exception"); } } static void DemoThread() { for(int i = 5; i >= 0; i--) { Console.Write("24/{0} =", i); Console.Out.Flush(); Console.WriteLine("{0}", 24 / i); System.Threading.Thread.Sleep(1000); if (exiting) return; } }
您可以收到另一个线程在应用程序退出之前何时抛出异常以执行某些清理的通知,但据我所知,不能从控制台应用程序强制应用程序继续运行(如果不处理该异常在它的引发线程上没有使用一些模糊的兼容性选项来使应用程序像.NET 1.x一样。 这段代码演示了如何通知主线程来自其他线程的异常,但仍然不愉快地终止:
static bool exiting = false; static void Main(string[] args) { try { System.Threading.Thread demo = new System.Threading.Thread(DemoThread); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); demo.Start(); Console.ReadLine(); exiting = true; } catch (Exception ex) { Console.WriteLine("Caught an exception"); } } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Console.WriteLine("Notified of a thread exception... application is terminating."); } static void DemoThread() { for(int i = 5; i >= 0; i--) { Console.Write("24/{0} =", i); Console.Out.Flush(); Console.WriteLine("{0}", 24 / i); System.Threading.Thread.Sleep(1000); if (exiting) return; } }
所以在我看来, 在控制台应用程序中处理它的最简单方法是确保每个线程在根级别都有一个异常处理程序:
static bool exiting = false; static void Main(string[] args) { try { System.Threading.Thread demo = new System.Threading.Thread(DemoThread); demo.Start(); Console.ReadLine(); exiting = true; } catch (Exception ex) { Console.WriteLine("Caught an exception"); } } static void DemoThread() { try { for (int i = 5; i >= 0; i--) { Console.Write("24/{0} =", i); Console.Out.Flush(); Console.WriteLine("{0}", 24 / i); System.Threading.Thread.Sleep(1000); if (exiting) return; } } catch (Exception ex) { Console.WriteLine("Caught an exception on the other thread"); } }
您还需要处理线程的异常:
static void Main(string[] args) { Application.ThreadException += MYThreadHandler; } private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e) { Console.WriteLine(e.Exception.StackTrace); }
哎呀,对不起,这是winform,任何你使用的控制台应用程序中的线程,你将不得不在try / catch块。 后台线程遇到未处理的异常不会导致应用程序结束。
你正在尝试应该根据MSDN文档的.Net 2.0工作。 您也可以尝试在您的控制台应用程序的入口处进行尝试/抓取。
static void Main(string[] args) { try { // Start Working } catch (Exception ex) { // Output/Log Exception } finally { // Clean Up If Needed } }
现在你的catch将会处理任何没有被捕获的东西( 在主线程中 )。 它可以是优雅的,甚至可以重新启动,如果你想,或者你可以让应用程序死亡,并记录异常。 如果你想做任何清理工作,你最好添加一个。 每个线程都需要自己的高级异常处理,类似于main。
编辑澄清BlueMonkMN所指出的关于线程的观点,并在他的回答中详细显示。