ape*_*als 1 api asp.net-mvc request console-application dotnet-httpclient
我正在使用 HttpClient 向 api 发出请求。此代码位于与两个附加项目(控制台和 Asp.Net Mvc 项目)共享的类库项目中。当我从控制台项目发出请求时,它工作得很好,但在 asp 项目中,它阻塞了行
using(Stream responseStream = await response.Content.ReadAsStreamAsync()
Run Code Online (Sandbox Code Playgroud)
这是我的请求代码
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我正在从控制台和 Asp.Net 项目对方法进行相同的调用。从控制台工作,但 asp .net 项目在读取响应内容时阻止行
这种死锁的发生很可能是因为调用ReadJson函数的控制器操作是同步的。您需要使操作异步。您可以在此处找到对此僵局的极好解释。(所有学分归斯蒂芬·克利里所有)
快速总结是:
Run Code Online (Sandbox Code Playgroud)/ 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(); } }导致死锁的原因
顶级方法调用 GetJsonAsync(在 UI/ASP.NET 上下文中)。GetJsonAsync 通过调用 HttpClient.GetStringAsync(仍在上下文中)启动 REST 请求。
GetStringAsync 返回一个未完成的 Task,表示 REST 请求未完成。
GetJsonAsync 等待 GetStringAsync 返回的 Task。上下文被捕获,稍后将用于继续运行 GetJsonAsync 方法。GetJsonAsync 返回一个未完成的Task,说明GetJsonAsync 方法未完成。
顶层方法同步阻塞 GetJsonAsync 返回的 Task。这会阻塞上下文线程。
… 最终,REST 请求将完成。这完成了由 GetStringAsync 返回的任务。
GetJsonAsync 的延续现在已准备好运行,它等待上下文可用,以便它可以在上下文中执行。
僵局。顶层方法正在阻塞上下文线程,等待 GetJsonAsync 完成,而 GetJsonAsync 正在等待上下文空闲以便它可以完成。
防止死锁
有两种最佳做法可以避免这种情况:
- 在您的“库”异步方法中,尽可能使用 ConfigureAwait(false)。
- 不要阻塞任务;一直使用异步。
| 归档时间: |
|
| 查看次数: |
1716 次 |
| 最近记录: |