WebApi 无法 return 到 HttpClient
WebApi unable to return to HttpClient
当我试图从 HttpClient
(MVC 应用程序)调用 GetAllFiles()
时,它在花括号结束后卡住。我可以在调试模式下看到数据,但是当到达然后结束大括号时它被卡住了。
当我从邮递员调用相同的WebApi 方法时,我可以很容易地获取数据。
public class FileToDriveController : ApiController
{
public IHttpActionResult GetAllFiles()
{
//Gets credentials
GoogleUtility googleUtility = new GoogleUtility();
UserCredential credential = googleUtility.GetCredential();
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "DriveApiFileUpload"
});
var listRequest = service.Files.List();
listRequest.MaxResults = 10;
IList<Google.Apis.Drive.v2.Data.File> files = listRequest.Execute().Items;
if(files!=null)
{
return Ok(files); //i can see files here in debug mode
}
return InternalServerError();
}
}
这是 HttpClient 对 api
的调用
public async Task<HttpResponseMessage> getAllFiles()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:16184/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage message = await client.GetAsync("api/FileToDrive/GetAllFiles");
if (message.StatusCode == HttpStatusCode.OK)
{
return message;
}
return null;
}
}
你的问题是一个棘手的问题,它是由从控制器内部进行异步调用时的死锁引起的。看到这个很好的解释:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
The top-level method calls GetJsonAsync (within the UI/ASP.NET context).
GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).
GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.
GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.
The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.
… Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.
The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.
Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.
解决您的问题(同样,摘自博客post):
In your “library” async methods, use ConfigureAwait(false) wherever possible.
Don’t block on Tasks; use async all the way down.
当我试图从 HttpClient
(MVC 应用程序)调用 GetAllFiles()
时,它在花括号结束后卡住。我可以在调试模式下看到数据,但是当到达然后结束大括号时它被卡住了。
当我从邮递员调用相同的WebApi 方法时,我可以很容易地获取数据。
public class FileToDriveController : ApiController
{
public IHttpActionResult GetAllFiles()
{
//Gets credentials
GoogleUtility googleUtility = new GoogleUtility();
UserCredential credential = googleUtility.GetCredential();
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "DriveApiFileUpload"
});
var listRequest = service.Files.List();
listRequest.MaxResults = 10;
IList<Google.Apis.Drive.v2.Data.File> files = listRequest.Execute().Items;
if(files!=null)
{
return Ok(files); //i can see files here in debug mode
}
return InternalServerError();
}
}
这是 HttpClient 对 api
的调用public async Task<HttpResponseMessage> getAllFiles()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:16184/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage message = await client.GetAsync("api/FileToDrive/GetAllFiles");
if (message.StatusCode == HttpStatusCode.OK)
{
return message;
}
return null;
}
}
你的问题是一个棘手的问题,它是由从控制器内部进行异步调用时的死锁引起的。看到这个很好的解释:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
The top-level method calls GetJsonAsync (within the UI/ASP.NET context). GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context). GetStringAsync returns an uncompleted Task, indicating the REST request is not complete. GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete. The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread. … Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync. The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context. Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.
解决您的问题(同样,摘自博客post):
In your “library” async methods, use ConfigureAwait(false) wherever possible. Don’t block on Tasks; use async all the way down.