使用 HttpClient.GetAsync 调用 Web API 似乎挂起
Using HttpClient.GetAsync to call Web API seems to hang
我正在研究概念原型的证明。
我有 Asp.Net C# 网络表单(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 调用处停止。当我说它停止时,调试器就像请求已经结束一样,但浏览器仍在等待。
如果我 运行 一个以相同方式调用 Web API 的控制台应用程序(我将 RunAsync() 方法复制并粘贴到其中),我将获得我的数据。所以,我相信 Web API 应用程序的响应符合预期。
这个:
RunAsyncBlogs().Wait();
使您的代码陷入僵局。它正在同步阻止您的异步方法调用,该方法调用试图将继续编组回隐式捕获的同步上下文。这就是为什么你 shouldn't block on async code
protected async void btnLoadData_Click(object sender, EventArgs e)
{
// Other stuff
await RunAsyncBlogs();
}
您的按钮点击事件需要异步。
protected async void btnLoadData_Click(object sender, EventArgs e)
{
//...;
switch (int.Parse(rblDataSource.SelectedValue))
{
//...;
case 4:
await RunAsyncBlogs();
break;
default:
blogs = localGetter.GetBlogs();
break;
}
//...;
}
请参阅此 post,了解如何处理异步阻塞问题。
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
问题是您必须嵌套 async
方法。 RunAsyncBlogs
和 response.Content.ReadAsAsync<List<Blog>>();
在里面。
在下一行末尾添加 .ConfigureAwait(false)
将防止您的代码挂起:
var thisBlogList = await response.Content.ReadAsAsync<List<Blog>>().ConfigureAwait(false);
然而,即使这将解决阻塞问题,代码仍将同步执行,因为在 btnLoadData_Click
方法中调用了 Wait()
。
如前所述,切换到异步执行是更好的解决方案。
是带有 WEbAPI 和 MVC 的 VS2013 的 Web 应用程序
在 MVC 中,我 link 到此:
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);
}
我正在研究概念原型的证明。
我有 Asp.Net C# 网络表单(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 调用处停止。当我说它停止时,调试器就像请求已经结束一样,但浏览器仍在等待。
如果我 运行 一个以相同方式调用 Web API 的控制台应用程序(我将 RunAsync() 方法复制并粘贴到其中),我将获得我的数据。所以,我相信 Web API 应用程序的响应符合预期。
这个:
RunAsyncBlogs().Wait();
使您的代码陷入僵局。它正在同步阻止您的异步方法调用,该方法调用试图将继续编组回隐式捕获的同步上下文。这就是为什么你 shouldn't block on async code
protected async void btnLoadData_Click(object sender, EventArgs e)
{
// Other stuff
await RunAsyncBlogs();
}
您的按钮点击事件需要异步。
protected async void btnLoadData_Click(object sender, EventArgs e)
{
//...;
switch (int.Parse(rblDataSource.SelectedValue))
{
//...;
case 4:
await RunAsyncBlogs();
break;
default:
blogs = localGetter.GetBlogs();
break;
}
//...;
}
请参阅此 post,了解如何处理异步阻塞问题。
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
问题是您必须嵌套 async
方法。 RunAsyncBlogs
和 response.Content.ReadAsAsync<List<Blog>>();
在里面。
在下一行末尾添加 .ConfigureAwait(false)
将防止您的代码挂起:
var thisBlogList = await response.Content.ReadAsAsync<List<Blog>>().ConfigureAwait(false);
然而,即使这将解决阻塞问题,代码仍将同步执行,因为在 btnLoadData_Click
方法中调用了 Wait()
。
如前所述,切换到异步执行是更好的解决方案。
是带有 WEbAPI 和 MVC 的 VS2013 的 Web 应用程序 在 MVC 中,我 link 到此:
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);
}