异步方法并不总是在 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);
        }
    }
}

我做错了什么?

异步方法并不总是在 Windows Phone 8 应用上执行

不确定,但我认为您在使用 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检查OAuthResultIsError属性是否为真,并使用它来决定调用ErrorLoggerTestLogger。当然,任何地方都没有async void