[英]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:避免異步無效。 無法判斷它們是否已執行。
這個:
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
是真實的,並使用該決定稱無論是ErrorLogger
或TestLogger
。 當然,任何地方都沒有async void
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.