HttpClient 请求在 asp .net 项目中不起作用
HttpClient request is not working in asp .net Project
我正在使用 HttpClient 向 api 发出请求。此代码位于与两个附加项目共享的 class 库项目中,一个控制台和一个 Asp.Net Mvc 项目。当我从控制台项目发出请求时,它运行良好,但在 asp 项目中它阻塞在行
using(Stream responseStream = await response.Content.ReadAsStreamAsync()
这是我的请求码
private async Task<dynamic> ReadJson(string url)
{
HttpResponseMessage response = await httpClient.GetAsync(url);
if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
throw new RateLimitException();
if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
throw new AccessDeniedException();
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception("Error: " + response.StatusCode);
using (Stream responseStream = await response.Content.ReadAsStreamAsync())
using (StreamReader sr = new StreamReader(responseStream, System.Text.Encoding.UTF8))
{
string json = sr.ReadToEnd();
return JObject.Parse(json);
}
}
我正在从控制台和 Asp.Net 项目对方法进行相同的调用。从控制台工作但 asp .net 项目在读取响应内容时阻塞在行中
很可能会发生此死锁,因为调用 ReadJson
函数的控制器操作是同步的。您需要使操作异步。你可以找到这个死锁的一个很好的解释 here。 (所有学分归于 Stephen Cleary)
快速总结是:
/ My "library" method.
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
}
// My "top-level" method.
public class MyController : ApiController
{
public string Get()
{
var jsonTask = GetJsonAsync(...);
return jsonTask.Result.ToString();
}
}
What Causes the Deadlock
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.
Preventing the Deadlock
There are two best practices that avoid this situation:
- In your “library” async methods, use ConfigureAwait(false) wherever possible.
- Don’t block on Tasks; use async all the way down.
我正在使用 HttpClient 向 api 发出请求。此代码位于与两个附加项目共享的 class 库项目中,一个控制台和一个 Asp.Net Mvc 项目。当我从控制台项目发出请求时,它运行良好,但在 asp 项目中它阻塞在行
using(Stream responseStream = await response.Content.ReadAsStreamAsync()
这是我的请求码
private async Task<dynamic> ReadJson(string url)
{
HttpResponseMessage response = await httpClient.GetAsync(url);
if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
throw new RateLimitException();
if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
throw new AccessDeniedException();
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception("Error: " + response.StatusCode);
using (Stream responseStream = await response.Content.ReadAsStreamAsync())
using (StreamReader sr = new StreamReader(responseStream, System.Text.Encoding.UTF8))
{
string json = sr.ReadToEnd();
return JObject.Parse(json);
}
}
我正在从控制台和 Asp.Net 项目对方法进行相同的调用。从控制台工作但 asp .net 项目在读取响应内容时阻塞在行中
很可能会发生此死锁,因为调用 ReadJson
函数的控制器操作是同步的。您需要使操作异步。你可以找到这个死锁的一个很好的解释 here。 (所有学分归于 Stephen Cleary)
快速总结是:
/ My "library" method. public static async Task<JObject> GetJsonAsync(Uri uri) { using (var client = new HttpClient()) { var jsonString = await client.GetStringAsync(uri); return JObject.Parse(jsonString); } } // My "top-level" method. public class MyController : ApiController { public string Get() { var jsonTask = GetJsonAsync(...); return jsonTask.Result.ToString(); } }
What Causes the Deadlock
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.
Preventing the Deadlock
There are two best practices that avoid this situation:
- In your “library” async methods, use ConfigureAwait(false) wherever possible.
- Don’t block on Tasks; use async all the way down.