我正在研究WinRT。如果抛出未处理的异常,我想将消息文本写入存储。 我在'App.xaml.cs'中添加了一个事件处理程序,请参阅代码。
捕获到异常,但写入文件的最后一行再次崩溃 - > '例外'!
为什么呢?有什么想法吗?
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.UnhandledException += App_UnhandledException;
}
async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file= await folder.CreateFileAsync("crash.log",CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, e.Message); // <----- crash again -----
}
谢谢
阳光
答案 0 :(得分:4)
我一直想知道同样的事情,并在我的搜索中很早就偶然发现了这一点。我已经找到了一种方法,希望这对其他人也有用。
问题是await
正在返回对UI线程的控制并且应用程序崩溃。你需要推迟,但没有真正的方法可以推迟。
我的解决方案是使用设置存储。我假设大多数人想要这样做想要做一些LittleWatson风格,所以这里有一些代码从http://blogs.msdn.com/b/andypennell/archive/2010/11/01/error-reporting-on-windows-phone-7.aspx修改为了您的方便:
namespace YourApp
{
using Windows.Storage;
using Windows.UI.Popups;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
public class LittleWatson
{
private const string settingname = "LittleWatsonDetails";
private const string email = "mailto:?to=you@example.com&subject=YourApp auto-generated problem report&body=";
private const string extra = "extra", message = "message", stacktrace = "stacktrace";
internal static void ReportException(Exception ex, string extraData)
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = extraData;
exceptionValues[message] = ex.Message;
exceptionValues[stacktrace] = ex.StackTrace;
}
internal async static Task CheckForPreviousException()
{
var container = ApplicationData.Current.LocalSettings.Containers;
try
{
var exceptionValues = container[settingname].Values;
string extraData = exceptionValues[extra] as string;
string messageData = exceptionValues[message] as string;
string stacktraceData = exceptionValues[stacktrace] as string;
var sb = new StringBuilder();
sb.AppendLine(extraData);
sb.AppendLine(messageData);
sb.AppendLine(stacktraceData);
string contents = sb.ToString();
SafeDeleteLog();
if (stacktraceData != null && stacktraceData.Length > 0)
{
var dialog = new MessageDialog("A problem occured the last time you ran this application. Would you like to report it so that we can fix the error?", "Error Report")
{
CancelCommandIndex = 1,
DefaultCommandIndex = 0
};
dialog.Commands.Add(new UICommand("Send", async delegate
{
var mailToSend = email.ToString();
mailToSend += contents;
var mailto = new Uri(mailToSend);
await Windows.System.Launcher.LaunchUriAsync(mailto);
}));
dialog.Commands.Add(new UICommand("Cancel"));
await dialog.ShowAsync();
}
}
catch (KeyNotFoundException)
{
// KeyNotFoundException will fire if we've not ever had crash data. No worries!
}
}
private static void SafeDeleteLog()
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = string.Empty;
exceptionValues[message] = string.Empty;
exceptionValues[stacktrace] = string.Empty;
}
}
}
要实现它,你需要像上面的链接那样做,但要确保数据在这里,以防网址出现故障:
App.xaml.cs
构造函数(在调用this.InitializeComponent()
之前):
this.UnhandledException += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
显然,如果你已经有一个UnhandledException方法,你可以在那里抛出对LittleWatson的调用。
如果您使用的是Windows 8.1,则还可以添加NavigationFailed调用。这需要在实际页面中(通常是MainPage.xaml.cs或首先打开的任何页面):
xx.xaml.cs
构造函数(任何给定页面):
rootFrame.NavigationFailed += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
最后,您需要询问用户是否要在重新打开应用时发送电子邮件。在你的应用程序的默认页面构造函数中(默认:页面App.xaml.cs初始化):
this.Loaded += async (s, e) => await LittleWatson.CheckForPreviousException();
如果已经使用过,请将调用添加到OnLoad方法中。
答案 1 :(得分:0)
在这种情况下,await
可以被松散地翻译为“在另一个线程上完成这项工作,并在等待它完成时继续你正在做的事情”。鉴于您的应用正在做的是崩溃,您可能不希望它继续这样做,直到您完成记录问题。在这种情况下,我建议同步运行文件IO。
答案 2 :(得分:0)
对于原始问题,这可能有点太迟了,但是......
正如@Hans Passant建议的那样,避免await
(即同步运行FileIO.AppendTextAsync()
),也被@Jon借调,我会选择这个,而不是的相对过重的代码LittleWatson 。由于应用程序处于某种错误处理状态(这应该是罕见的)我不会因同步(由于删除等待)而产生任何阻塞作为主要缺点。
将同步选项放在一边,以下await
实现对我有用:
将await FileIO.AppendTextAsync(file, e.Message);
更改为:
Task task = LogErrorMessage(file, e.Message)
task.Wait(2000); // adjust the ms value as appropriate
...
private async Task LogErrorMessage(StorageFile file, string errorMessage)
{
await FileIO.AppendTextAsync(file, errorMessage); // this shouldn't crash in App_UnhandledException as it did before
}