WebClient.DownloadFileAsync - Download files one a

2019-01-14 14:03发布

I am using the code below to download multiple attachments from a TFS server:

foreach (Attachment a in wi.Attachments)
{    
    WebClient wc = new WebClient();
    wc.Credentials = (ICredentials)netCred;
    wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
    wc.DownloadFileAsync(a.Uri, "C:\\" + a.Name);
}

I would like to download multiple files using DownloadFileAsync, but I want them to be downloaded one by one.

One may ask "Why don't you just use the synchronous DownloadFile method?" Its because:

  1. I want to make use of the events provided by DownloadFileAsync.
  2. I don't want to make multiple instances of the Webclient to avoid flooding the server.

This is the solution that I thought of:

foreach (Attachment a in wi.Attachments)
{        
    WebClient wc = new WebClient();
    wc.Credentials = (ICredentials)netCred;
    wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
    wc.DownloadFileAsync(a.Uri, "C:\\" + a.Name);
    while (wc.IsBusy)
    {
        System.Threading.Thread.Sleep(1000);
    }
}

However, there are a couple of problems with this approach:

  1. The Thread.Sleep() is locking up my Form. I still need to make my own Thread or use BackgroundWorker. (I would like to avoid this as much as possible)
  2. The DownloadFileCompleted event is being triggered after ALL files has been downloaded. I don't know if this is a side-effect of using System.Threading.Thread.Sleep(1000);

Is there a better approach to download files one at a time using WebClient.DownloadFileAsync?

Thanks!

3条回答
Luminary・发光体
2楼-- · 2019-01-14 14:35

To simplify the task you can create separated attachment list:

list = new List<Attachment>(wi.Attachments);

where list is private field with type List<Attachment>. After this you should configure WebClient and start downloading of first file:

if (list.Count > 0) {
   WebClient wc = new WebClient();
   wc.Credentials = (ICredentials)netCred;
   wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
   wc.DownloadFileAsync(list[0].Uri, @"C:\" + list[0].Name);
}

Your DownloadFileComplete handler should check if not all files already downloaded and call DownloadFileAsync again:

void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
   // ... do something useful 
   list.RemoveAt(0);
   if (list.Count > 0)
      wc.DownloadFileAsync(list[0].Uri, @"C:\" + list[0].Name);
}

This code is not optimized solution. This is just idea.

查看更多
看我几分像从前
3楼-- · 2019-01-14 14:45

I think that should use Queue

查看更多
ら.Afraid
4楼-- · 2019-01-14 14:47

At the risk of sounding like an idiot, this worked for me:

Console.WriteLine("Downloading...");
client.DownloadFileAsync(new Uri(file.Value), filePath);
while (client.IsBusy)
{
    // run some stuff like checking download progress etc
}
Console.WriteLine("Done. {0}", filePath);

Where client is an instance of a WebClient object.

查看更多
登录 后发表回答