【问题标题】:HttpClient request is not working in asp .net ProjectHttpClient 请求在 asp .net 项目中不起作用
【发布时间】:2017-01-27 16:47:31
【问题描述】:

我正在使用 HttpClient 向 api 发出请求。此代码位于与两个附加项目(控制台和 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 项目会阻塞在行中

【问题讨论】:

  • 尝试像这样同步调用异步方法:httpClient.Get(url);response.Content.ReadAsStream() 并告诉我是否仍然阻塞。
  • 您还需要在MVC控制器async中进行操作
  • @Alisson httpClient 没有 Get() 方法,并且 Content 没有 ReadAsStream()。我错过了一些命名空间?
  • 显示调用ReadJson函数的控制器动作
  • @AlexArt。我的控制器不是异步的,但我正在这样做: var task = ReadJson(...);任务.Wait();并使用任务的 Result 属性。为什么要使用异步控制器?

标签: asp.net-mvc api request console-application dotnet-httpclient


【解决方案1】:

这个死锁很可能是因为调用ReadJson 函数的控制器动作是同步的。您需要使操作异步。你可以找到这个死锁的一个很好的解释here。 (所有学分都归斯蒂芬·克利里所有)

快速总结是:

/ 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();
  }
}

导致死锁的原因

  1. 顶级方法调用 GetJsonAsync(在 UI/ASP.NET 上下文中)。 GetJsonAsync 通过调用启动 REST 请求 HttpClient.GetStringAsync(仍在上下文中)。

  2. GetStringAsync 返回一个未完成的Task,表示REST请求未完成。

  3. GetJsonAsync 等待 GetStringAsync 返回的任务。上下文被捕获并将用于继续运行 GetJsonAsync 方法稍后。 GetJsonAsync 返回一个未完成的 任务,表示GetJsonAsync方法未完成。

  4. 顶级方法同步阻塞 GetJsonAsync 返回的任务。这会阻塞上下文线程。

  5. ... 最终,REST 请求将完成。这样就完成了 GetStringAsync 返回的任务。

  6. GetJsonAsync 的延续现在已准备好运行,它等待上下文可用,以便可以在上下文中执行。

  7. 死锁。顶层方法正在阻塞上下文线程,等待 GetJsonAsync 完成,而 GetJsonAsync 正在等待 上下文是免费的,以便它可以完成。

防止死锁

有两种最佳做法可以避免这种情况:

  1. 在您的“库”异步方法中,尽可能使用 ConfigureAwait(false)。
  2. 不要阻止任务;一直使用异步。

【讨论】:

  • 我的控制器不是异步的,但我正在从 ReadJson 方法返回的任务中调用 wait 方法。就像@Alisson 所说,这是一个很好的做法,但它不应该是我的问题的原因。无论如何我都会托盘。
  • “我的控制器不是异步的,但我正在调用等待方法。”这正是问题所在。不要那样做——它会导致死锁。使您的控制器异步。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
  • 1970-01-01
  • 2018-10-18
  • 2019-10-16
  • 2014-08-29
  • 2020-12-01
相关资源
最近更新 更多