Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using HttpClient.GetAsync to call Web API seems to hang

I'm working on a proof of concept prototype.
I have Asp.Net C# web form (Visual Studio 2013, .Net 4.5) page. On a button click I do something like this:

List<Blog> blogs = null;
protected void btnLoadData_Click(object sender, EventArgs e)
{
    //...;

    switch (int.Parse(rblDataSource.SelectedValue))
    {
        //...;

        case 4:
            RunAsyncBlogs().Wait();

            break;

        default:
            blogs = localGetter.GetBlogs();
            break;
    }

    //...;
}

RunAsyncBlogs looks like this:

static async Task RunAsyncBlogs()
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost/wapiDemo/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        // HTTP GET
        HttpResponseMessage response = await client.GetAsync("api/Blogs");
        if (response.IsSuccessStatusCode)
        {
            List<Blog> thisBlogList = await response.Content.ReadAsAsync<List<Blog>>();
            var cnt = thisBlogList.Count();
        }

    }
}

The code stops at the response = await client.GetAsync call. When I say it stops, the debugger acts like the request has ended, but the browser is still waiting.

If I run a console app (I copy and paste the RunAsync() method into it) which calls the Web API the same way, I get my data. So, I believe the Web API app is responding as expected.

like image 954
M Kenyon II Avatar asked May 14 '15 19:05

M Kenyon II


2 Answers

This:

 RunAsyncBlogs().Wait();

Is deadlocking your code. It is synchronously blocking your async method call which is trying to marshal back the continuation on to the implicitly captured synchronization context. That is why you shouldn't block on async code

protected async void btnLoadData_Click(object sender, EventArgs e)
{
   // Other stuff
   await RunAsyncBlogs();
}
like image 170
Yuval Itzchakov Avatar answered Nov 19 '22 18:11

Yuval Itzchakov


Problem is that you have to nested async methods. RunAsyncBlogs and response.Content.ReadAsAsync<List<Blog>>(); inside of it.

Adding .ConfigureAwait(false) at the end of following line will prevent your code from hanging:

var thisBlogList = await response.Content.ReadAsAsync<List<Blog>>().ConfigureAwait(false);

However, even though this will solve blocking, code will still execute synchronously, because of the Wait() call in btnLoadData_Click method.

Switching to asynchronous execution, as already suggested is better solution.

like image 29
Nenad Avatar answered Nov 19 '22 18:11

Nenad