12

I am trying to use the functionality provided by "async" & "await" to asynchronously download webpage content and I have into issues where the Tasks are waiting forever to complete. Could you please let me know what is wrong with the following code snippet?

protected void Page_Load(object sender, EventArgs e)
{
    var websites = new string[] {"http://www.cnn.com","http://www.foxnews.com"};
    var tasks = websites.Select(GenerateSomeContent).ToList();

    //I don't want to use 'await Tasks.WhenAll(tasks)' as I need to block the
    //page load until the all the webpage contents are downloaded
    Task.WhenAll(tasks).Wait();

    //This line is never hit on debugging
    var somevalue = "Complete";
}

static async Task<Results> GenerateSomeContent(string url)
{
    var client = new HttpClient();
    var response = await client.GetAsync(url); //Await for response
    var content = await response.Content.ReadAsStringAsync();
    var output = new Results {Content = content};
    return output;
}

//Sample class to hold results
public class Results
{
    public string Content;
}
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
infinity
  • 1,900
  • 4
  • 29
  • 48
  • 1
    possible duplicate of [await vs Task.Wait - Deadlock?](http://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock) - describe exactly what happens - `await` and `Wait` are very different things. – Alexei Levenkov Jan 04 '13 at 03:12
  • On my example, the code execution stalls at the line 'Task.WhenAll(tasks).Wait();' – infinity Jan 04 '13 at 03:17

2 Answers2

21

First, make sure you're running on .NET 4.5, not .NET 4.0. ASP.NET was made async-aware in .NET 4.5.

Then, the proper solution is to await the result of Task.WhenAll:

var tasks = websites.Select(GenerateSomeContent);
await Task.WhenAll(tasks);

The ASP.NET pipeline (in .NET 4.5 only) will detect that your code is awaiting and will stall that request until Page_Load runs to completion.

Synchronously blocking on a task using Wait in this situation causes a deadlock as I explain on my blog.

dana
  • 17,267
  • 6
  • 64
  • 88
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • in your blog post, you say to use async/await all the way through the stack... what if it's not an option... how can you properly use `.Wait()`? – Leonardo Apr 04 '17 at 21:19
  • @Leonardo: There's no solution that works in every scenario, but I enumerate several hacks in an [MSDN article on brownfield async](https://msdn.microsoft.com/en-us/magazine/mt238404.aspx). – Stephen Cleary Apr 05 '17 at 00:20
1

+1 Stephen Cleary. Just came to know you need to have async before void type with Page_Load as given below:

protected async void Page_Load(object sender, EventArgs e)
{
   var tasks = websites.Select(GenerateSomeContent);
   await Task.WhenAll(tasks);
}

And then in your code-behind file (in case asp.net web form app) should also have Async="true" attribute.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Async="true" Inherits="EmptyWebForm._default" %>

Hope this helps visitors.

Abhimanyu
  • 2,173
  • 2
  • 28
  • 44