【问题标题】:Using HttpClient.GetAsync to call Web API seems to hang使用 HttpClient.GetAsync 调用 Web API 似乎挂了
【发布时间】:2015-07-26 13:53:09
【问题描述】:

我正在制作概念验证原型。
我有 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 应用会按预期响应。

【问题讨论】:

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


    【解决方案1】:

    这个:

     RunAsyncBlogs().Wait();
    

    使您的代码陷入僵局。它正在同步阻止您的异步方法调用,该方法调用试图将继续编组到隐式捕获的同步上下文中。这就是为什么你shouldn't block on async code

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

    【讨论】:

      【解决方案2】:

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

      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】:

        问题是你必须嵌套async 方法。 RunAsyncBlogsresponse.Content.ReadAsAsync&lt;List&lt;Blog&gt;&gt;(); 在里面。

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

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

        然而,即使这会解决阻塞,代码仍将同步执行,因为 btnLoadData_Click 方法中的 Wait() 调用。

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

        【讨论】:

          【解决方案4】:

          是一个带有 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);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-04
            • 2011-12-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-03
            相关资源
            最近更新 更多