【问题标题】:how to wait for webclient OpenReadAsync to complete如何等待 webclient OpenReadAsync 完成
【发布时间】:2014-07-31 05:51:51
【问题描述】:

我正在使用 WebClient 在 Windows Phone 8.1 应用程序中从 Internet 下载一些东西。 下面是我在我的应用程序中使用的示例代码 - 我在其中调用下面的方法,但我的网络客户端没有等待完成读取操作并在 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;
    }
}

【问题讨论】:

  • 制作方法async。如果您不知道这意味着什么,请阅读 C# 中的 async 方法
  • 感谢@Alxandr 的回复,我确实尝试过使用 async/await 但行为相同。 OpenReadCompleted 事件在方法返回调用后完成。

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


【解决方案1】:

我建议您将 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 中找到出色的阅读材料,只需在搜索栏中按该标签进行过滤即可。

【讨论】:

  • 感谢回复,其实这个OpenReadTaskAsync()不在WindowsPhone平台上。
  • Salam,我认为您必须将“taskComplete”更改为“tcs.SetResult(...)”
  • @SayedAbolfazlFatemi 感谢您告诉我。编辑了我的答案。
  • 感谢扩展提示。
  • 天啊!!!这是我见过的最重要的 Silverlight 代码示例。这不仅适用于 REST 调用,也适用于 WCF 调用。到目前为止,我一直在使用没有 async/await 运算符的旧异步模型来调用 WCF/REST 方法。我们的代码到处都是可怕的事件处理程序,代码就像一个迷宫。这将极大地清理我们的代码。不过我应该提一下,为了使用它,我们必须添加 Microsoft.Bcl.Async NuGet 包。这是解决这个问题的另一个关键。
【解决方案2】:

我希望这不是太离题,但是其他正在研究这个的人可能想知道上面的代码示例也可以用于 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多