当C# Windows Store(Metro)应用程序崩溃时,我如何获取有用的信息(例如堆栈跟踪)?

25

我正在学习C#(以及.NET/Visual Studio),首先编写了一个简单的可移植库来完成拼图游戏,并为不同的目标平台编写UI。我从控制台UI开始,然后转向WPF应用程序。接着我尝试使用“Windows商店”,大部分代码都可以复制WPF代码,只需更改一些命名空间和方法签名。

但是某些事情的行为会有所不同,并且我在搜索了一个多小时之后才得到任何有关崩溃的信息。例如,如果我在传统的WPF应用程序中做出以下操作:

Storyboard.SetTargetProperty(animation, 
     new PropertyPath("{Canvas.MispelledProperty}"));

我在.NET异常发生的确切位置遇到了问题。如果我在Windows Store应用程序中犯同样的错误,我只能看到这个。
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
        UnhandledException += (sender, e) =>
        {
            if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
        };
#endif

(编辑:这是在名为App.g.i.cs的文件中。)
然后我必须仔细查看输出以找出
WinRT information: Cannot resolve TargetProperty (Canvas.MispelledProperty) on specified object.

在某些情况下这可能已经足够了,但我真的很难相信这就是你能得到的全部。我之前解决了一些与Storyboard工作方式中微妙差别相关的问题(例如直接附加到动画的完成事件没有像WPF中那样触发),但现在我完全不知道这个错误的原因:

A first chance exception of type 'System.ArgumentOutOfRangeException' occurred

这可能只是因为过度点击导致的,也会导致整个应用程序崩溃。

现在我的应用程序非常简单,这可能与我如何处理PointerPressedPointerReleased事件有关,但是没有更好的起点真的令人沮丧。

所以,我想实际问题是:它确实应该像这样吗?还是我可以配置调试器以给我更多有用的信息?如果不行,那么:当开发Windows Store应用程序时,你们使用什么样的调试技术或解决方法?

更新:

起初,我认为这只会发生在WinRT相关的异常之外,在CLR之外发生了异常,并且没有被正确包装,但事实证明,所有未处理的异常都会带您到App.g.i.cs而不是它们发生的地方。例如,我故意尝试在方法中访问一个列表超出其范围,以查看当引发异常时Visual Studio是否会将我带到那里,但是它又把我带回了App.g.i.cs。在本地变量中,我得到了这个Windows.UI.Xaml.UnhandledExceptionEventArgs,消息字符串中有一些类似堆栈跟踪的信息,但没有行号。以下是我的有意制造的错误示例:

System.ArgumentOutOfRangeException
   at System.ThrowHelper.ThrowArgumentOutOfRangeException()
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at StorePuzzle.PuzzleRenderer.HandleTileReleased(Object sender, PointerRoutedEventArgs e)

我希望Visual Studio可以立即将我带到引发异常的地方,而不是像“非商店应用”一样带我到App.g.i.cs。 现在,编译器预处理指令看起来像是我可以关闭它(#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION), 但是我查阅了谷歌,没有找到任何方法可以这样做。

这是声明式编程风格的必然结果。你只能调试代码,而不能调试声明。失败很丑陋,代码被埋在.NET框架代码中,因此你没有任何源代码可以查看,调用堆栈几乎没有任何与你自己的代码有关的信息。通过谷歌搜索“调试WPF数据绑定”来寻找调试技巧。 - Hans Passant
我不确定声明式是否是问题的主要原因,我也遇到了这个问题,但是WPF(也使用XAML)通常会带您到断点行,或者给出任何XAML问题的提示。 - Craig Brett
4个回答

4

当你知道要查找的特定异常类型时,调试代码中的异常很容易。

从菜单中选择Debug然后选择Exceptions(或使用快捷键Ctrl+DCtrl+E)。

搜索您的特定异常并检查thrown

调试器将会在引发异常的代码行处停止执行。

我通常将大多数异常都打开以便及早发现问题。

XAML中的错误是不同的,有时很难找到。


4

我自己也有一个非常相似的问题,关于获取堆栈跟踪和转储,我在这里提出了问题:如何从用C#编写的WinRT应用程序中获取崩溃日志和堆栈跟踪?

与Android相比,Microsoft使得从WinRT应用获取崩溃信息非常困难。 与Android不同,没有像logcat一样的内置日志,您可以通过简单的堆栈跟踪查看应用程序为什么崩溃。 Android向开发人员提供此功能,并且不要求他们编写任何代码!

对于WinRT应用,看起来我们都必须自己解决这个问题。如果您想记录所有异常,因为如果您不记录所有异常,记录异常有什么意义--看起来这将需要很多工作!

本文介绍了如何捕获XAML异常以便记录它们:

本文解释了为什么需要在异步事件回调中包装所有代码的try / catch:

这个库看起来是记录日志的不错选择,尽管它似乎有点重,因为它依赖于SQLite,如果有一个不需要数据库的轻量级选择,那可能更好。

更新:

Microsoft在Windows 8.1中宣布了一些新的日志记录功能,现在在此处发布文档:

http://msdn.microsoft.com/en-us/library/windows/apps/windows.foundation.diagnostics.loggingchannel


“+1”给https://github.com/mbrit/metrolog- 我们在我们的Windows Phone 8.1(WinRT)应用程序中使用它,它非常有帮助。 - Sevenate

1
关于 ArgumentOutOfRangeException: Visual Studio中的调试器有特殊选项用于不同类型的异常,您需要确保对于您的异常类型已经勾选了"抛出" (在您的情况下,可以选择所有公共语言运行时异常) http://msdn.microsoft.com/en-us/library/d14azbfh.aspx 关于WinRT: 对于WinRT,我想情况可能会有所不同。我不是WinRT的真正专家,但在我看来,Windows实际上与WPF以不同的方式处理XAML。Windows异步完成大部分工作(如生成控件、解析XAML等)。因此,您通常会从XAML中获取未处理的异常,而不是在尝试设置属性时获取异常。

-1

Locals in VS2012

如果您在Visual Studio 2012的“本地”窗格中查看,当调用异常时,您会注意到一个名为$exception的值。如果您深入了解它,您可以找到有关该问题的各种信息。

2
我没有得到任何名为 $exception 的东西。我只能看到 sendere 这两个参数,它们来自于 UnhandledException += (sender, e) => 中的 lambda 表达式。参数 e 的类型是 Windows.UI.Xaml.UnhandledExceptionEventArgs,而堆栈跟踪为 null。但是,UnhandledExceptionEventArgs 也有一个消息,该消息与异常中的消息相同,还包括引发异常的方法名称和签名。虽然我仍然无法得到行号,但这已经是一个开始了。 - Federico

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