首页 > 解决方案 > 为什么在 WebApi 上下文中的 using 块中使用 HttpClient 是错误的?

问题描述

那么,问题是为什么在使用块中使用 HttpClient 是错误的,但在 WebApi 上下文中?

我一直在阅读这篇文章Don't Block on Async Code。在其中,我们有以下示例:

public static async Task<JObject> GetJsonAsync(Uri uri)
{
  // (real-world code shouldn't use HttpClient in a using block; this is just example code)
  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();
  }
}

评论// (real-world code shouldn't use HttpClient in a using block; this is just example code)刚刚触发了我。我一直以这种方式使用 HttpClient。

我检查的下一件事是微软关于 HttpClient Class 的文档。在其中,我们有以下语句以及提供的源示例:

HttpClient 旨在被实例化一次并在应用程序的整个生命周期中重复使用。为每个请求实例化一个 HttpClient 类将耗尽重负载下可用的套接字数量。这将导致 SocketException 错误。下面是一个正确使用 HttpClient 的例子。

public class GoodController : ApiController
{
    private static readonly HttpClient HttpClient;

    static GoodController()
    {
        HttpClient = new HttpClient();
    }
}

那么不是每个请求都调用构造函数,因此每次都会创建一个新的 HttpClient 吗?

谢谢!

标签: c#httpclientusingwebapi

解决方案


这个答案有点长...

最初,官方的建议是HttpClient在一个using块中使用。但这导致了大规模的问题,基本上耗尽了该TIME_WAIT州的大量连接。

所以,官方建议改为使用 static HttpClient。但这会导致无法正确处理 DNS 更新的问题。

因此,ASP.NET 团队IHttpClientFactory在 .NET Core 2.1中提出,因此代码(或至少在现代平台上运行的代码)可以重用HttpClient实例(或者更准确地说,这些实例的消息处理程序),避免了这个TIME_WAIT问题,但是还定期关闭这些连接以避免 DNS 问题。

但是,与此同时,.NET 团队也提出了SocketsHttpHandler.NET Core 2.1,它进行了连接池。

因此,在现代平台上,您可以使用IHttpClientFactory或使用 static/singleton HttpClient。在较旧的平台(包括 .NET Framework)上,您将使用静态/单例HttpClient,并且要么忍受 DNS 问题,要么使用其他解决方法


推荐阅读