簡體   English   中英

異步方法並非總是在Windows Phone 8應用程序上執行

[英]Asynchronous methods aren't always executed on Windows Phone 8 app

我正在開發需要在一個Windows Phone 8設備上運行的應用程序。 該應用程序需要連接到多個URL並記錄每次連接嘗試的結果:響應的大小和整個請求響應所花費的時間。 它通常可以正常工作,但是我無法使異步方法發揮出色:並非所有嘗試都被記錄下來。 通常,最后一個測試沒有記錄下來,對我來說好像沒有調用相關方法。

這是我的MainViewModel中的相關代碼:

private readonly BackgroundWorker backgroundWorker;

public MainViewModel()
{
    backgroundWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = false };
    backgroundWorker.DoWork += BackgroundWorkerDoWork;
    backgroundWorker.ProgressChanged += BackgroundWorkerProgressChanged;
    backgroundWorker.RunWorkerCompleted += BackgroundWorkerRunCompleted;
}

private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs args)
{
    var worker = sender as BackgroundWorker;
    if (worker == null) return;

    var testItems = new TestItemListCreator().Execute(NetworkType);
    var total = testItems.Count;

    var count = 0;
    foreach (var testItem in testItems)
    {
        count++;
        // because otherwise the logging fails
        Thread.Sleep(TimeSpan.FromSeconds(2)); 
        new TestExecutor().RunTest(testItem);
        worker.ReportProgress((count * 100) / total);
    }
}

private void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs args)
{
    ProgressPercent = args.ProgressPercentage;
}

private void BackgroundWorkerRunCompleted(object sender, RunWorkerCompletedEventArgs args)
{
    if (args.Error == null)
    {
        Message = "Done!";
    }
    else
    {
        Message = "Error: " + args.Error.Message;
    }
}

private void ExecuteRunTests()
{
    Message = "Please wait...";
    ProgressPercent = 0;

    if (backgroundWorker.IsBusy) return;

    CanExecuteRunTests = false;
    backgroundWorker.RunWorkerAsync();
}

這是TestExecutor:

public class TestExecutor
{
    private readonly OAuthGetRequestExecutor oAuthGetRequestExecutor;

    public TestExecutor()
    {
        oAuthGetRequestExecutor = new OAuthGetRequestExecutor();
    }

    public void RunTest(TestItem testItem)
    {
        oAuthGetRequestExecutor.PerformGetRequest(testItem, RequestFinished);
    }

    private void RequestFinished(object sender, OAuthEventArgs eventArgs)
    {
        if (eventArgs.IsError)
        {
            ErrorLogger.Log(eventArgs.ErrorMessage);
        }
        else
        {
            TestLogger.Log(eventArgs.TestItem);
        }
    }
}

這是TestLogger:

internal class TestLogger
{
    private const string Separator = ";";

    public static async void Log(TestItem testItem)
    {
        await CsvFileAssistant.WriteToFile(string.Join(Separator, GetLine(testItem)) + Environment.NewLine);
    }

    private static IEnumerable<object> GetLine(TestItem testItem)
    {
        return new List<object>
        {
            testItem.DateTime,
            testItem.NetworkCategory,
            testItem.NetworkType,
            testItem.TestName,
            testItem.TestResult.Sent,
            testItem.TestResult.Received,
            testItem.TestResult.Time
        };
    }
}

這是CsvFileAssistant:

internal class CsvFileAssistant
{
    private static readonly StorageFolder DefaultFolder = ApplicationData.Current.LocalFolder;
    private const string FolderName = "Data";
    private const string FileName = "Tests.csv";

    public static async Task WriteToFile(string text)
    {
        var dataFolder = await DefaultFolder.CreateFolderAsync(FolderName, CreationCollisionOption.OpenIfExists);

        var file = await dataFolder.CreateFileAsync(FileName, CreationCollisionOption.OpenIfExists);

        using (var s = await file.OpenStreamForWriteAsync())
        {
            var fileBytes = Encoding.UTF8.GetBytes(text.ToCharArray());
            s.Seek(0, SeekOrigin.End);
            s.Write(fileBytes, 0, fileBytes.Length);
        }
    }
}

我究竟做錯了什么?

不確定,但是我認為您在使用異步/等待時違反了規則1:避免異步無效。 無法判斷它們是否已執行。

http://haacked.com/archive/2014/11/11/async-void-methods/

這個:

TestLogger.Log(eventArgs.TestItem);

不需要等待,因為您是通過同步方法執行此操作的。 一旦不使用await ,您將簡單地使用“即發即棄”機制,這不能保證您的方法能夠正常完成。

您正在將基於事件的異步模式與新的任務異步模式混合。 我建議您使用其中之一,但不要一起使用。

除了事件處理程序,您不應該使用async void ,這是您的情況:

private async void RequestFinished(object sender, OAuthEventArgs eventArgs)
{
    if (eventArgs.IsError)
    {
        ErrorLogger.Log(eventArgs.ErrorMessage);
    }
    else
    {
        await TestLogger.Log(eventArgs.TestItem);
    }
}

我重寫了項目的一部分,以避免使用EventHandler並刪除BackgroundWorker。

這是MainViewModel:

private readonly IProgress<int> progress;

public MainViewModel()
{
    progress = new Progress<int>(value =>
    {
        ProgressPercent = value;
    });
}

private async void ExecuteRunTests()
{
    ProgressPercent = 0;

    var testItems = new TestItemListCreator().Execute(NetworkType);
    var total = testItems.Count;

    var count = 0;
    foreach (var testItem in testItems)
    {
        count++;

        var result = await new OAuthGetRequestExecutor().PerformGetRequest(testItem);
        await ResultLogger.Log(result);

        var percent = (count * 100) / total;
        progress.Report(percent);
    }
}

ResultLogger檢查是否IsError的財產OAuthResult是真實的,並使用該決定稱無論是ErrorLoggerTestLogger 當然,任何地方都沒有async void

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM