如何等待webclient OpenReadAsync完成

时间:2014-07-31 05:51:52

标签: c# windows-phone-8.1 async-await task-parallel-library webclient

我正在使用WebClient从Windows Phone 8.1应用程序中下载一些来自互联网的东西。 下面是我在我的应用程序中使用的示例代码 - 我在下面调用方法,但我的webclient没有等待完成读取操作并在OpenReadAsync调用后立即返回。

如何确保我的方法返回操作必须等到OpenReadCompleted事件完成后? 我见过多个类似的问题,但找不到解决方案。

MyCustomObject externalObj;  // my custom object

private static void CheckNetworkFile()
{
    try
    {
        WebClient webClient = new WebClient();
        webClient.OpenReadCompleted += (s, e) =>
        {
          externalObj = myReadWebclientResponse(e.Result); // my custom method to read the response
        };

        webClient.OpenReadAsync(new Uri("http://externalURl.com/sample.xml", UriKind.Absolute));                
    }
    catch (Exception)
    {
      externalObj = null;
    }
}

2 个答案:

答案 0 :(得分:11)

我建议您将WebClient.OpenReadTaskAsync与.NET 4.5中引入的async/await关键字组合使用。您需要在方法中添加async关键字,使其返回Task,并建议使用Async后缀结束您的方法:

MyCustomObject externalObj;

private static async Task CheckNetworkFileAsync()
{
    try
    {
        WebClient webClient = new WebClient();

        Stream stream = await webClient.OpenReadTaskAsync(new Uri("http://externalURl.com/sample.xml", UriKind.Absolute));                
        externalObj = myReadWebclientResponse(stream);
    }
    catch (Exception)
    {
      externalObj = null;
    }
}

修改

如你所说,WebClient.OpenReadTaskAsync不适用于WP8.1,所以我们创建一个扩展方法,它将是:

public static class WebClientExtensions 
{
    public static Task<Stream> OpenReadTaskAsync(this WebClient client, Uri uri)
    {
       var tcs = new TaskCompletionSource<Stream>();

       OpenReadCompletedEventHandler openReadEventHandler = null;
       openReadEventHandler = (sender, args) => 
       {
          try 
          {
             tcs.SetResult(args.Result);
          } 
          catch (Exception e)
          {
             tcs.SetException(e);
          }
       };

       client.OpenReadCompleted += openReadEventHandler;
       client.OpenReadAsync(uri);

       return tcs.Task;
    }
}

现在,您可以在WebClient上使用它。

您可以在async-await wiki中找到精彩的阅读材料,只需在搜索栏中按该标记进行过滤即可。

答案 1 :(得分:0)

我希望这不是太偏离主题,但正在研究这个问题的其他人可能想知道上面的代码示例也可以用于Silverlight中的WCF调用。请务必先添加Microsoft.Bcl.Async NuGet包。这是一个WCF代码示例:

  public static async Task<string> AuthenticateAsync(string userName, string password)
    {
        var dataAccessServiceClient = new DataAccessServiceClient("DataAccessService");

        var taskCompletionSource = new TaskCompletionSource<string>();

        EventHandler<AuthenticateCompletedEventArgs> completedHandler = null;
        completedHandler = (s, args) =>
        {
            try
            {
                taskCompletionSource.SetResult(args.Result);
            }
            catch (Exception e)
            {
                taskCompletionSource.SetException(e);
            }
        };

        dataAccessServiceClient.AuthenticateCompleted += completedHandler;
        dataAccessServiceClient.AuthenticateAsync(userName, password);

        return await taskCompletionSource.Task;
    }

可以像这样调用:

var result = await AuthenticateAsync(username, password);