如何从用户机器获取有用的 WPF .NET 错误信息?

17

我有一个WPF应用程序,在安装了开发环境的机器上正常运行,但在没有开发环境的机器上却崩溃了——如果这是一个重复的问题,我可以关闭它,但我的搜索技能似乎找不到等价的问题。看起来我遇到了XamlParseException,但除此之外没有更有用的信息。我需要获得有用的信息。

浏览Windows 7事件日志会给我这个错误日志:

Fault bucket , type 0
Event Name: CLR20r3
Response: Not available
Cab Id: 0

Problem signature:
P1: MyApp.exe
P2: 1.0.0.0
P3: 4b88323d
P4: PresentationFramework
P5: 3.0.0.0
P6: 4a174fbc
P7: 624f
P8: e1
P9: System.Windows.Markup.XamlParse
P10: 

Attached files:
C:\Users\Mark\AppData\Local\Temp\WER7DC.tmp.WERInternalMetadata.xml

These files may be available here:
C:\Users\Mark\AppData\Local\Microsoft\Windows\WER\ReportArchive
 \AppCrash_generatortestbed_4fa7dff09a9e893eb675f488392571ced4ac8_04ef1100

Analysis symbol: 
Rechecking for solution: 0
Report Id: cd55060c-271f-11df-b6ff-001e52eefb8e
Report Status: 1
我已经检查了这些目录,第一个目录不存在,而第二个目录包含一个wer文件,其中只列出了加载的dlls。
我可以在我的测试机上安装开发环境,但这样它就不能作为测试机使用,我又回到了原点。我在安装开发环境时没有遇到此错误,因此我不知道如何获得详细和有用的错误消息。
编辑:在@Alastair Pitts下面的评论基础上,这是我填写异常处理的方式:
    private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
        Exception theException = e.Exception;
        string theErrorPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\GeneratorTestbedError.txt";
        using (System.IO.TextWriter theTextWriter = new System.IO.StreamWriter(theErrorPath, true)){
            DateTime theNow = DateTime.Now;
            theTextWriter.WriteLine("The error time: " + theNow.ToShortDateString() + " " + theNow.ToShortTimeString());
            while (theException != null) {
                theTextWriter.WriteLine("Exception: " + theException.ToString());
                theException = theException.InnerException;
            }
        }
        MessageBox.Show("The program crashed.  A stack trace can be found at:\n" + theErrorPath);
        e.Handled = true;
        Application.Current.Shutdown();
    }

希望这样我能得到我所需要的东西。感谢您的帮助!

4个回答

15

我将使用以下方法来处理应用程序域中的 UnhandledException 事件

一旦您这样做了,您就有多种选择。将异常记录到文件中,序列化以供以后检查,显示带有异常消息的对话框。

编辑:XamlParseException发生在创建主窗口时。这意味着正在调用该窗口的构造函数。如果在该构造函数中执行任何逻辑,则任何导致的异常都会抛出一个XamlParseException。据我了解,UnhandledException处理程序仍将捕获此异常。

要在 WPF 中连接 UnhandledException 事件,请在 app.xaml 中添加事件连接。

<Application 
   x:Class="DispatcherUnhandledExceptionSample.App"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   StartupUri="MainWindow.xaml"     
   DispatcherUnhandledException="App_DispatcherUnhandledException" />

然后在您的app.cs中添加一个方法。

public partial class App : Application
{
    void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        // Process unhandled exception do stuff below

        // Prevent default unhandled exception processing
        e.Handled = true;
    }
}

MSDN


如果是XamlParseError,似乎会在我使用任何代码之前就出现错误,只是在应用程序窗口的绘制中。有没有办法在调用用户代码之前跟踪此异常?或者我对XamlParseErrors的理解是错误的? - mmr

2
除了拥有记录堆栈跟踪的未处理异常事件处理程序外,查看在重现机器上生成的崩溃转储也非常有用。您提到它是Windows 7,因此可以通过以下方式查找相应的崩溃转储:
1. 控制面板->所有控制面板项目->操作中心->“查看要报告的问题”链接,在维护/“检查未报告问题的解决方案”区域下方。这将显示已崩溃的应用程序列表,您可以深入了解它们以查找转储文件和信息。在问题技术详细信息的左下角寻找“查看这些文件的临时副本”链接。这将提取转储文件并在资源管理器窗口中显示它们。
2. cd /d %ProgramData%\Microsoft\Windows\WER。
WER似乎将其崩溃转储保存在该目录下,因此我会使用dir /s/b命令来查找我知道应用程序名称一部分的内容。例如,我创建了一个故意崩溃的应用程序,名为crashyapp.exe:
C:\ProgramData\Microsoft\Windows\WER>dir /s/b *crashy* C:\ProgramData\Microsoft\Windows\WER\ReportQueue\AppCrash_crashyapp.exe_56f8d710d72e31d822d6b895c5c43a18d34acfa1_cab_2823e614
该目录包含崩溃的hdmp和mdmp文件。现在是时候附加调试器了!

有趣的想法。我已经离开了这个公司,所以无法解决这个问题,但我可以把它转达给一些仍在苦苦挣扎的朋友。似乎WPF错误几乎总是XamlParseExceptions,因此除此之外的任何信息都是有帮助的。 - mmr

1

异常日志记录(如Alastair Pitts的答案所述)有助于缩小错误源。

第P9行出现XamlParse表明可能存在问题,即无法从XAML描述中初始化控件或窗口。 XAML引用的程序集在目标计算机上未找到,或与XAML中的签名不匹配。

编辑:

XAML解析发生在InitializeComponent()中,该方法在窗口或控件的构造函数中调用。


0

除了Alistair的回答外,正是InnerException给了我寻找答案所需的线索:

public partial class App : Application {
    void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) {
        Exception ex = e.Exception;
        Exception ex_inner = ex.InnerException;
        string msg = ex.Message + "\n\n" + ex.StackTrace + "\n\n" +
            "Inner Exception:\n" + ex_inner.Message + "\n\n" + ex_inner.StackTrace + "\n\n" + 
            Utils.RegistryVersion();
        MessageBox.Show(msg, "Drop Print Batch Application Halted!", MessageBoxButton.OK);
        Utils.MailReport(msg);
        e.Handled = true;
        Application.Current.Shutdown();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接