HttpClient和HttpClientHandler必须被丢弃吗?

System.Net.Http.HttpClient和.NET Framework 4.5中的System.Net.Http.HttpClientHandler实现IDisposable(通过System.Net.Http.HttpMessageInvoker)。

using说明文档说:

通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它。

这个答案使用这种模式:

var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("foo", "bar"),
        new KeyValuePair<string, string>("baz", "bazinga"),
    });
    cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
    var result = client.PostAsync("/test", content).Result;
    result.EnsureSuccessStatusCode();
}

但是来自Microsoft的最明显的例子并不是明确地或隐含地调用Dispose() 。 例如:

  • 最初的博客文章宣布HttpClient的发布。
  • HttpClient的实际MSDN文档。
  • BingTranslateSample
  • GoogleMapsSample
  • WorldBankSample
  • 在公告的评论中,有人问微软员工:

    在检查完你的示例之后,我看到你没有在HttpClient实例上执行处理动作。 我已经在我的应用程序中使用了HttpClient的所有实例,并且我认为这是自HttpClient实现IDisposable接口以来的正确方法。 我在正确的道路上吗?

    他的回答是:

    一般来说,这是正确的,虽然你必须小心“使用”和异步,因为他们不真正混入.Net 4,在.Net 4.5中,你可以在“使用”语句中使用“await”。

    顺便说一句,你可以重复使用相同的HttpClient多次[因为你喜欢,所以通常你不会一直创建/处理它们。

    第二段对于这个问题来说非常重要,它并不关心你可以使用一个HttpClient实例的次数,但是如果在你不再需要它的时候有必要处理它。

    (更新:实际上第二段是答案的关键,正如以下@DPeden所提供的。)

    所以我的问题是:

  • 鉴于当前的实现(.NET Framework 4.5),是否有必要在HttpClient和HttpClientHandler实例上调用Dispose()? 澄清:“必要的”我的意思是,如果不处置有任何消极后果,例如资源泄漏或数据损坏风险。

  • 如果没有必要,无论如何,它会是一个“良好实践”,因为它们实现了IDisposable?

  • 如果有必要(或推荐),上面提到的代码是否安全地实现了它(对于.NET Framework 4.5)?

  • 如果这些类不需要调用Dispose(),为什么它们实现为IDisposable?

  • 如果他们需要,或者如果这是一个推荐的做法,微软的例子是误导还是不安全?


  • 普遍的共识是你不(不应该)需要处理HttpClient。

    许多与其工作方式密切相关的人已经表明了这一点。

    请参阅Darrel Miller的博客文章和相关SO帖子:HttpClient抓取导致内存泄漏以供参考。

    我还强烈建议您阅读使用ASP.NET设计Evolvable Web API的HttpClient一章,了解引擎背后发生的情况,特别是此处引用的“生命周期”部分:

    尽管HttpClient间接实现了IDisposable接口,但HttpClient的标准用法并不是在每次请求后处理它。 只要您的应用程序需要发出HTTP请求,HttpClient对象就会生存下来。 跨多个请求存在一个对象可以让您设置DefaultRequestHeaders的位置,并防止您在每个请求上重新指定CredentialCache和CookieContainer之类的内容,这与使用HttpWebRequest时所需要的一样。

    甚至打开DotPeek。


    根据我的理解,调用Dispose()只有在稍后锁定需要的资源(如特定连接)时才是必需的。 总是建议您释放您不再使用的资源,即使您不再需要它们,这仅仅是因为您通常不应该持有您未使用的资源(双关语意)。

    微软的例子是不正确的,必然。 所有使用的资源将在应用程序退出时发布。 在这个例子中,在HttpClient完成使用后几乎立即发生。 在类似的情况下,显式调用Dispose()有点多余。

    但是,一般来说,当一个类实现了IDisposable ,我们的理解是,只要您完全准备好并且能够完成,就应该Dispose()它的实例。 我假设这在HttpClient情况下尤其如此,其中没有明确记录资源或连接是否保持在/打开状态。 在其中连接将被再次使用的情况下[快],你要放弃Dipose()它ING -你不是在这种情况下,“完全准备好”。

    另请参阅:IDisposable.Dispose方法和何时调用Dispose


    目前的答案有点令人困惑和误导,并且缺少一些重要的DNS含义。 我会尽量总结事情的清楚之处。

  • 一般来说,大多数IDisposable对象理想情况下应该在处理 IDisposable 它们后处置 ,特别是那些拥有命名/共享OS资源的对象。 HttpClient也不例外,因为Darrel Miller指出它分配取消令牌,请求/响应主体可以是非托管流。
  • 但是,HttpClient的最佳实践是,您应该创建一个实例并尽可能重用它(在多线程场景中使用它的线程安全成员)。 因此,在大多数情况下, 你永远不会处理它,仅仅因为你会一直需要它
  • 重复使用相同HttpClient“永远”的问题是,无论DNS更改如何,底层HTTP连接都可能会保持打开,以抵御最初DNS解析的IP。 这可能是蓝色/绿色部署和基于DNS的故障转移等场景中的问题。 处理这个问题有多种方法,最可靠的方法是在发生DNS更改后服务器发送Connection:close标头。 另一种可能性是定期或通过一些了解DNS变化的机制在客户端回收HttpClient 。 有关更多信息,请参阅https://github.com/dotnet/corefx/issues/11224(我建议您在盲目使用链接的博客文章中建议的代码之前仔细阅读它)。
  • 链接地址: http://www.djcxy.com/p/54039.html

    上一篇: Do HttpClient and HttpClientHandler have to be disposed?

    下一篇: Disposable Context Object pattern