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的所有实例,并且我认为这是自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指出它分配取消令牌,请求/响应主体可以是非托管流。 Connection:close
标头。 另一种可能性是定期或通过一些了解DNS变化的机制在客户端回收HttpClient
。 有关更多信息,请参阅https://github.com/dotnet/corefx/issues/11224(我建议您在盲目使用链接的博客文章中建议的代码之前仔细阅读它)。 上一篇: Do HttpClient and HttpClientHandler have to be disposed?