在Windows Phone 8.1 Runtime App中处理错误

在Windows Phone中处理错误其实没有什么特殊之处,不外乎是try…catch…而且Windows Phone SDK一开始在支持应用级别触发UnhandledException事件,开发者可以利用这一事件来处理漏网的异常,从而阻止类似应用崩溃这样的不良体验。

开发者通常会在该事件中将异常信息组织成文本,然后提示用户发送错误报告。然而在Windows Phone 8.1新引入的Runtime SDK中,奇怪的事情发生了……

在进行调试时,未捕获的异常也会触发UnhandledException事件,此时你可以通过参数e(UnhandledExceptionEventArgs类型)的Exception属性来获取这个异常,你可以看到该异常的Message,也可以看到StackTrace,这一点非常重要,没有它你很难确定错误具体发生在哪里。

Visual Studio的调试功能非常棒,你可以随意查看当前代码位置的各种变量信息,但是如果你想再看一次那个异常,你就会惊讶的发现,它的StackTrace消失了,变成了一个尴尬的null。

这并不是Visual Studio的问题,如果你的应用在运行时(而非调试时)触发了UnhandledException,你的代码也无法拿到相关异常的StackTrace。所以我只能说这应当是一个Bug。

解决办法是尽量摆脱对UnhandledException事件中的e.Exeption的依赖,比如在App类中设置一个静态的Exception对象和用来抛出异常的工具方法:

static Exception MonsterException { get; set; }

internal static void ThrowException(string message, Exception e)
{
App.MonsterException = new Exception(message, e);
throw App.MonsterException;
}

那么在UnhandledException事件中,就可以优先考虑使用MonsterException:

void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (MonsterException == null)
MonsterException = e.Exception;
//....
}

将可能发生异常的代码段置于try..catch…块中,在catch块中调用ThrowException来重新包装并抛出异常:

App.ThrowException("error comment", ex);

ThrowException的方法接收一个异常描述,并且会把它和传入的异常重新包装再交给UnhandledException,你可以通过该异常描述参数来传递一些有助于排查问题的信息,比如错误发生时代码正在尝试做的事情。

尤其是在Runtime SDK将许多API都设计成了异步执行,带来的副作用就是异常的StackTrace基本无法解读,比如下面这种:

at PicturePicker.<btnSave_Click>d__8.MoveNext()
—End of stack trace from previous location where exception was thrown—
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__3(Object state)
at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()

简单的解决方案就是准备一个用来记录当前步骤的字符串变量,每次执行(可能出错的)新方法之前,给该变量赋值来体现下一个步骤,这样,在出错后调用ThrowException时,就可以把这个步骤信息传递出去了。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注