M Kenyon II
M Kenyon II

Reputation: 4274

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.

Upvotes: 5

Views: 15006

Answers (4)

Fabio Marchi
Fabio Marchi

Reputation: 1

Is a Web Application with VS2013 with WEbAPi and MVC In MVC I have I link to this:

public JsonResult GetWithHttpClient()
{

Employee employee = null;
using (var client = new HttpClient())
{

    client.BaseAddress = new Uri(path);
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = client.GetAsync("api/Employees/12345").Result;

    //the IsSuccessStatusCode property is false if the status is an error code. 
    //All the error: {StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:{  Pragma: no-cache  X-SourceFiles: =?UTF-8?B?QzpcRkFCSU9fQ09ESUNFXE15RXhhbXBsZVxXZWJBcHBsaWNhdGlvbjFcV2ViQXBwbGljYXRpb24xXGFwaVxFbXBsb3llZXNcMTIzNDU=?=  Cache-Control: no-cache  Date: Tue, 28 Jul 2015 14:47:03 GMT  Server: Microsoft-IIS/8.0  WWW-Authenticate: Bearer  X-AspNet-Version: 4.0.30319  X-Powered-By: ASP.NET  Content-Length: 61  Content-Type: application/json; charset=utf-8  Expires: -1}}
        if (response.IsSuccessStatusCode)
        {
            employee = response.Content.ReadAsAsync<Employee>().Result;               

    }
}

return Json (employee, JsonRequestBehavior.AllowGet); 

}

The WebApi is called EmployeesController. And I have this method:

public Employee Get(int id)
{
return list.First(e => e.Id == id);
}

Upvotes: 0

Nenad
Nenad

Reputation: 26687

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.

Upvotes: 1

William Xifaras
William Xifaras

Reputation: 5312

Your button click event needs to be async.

protected async void btnLoadData_Click(object sender, EventArgs e)
{
    //...;

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

        case 4:
            await RunAsyncBlogs();

            break;

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

    //...;
}

See this post on dealing with blocking issues with async.

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Upvotes: 0

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149558

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();
}

Upvotes: 4

Related Questions