【问题标题】:C# unhandled exception handler, attempting to write to log fileC# 未处理的异常处理程序,试图写入日志文件
【发布时间】:2011-08-08 06:49:23
【问题描述】:

我的应用程序是 Windows Forms .NET 4 C# TCP/IP 服务器。它每天大约会崩溃一次,并显示一条通用的 Windows Server 崩溃消息(按关闭以关闭此应用程序)。我插入了以下代码以捕获可能导致此问题的任何异常,并将一个简单的 null 对象插入到定期调用以生成测试异常的例程中。

两件事:

  1. 发生测试异常时,在调试器中命中日志代码,创建并写入文件,一切正常。
  2. 如果没有调试器,我会收到“继续或退出”.NET 堆栈跟踪消息,无论我选择哪个,都不会创建或写入文件。

.NET 消息对我来说毫无用处。我需要崩溃的日志文件堆栈跟踪。有谁知道我该怎么做?谢谢。

static class Program
{
    [STAThread]
    static void Main(string[] rgszArgs)
    {
        //My exception handler
        AppDomain.CurrentDomain.UnhandledException +=
            new UnhandledExceptionEventHandler(CatchUnhandledException);

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FormMain(rgszArgs));
    }

    static void CatchUnhandledException
        (object sender, UnhandledExceptionEventArgs e)
    {
        StreamWriter sw;
        DateTime dtLogFileCreated = DateTime.Now;
        Exception ex;

        try
        {
            sw = new StreamWriter("crash-" + dtLogFileCreated.Day + dtLogFileCreated.Month
                        + dtLogFileCreated.Year + "-" + dtLogFileCreated.Second
                        + dtLogFileCreated.Minute + dtLogFileCreated.Hour + ".txt");

            ex = (Exception)e.ExceptionObject;

            sw.WriteLine("### Server Crash ###");
            sw.WriteLine(ex.Message + ex.StackTrace);
            sw.Close();
        }
        finally
        {
            Application.Exit();
        }
    }
}

【问题讨论】:

  • 只是挑剔,但我会将您的 streamwriter.close() 调用放入 finally 或在 using 块中使用 SW。

标签: c# .net logging exception-handling


【解决方案1】:

这是来自 AppDomain.UnhandledException Event 上的 MSDN:

从 .NET Framework 版本 4 开始,对于破坏进程状态的异常(例如堆栈溢出或访问冲突)不会引发此事件,除非事件处理程序是安全关键的并且具有 HandleProcessCorruptedStateExceptionsAttribute 属性。

会是这样吗?

【讨论】:

  • 我不这么认为...我插入了一个不应该被视为安全关键的非常简单的异常。
【解决方案2】:

我猜这是 AppDomain.UnhandledException 事件的事件处理程序。您绝对不能做的一件事是调用 Application.Exit(),程序不再处于正确关闭的正确状态,您必须调用 Environment.Exit()。 Application.Exit() 调用很可能是“继续或退出”消息的来源,这听起来像是 Winforms 应用程序显示的 ThreadExceptionDialog 在 UI 线程中遭受了一次壁炉攻击。

下一个问题是传递给 StreamWriter 构造函数的参数。您没有为文件指定完整路径名(如 c:\mumble\foo.txt),它可能会尝试将文件写入您没有写入权限的目录。很有可能在 Vista 或 Win7 上。或者文件实际上已经写好了,但是你找不到它,因为你不知道去哪里找。

使用 Environment.GetFolderPath() 选择您知道可以写入的目录。

【讨论】:

  • 或者使用事件日志。它是为这种情况而设计的。
  • @tomfanning 抱歉,我现在添加了完整的课程。显然遗漏了一条重要信息。
【解决方案3】:

如果您的程序状态如此混乱以至于 try/finally 块中的任何代码都会损坏您的程序,您也可以尝试调用 Environment.FailFast("reason for failure here")。这将自动写入事件日志。

【讨论】:

    【解决方案4】:

    您想要Application.ThreadException 事件。

    AppDomain 未处理异常事件捕获抛出的未处理异常 - 例如,Main 方法抛出的任何异常,但是 Application.Run 在内部处理异常 - 这意味着 Application.Run 不会因为事件处理程序中的异常,因此永远不会运行 CatchUnhandledException

    这意味着如果ThreadException 处理程序能够从异常中恢复,则应用程序将继续正常运行(如果Application.Run 抛出异常,则没有恢复的机会)。 由于我不明白调试时这种行为不同的原因。。调试时,此行为会发生更改,以便引发异常,从而允许您立即在 Visual Studio 中调试异常 - 这就是您的未处理异常处理程序在调试时工作的原因。

    请注意,上述CatchUnhandledException 处理程序捕获应用程序域中后台线程抛出的异常。

    另见Application.SetUnhandledExceptionMode

    【讨论】:

    • 工作完美,感谢您为我指明正确的方向。
    猜你喜欢
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多