Reputation: 28296
When I run the code below, the message "Press Enter to continue... "
appears before the results are returned from the HttpClient.GetAsync()
calls are completed. The actual sequence of events: the GetAsync()
calls are made, the "Press Enter...
" message appears, and then the results are one-by-one output to the console window. How do I wait until all the GetAsync()
calls are complete before displaying the "Press Enter...
" message?
class Program
{
static HttpClient client = new HttpClient();
static void Main(string[] args)
{
RunAsync().Wait();
Console.WriteLine("\n\n\n\nPress Enter to continue... ");
Console.ReadLine();
}
static async Task RunAsync()
{
List<string> urls = new List<string>()
{
"http://www.domain1.com",
"http://www.domain2.com",
"http://www.domain3.com",
"http://www.domain4.com"
};
foreach (var url in urls)
{
DownloadPageAsync(url);
}
}
static async Task<string> DownloadPageAsync(string url)
{
Console.WriteLine("Starting: " + url);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
// do stuff here
}
Console.WriteLine("Done: " + url);
return response.Content.ToString();
}
}
Upvotes: 0
Views: 1783
Reputation: 4119
You need to create different tasks per every call you want, in your example you are running the code and not waiting for the call. When you call WhenAll that simply creates a task for all of them. Let's say that you use the code bellow and inside each MakeYouCall method you insert an item on a list. That list will be a shared resource that you need to lock. When the WhenAll is made, then if you don't wait for the result(make a call to Wait() ) then the collection could be partially filled.
var register1 = new Action(() => MakeYourCall1());
var register2 = new Action(() => MakeYourCall2());
var register3 = new Action(() => MakeYourCall3());
then
var t1 = Task.Factory.StartNew(register1);
var t2 = Task.Factory.StartNew(register2);
var t3 = Task.Factory.StartNew(register3);
after that you can call the WhenAll that will return a Task, then wait for it.
Task.WhenAll(t1, t2, t3).Wait();
Upvotes: -2
Reputation: 2889
The @patrik-hofman answer is a good one (up voted) although, see my comment
If you would rather the requests to happen sequentially...
Add await
to the DownloadPageAsync
line.
You've used async
in RunAsync
but there are no await
s. So, although it returns a Task it is not waiting for the DownloadPageAsync
call to complete. This means that the method simply returns an "empty" Task which completes immediately. So your .Wait()
is waiting for nothing.
Upvotes: 1
Reputation: 5303
I think the problem is that you are not awaiting the DownloadPageAsync
method inside the RunAsync()
method. If you update the RunAsync()
method to the code below then I believe it will work as you expect:
static async Task RunAsync()
{
List<string> urls = new List<string>()
{
"http://www.domain1.com",
"http://www.domain2.com",
"http://www.domain3.com",
"http://www.domain4.com"
};
foreach (var url in urls)
{
// added await here
await DownloadPageAsync(url);
}
}
Upvotes: 0
Reputation: 156898
Since DownloadPageAsync
returns a task, you can make a list of all tasks and wait on them all:
Task.WhenAll(urls.Select(url => DownloadPageAsync(url)))
Or simplified:
Task.WhenAll(urls.Select(DownloadPageAsync))
Upvotes: 3