4

私は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 -----
 }

ありがとう

サニー

4

3 に答える 3

4

私は同じことを考えていて、検索のかなり早い段階でこれに出くわしました。私は方法を考え出しました。うまくいけば、これは他の誰かにも役立つでしょう。

問題はawait、UI スレッドの制御が返され、アプリがクラッシュすることです。延期が必要ですが、それを取得する実際の方法はありません。

私の解決策は、代わりに設定ストレージを使用することです。これをやりたいと思っているほとんどの人は、LittleWatson スタイルの何かをしたいと思っていると思います。 -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;
        }
    }
}

それを実装するには、上記のリンクと同じことを行う必要がありますが、URL がダウンした場合に備えてデータがここにあることを確認する必要があります。

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");

最後に、アプリを再度開いたときに電子メールを送信するかどうかをユーザーに確認する必要があります。アプリの既定の Page のコンストラクター (既定: App.xaml.cs が初期化するページ) で:

this.Loaded += async (s, e) => await LittleWatson.CheckForPreviousException();

または、既に使用している場合は、OnLoad メソッドへの呼び出しを追加します。

于 2014-01-30T22:05:05.343 に答える
0

この状況でawaitは、大まかに「このジョブを別のスレッドで実行し、完了するのを待つ間、実行していたことを続行する」と言い換えることができます。アプリが行っていたことがcrashingであったことを考えると、おそらく、問題のログ記録が完了するまで、それを継続させたくないでしょう。この場合、ファイル IO を同期的に実行することをお勧めします。

于 2013-07-25T21:21:03.350 に答える