I'm currently working with the Async CTP and need to convert this code into code where I can use Task.WhenAll().
What I did until now was using the UserState object and put my identifier (AID) into it and then use it in the completed event.
However the wc.DownloadFileTaskAsync methode doesn't have an overload with UserState. What can I do?
for (int i = 0; i < SortedRecommendations.Count; i++)
{
string tempfilepath = filepath + SortedRecommendations[i].Aid + ".jpg";
if (File.Exists(tempfilepath))
continue;
WebClient wc = new WebClient();
wc.DownloadFileCompleted += (s, e) =>
{
var q = SortedRecommendations.Where(x => x.Aid == (int)e.UserState);
if (q.Count() > 0)
q.First().Image = tempfilepath;
};
wc.DownloadFileAsync(new Uri(SortedRecommendations[i].Image.Replace("t.jpg", ".jpg")), tempfilepath, SortedRecommendations[i].Aid);
}
This is basically with what I came up with, however I'm getting a out ouf bounds exception at y.Aid == SortedRecommendations[i].Aid because i is now obvioulsy something else then it was when the download started. Only other possibility I see is using something like TaskEx.Run( () => { // download data synchronously }; but I don't like this approach.
for (int i = 0; i < SortedRecommendations.Count; i++)
{
string tempfilepath = filepath + SortedRecommendations[i].Aid + ".jpg";
if (File.Exists(tempfilepath))
continue;
WebClient wc = new WebClient();
wc.DownloadFileCompleted += (s, e) =>
{
var q = SortedRecommendations.Where(x => x.Aid == SortedRecommendations[i].Aid);
if (q.Count() > 0)
q.First().Image = tempfilepath;
};
tasks.Add(wc.DownloadFileTaskAsync(new Uri(SortedRecommendations[i].Image.Replace("t.jpg", ".jpg")), tempfilepath));
}
await TaskEx.WhenAll(tasks);
//Everything finished
First, I think you shouldn't base your logic on ids (unless you really have to). You should use references to the objects in the
SortedRecommendations
collection.Now, if you wanted to download only one file at a time, you could simply use
await
:But, if you wanted to start all of the downloads at the same time, like your
DownloadFileAsync()
code does, you could useContinueWith()
instead. And you don't need user state, that's what closures are for:The best solution would probably be to download a limited number of files at once, not one or all of them. Doing that is more complicated and one solution would be to use
ActionBlock
from TPL Dataflow withMaxDegreeOfParallelism
set.