异步下载多个文件并等待它们全部完成后再执行其余代码

23

我正试图从互联网上下载多个文件,并等待它们全部完成。这是我正在运行的C#控制台应用程序,因此不需要进度条事件处理程序。然而,尽管并未下载所有文件,它目前仍在继续执行代码。

  • 1.正在下载所有文件!
  • 2.已完成文件A的下载
  • 3.已完成下载所有文件!
  • 4.已完成文件B的下载
  • 5.已完成文件C的下载

您应该如何等待直到所有异步下载文件都完成。

 private void DownloadMultipleFiles(List<DocumentObject> doclist)
    {
        foreach(var value in doclist){
            try
            {
                using (WebClient webClient = new WebClient())
                {
                    string downloadToDirectory = @Resources.defaultDirectory + value.docName;
                    webClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                    webClient.DownloadFileCompleted += client_DownloadFileCompleted;
                    webClient.DownloadFileAsync(new Uri(value.docUrl), @downloadToDirectory);

                    //Add them to the local
                    Context.listOfLocalDirectories.Add(downloadToDirectory);
                }         
            }
            catch (Exception)
            {
                Errors.printError("Failed to download File: " + value.docName);
            }
        }
    }
1个回答

53

WebClientDownloadFileAsync/DownloadFileCompleted成员使用事件驱动异步模式。如果你想使用asyncawait,应该使用基于任务的异步模式

在这种情况下,你应该使用DownloadFileTaskAsync成员,代码如下:

private async Task DownloadFileAsync(DocumentObject doc)
{
  try
  {
    using (WebClient webClient = new WebClient())
    {
      string downloadToDirectory = @Resources.defaultDirectory + doc.docName;
      webClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
      await webClient.DownloadFileTaskAsync(new Uri(doc.docUrl), @downloadToDirectory);

      //Add them to the local
      Context.listOfLocalDirectories.Add(downloadToDirectory);
    }         
  }
  catch (Exception)
  {
    Errors.printError("Failed to download File: " + doc.docName);
  }
}

private async Task DownloadMultipleFilesAsync(List<DocumentObject> doclist)
{
  await Task.WhenAll(doclist.Select(doc => DownloadFileAsync(doc)));
}

请注意,您的Context.listOfLocalDirectories.AddErrors.printError方法应该是线程安全的。

谢谢你提醒我。我确保了我的localDirectories是线程安全的,并添加了自己的完成事件处理程序。感谢你的所有帮助。这也帮助我理解了其他异步任务的问题。 - user2100493
这是自4.5版本以来可用的。 - Natxo
1
如果尝试下载的URL返回404 Not Found,那么异常“failed to download file”会被抛出吗? - Mike Upjohn
1
@MikeUpjohn:我相信是这样的。WebClient会针对任何非成功响应代码引发异常。 - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接