.NET Framework 4.5 中的System.Net.Http.HttpClient和System.Net.Http.HttpClientHandler实现 IDisposable(通过System.Net.Http.HttpMessageInvoker)。
using声明文件说:
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(); }
但是微软最明显的例子并没有Dispose()显式或隐式调用。
Dispose()
在公告的评论中,有人问微软员工:
检查您的示例后,我发现您没有对 HttpClient 实例执行 dispose 操作。我已经在我的应用程序上使用了带有 using 语句的 HttpClient 的所有实例,并且我认为这是正确的方法,因为 HttpClient 实现了 IDisposable 接口。我在正确的道路上吗?
他的回答是:
一般来说,这是正确的,尽管您必须小心“使用”和异步,因为它们不会真正混合在 .Net 4 中,在 .Net 4.5 中,您可以在“使用”语句中使用“等待”。 顺便说一句,您可以根据自己的喜好多次重复使用相同的 HttpClient,因此通常您不会一直创建/处置它们。
一般来说,这是正确的,尽管您必须小心“使用”和异步,因为它们不会真正混合在 .Net 4 中,在 .Net 4.5 中,您可以在“使用”语句中使用“等待”。
顺便说一句,您可以根据自己的喜好多次重复使用相同的 HttpClient,因此通常您不会一直创建/处置它们。
第二段对于这个问题是多余的,它不是关心你可以使用多少次 HttpClient 实例,而是关心在你不再需要它之后是否有必要将其处置。
(更新:事实上,第二段是答案的关键,@DPeden 在下面提供。)
所以我的问题是:
鉴于当前的实现(.NET Framework 4.5),是否有必要在 HttpClient 和 HttpClientHandler 实例上调用 Dispose() ?澄清:“必要”是指不处置是否有任何负面后果,例如资源泄漏或数据损坏风险。
如果没有必要,这是否是一个“好习惯”,因为他们实现了 IDisposable?
如果有必要(或推荐),上面提到的这段代码是否安全地实现它(对于 .NET Framework 4.5)?
如果这些类不需要调用 Dispose(),为什么它们被实现为 IDisposable?
如果他们需要,或者如果这是推荐的做法,Microsoft 示例是否具有误导性或不安全?
普遍的共识是您不需要(不应该)处理 HttpClient。
许多密切参与其工作方式的人都说过这一点。
请参阅Darrel Miller 的博客文章和相关的 SO 文章:HttpClient crawling results in memory leak以供参考。
我还强烈建议您阅读 Designing Evolvable Web APIs with ASP.NET 中的 HttpClient 章节,了解 __幕后情况,特别是此处引用的“生命周期”部分:
尽管 HttpClient 确实间接实现了 IDisposable 接口,但 HttpClient 的标准用法并不是在每次请求后都将其丢弃。只要您的应用程序需要发出 HTTP 请求,HttpClient 对象就会一直存在。让一个对象存在于多个请求中可以设置 DefaultRequestHeaders 并防止您必须在每个请求上重新指定诸如 HttpWebRequest 所必需的 CredentialCache 和 CookieContainer 之类的东西。
甚至打开 DotPeek。