使用HttpClient.GetAsync来调用Web API似乎挂了

时间:2015-05-14 19:42:22

标签: c# asp.net asp.net-web-api async-await task-parallel-library

我正在研究概念验证原型 我有Asp.Net C#web表单(Visual Studio 2013,.Net 4.5)页面。点击按钮我会做这样的事情:

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如下所示:

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

    }
}

代码在response = await client.GetAsync调用处停止。当我说它停止时,调试器就像请求已经结束,但浏览器仍在等待。

如果我运行一个控制台应用程序(我将RunAsync()方法复制并粘贴到其中),它以相同的方式调用Web API,我得到了我的数据。所以,我相信Web API应用程序正在按预期响应。

4 个答案:

答案 0 :(得分:3)

此:

 RunAsyncBlogs().Wait();

使代码死锁。它同步阻止您的异步方法调用,该调用尝试将继续编组回隐式捕获的同步上下文。这就是你shouldn't block on async code

的原因
protected async void btnLoadData_Click(object sender, EventArgs e)
{
   // Other stuff
   await RunAsyncBlogs();
}

答案 1 :(得分:1)

问题是您必须嵌套async方法。其中RunAsyncBlogsresponse.Content.ReadAsAsync<List<Blog>>();

在以下行的末尾添加.ConfigureAwait(false)会阻止您的代码挂起:

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

但是,即使这会解决阻塞问题,代码也会同步执行,因为Wait()方法中的btnLoadData_Click调用。

如前所述,切换到异步执行是更好的解决方案。

答案 2 :(得分:0)

您的按钮点击事件需要是异步的。

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

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

        case 4:
            await RunAsyncBlogs();

            break;

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

    //...;
}

请参阅有关处理异步阻止问题的帖子。

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

答案 3 :(得分:0)

是VS2013与WEbAPi和MVC的Web应用程序 在MVC中,我链接到这个:

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

}

WebApi称为EmployeesController。我有这个方法:

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