I had previously asked this question on SO. The answer pointed me towards using the task parallel library for multiple parallel downloads. I'm not actually utilizing this exact code, but it got me to rethink my design.
The one open issue that wasn't really addressed (and I didn't ask it), cancelling the a local WebClient
. It isn't as simple as just calling WebClient.CancelASync();
since the scope of WebClient
is long gone by the time you need to cancel.
This isn't my code or even how I am approaching the problem, but just part of the test example I put together to see how this works. It seems to work, although it means having to wait for an event callback before the cancel is called. So I was wondering if there was another alternative.
private bool pendingCancel = false;
private Queue<Uri> queue = LoadQueue();
public void ASyncDownload()
{
if (queue.Count == 0) return;
var uri = queue.Dequeue();
WebClient client = new WebClient();
client.DownloadProgressChanged
+= (sender, e) =>
{
if (pendingCancellation)
{
((WebClient)sender).CancelAsync();
return;
}
//do something to report progress
};
client.DownloadDataCompleted
+= (sender, e) =>
{
if (!e.Cancelled || pendingCancel)
{
if (e.Error == null)
{
// do something with e.Results
}
else
{
// report error
}
}
else
{
// report cancellation
}
};
client.DownloadDataAsync(uri);
}
My thought process is for any long running downloads, waiting until the next item in the queue to exit would not be appropriate, so the idea would be to call CancelASync()
on the sender
of the DownloadProgressChanged
event handler.
Is this the best alternative short of putting a webClient
field in the class? And are there dangers or possible unpredictable behavior that I have not found in my testing?