异步方法并不总是在 Windows Phone 8 应用上执行
本文关键字:Phone 应用 执行 Windows 异步方法 | 更新日期: 2023-09-27 18:35:15
我正在开发一个需要在一台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();
}
这是测试执行器:
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);
}
}
}
这是测试记录器:
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);
}
}
}
我做错了什么?
不确定,但我认为您在使用 async/await 时违反了规则 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);
}
}
我已经重写了部分项目以避免事件处理程序并删除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
检查OAuthResult
的IsError
属性是否为真,并使用它来决定调用ErrorLogger
或TestLogger
。当然,任何地方都没有async void
。