为什么在 WebApi 上下文中在 using 块中使用 HttpClient 是错误的?

Ros*_*ech 4 c# using httpclient webapi

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

我一直在阅读这篇文章“不要阻止异步代码”。其中我们有以下示例:

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

评论// (real-world code shouldn't use HttpClient in a using block; this is just example code)刚刚触动了我。我一直都是这样使用HttpClient的。

我检查的下一件事是Microsoft 关于 HttpClient Class 的文档。其中,我们有以下声明以及提供的源示例:

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

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

    static GoodController()
    {
        HttpClient = new HttpClient();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

谢谢!

Ste*_*ary 10

这个问题的答案有点长……

HttpClient最初,官方建议是在块中使用using。但这造成了大规模的问题,基本上耗尽了该州的大量联系TIME_WAIT

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

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

但与此同时,.NET 团队SocketsHttpHandler在 .NET Core 2.1 中也提出了连接池功能。

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