是否必须处置HttpClient和HttpClientHandler?

本文翻译自:Do HttpClient and HttpClientHandler have to be disposed?

System.Net.Http.HttpClient and System.Net.Http.HttpClientHandler in .NET Framework 4.5 implement IDisposable (via System.Net.Http.HttpMessageInvoker ). .NET Framework 4.5中的System.Net.Http.HttpClientSystem.Net.Http.HttpClientHandler实现IDisposable(通过System.Net.Http.HttpMessageInvoker )。

The using statement documentation says: using语句文档说:

As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement. 通常,使用IDisposable对象时,应在using语句中声明并实例化它。

This answer uses this pattern: 此答案使用以下模式:

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();
}

But the most visible examples from Microsoft don't call Dispose() either explicitly or implicitly. 但是Microsoft最明显的示例都没有显式或隐式调用Dispose() For instance: 例如:

In the announcement 's comments, someone asked the Microsoft employee: 公告的评论中,有人问微软员工:

After checking your samples, I saw that you didn't perform the dispose action on HttpClient instance. 检查样本后,我发现您没有对HttpClient实例执行dispose操作。 I have used all instances of HttpClient with using statement on my app and I thought that it is the right way since HttpClient implements the IDisposable interface. 我已经在我的应用程序上使用了using语句来使用HttpClient的所有实例,并且我认为这是自HttpClient实现IDisposable接口以来的正确方法。 Am I on the right path? 我在正确的道路上吗?

His answer was: 他的回答是:

In general that is correct although you have to be careful with "using" and async as they dont' really mix in .Net 4, In .Net 4.5 you can use "await" inside a "using" statement. 通常,这是正确的,尽管您必须谨慎使用“使用”和异步,因为它们并没有真正混入.Net 4中。在.Net 4.5中,您可以在“ using”语句中使用“ await”。

Btw, you can reuse the same HttpClient as many times are [as] you like so typically you won't create/dispose them all the time. 顺便说一句,您可以根据需要多次重复使用同一HttpClient,因此通常不会一直创建/处置它们。

The second paragraph is superfluous to this question, which is not concerned about how many times you can use an HttpClient instance, but about if it is necessary to dispose it after you no longer need it. 第二段对于该问题是多余的,它与您可以使用HttpClient实例的次数无关,而与不再需要它之后是否需要处置它有关。

(Update: in fact that second paragraph is the key to the answer, as provided below by @DPeden.) (更新:实际上,第二段是答案的关键,如@DPeden所提供。)

So my questions are: 所以我的问题是:

  1. Is it necessary, given the current implementation (.NET Framework 4.5), to call Dispose() on HttpClient and HttpClientHandler instances? 在当前实现(.NET Framework 4.5)的情况下,是否有必要在HttpClient和HttpClientHandler实例上调用Dispose()? Clarification: by "necessary" I mean if there are any negative consequences for not disposing, such as resource leakage or data corruption risks. 澄清:“必要”是指是否存在不处置的任何负面后果,例如资源泄漏或数据损坏风险。

  2. If it's not necessary, would it be a "good practice" anyway, since they implement IDisposable? 如果没有必要,因为它们实现了IDisposable,这是否仍然是“良好实践”?

  3. If it's necessary (or recommended), is this code mentioned above implementing it safely (for .NET Framework 4.5)? 如果有必要(或建议), 上述代码是否可以安全地实现(对于.NET Framework 4.5)?

  4. If these classes don't require calling Dispose(), why were they implemented as IDisposable? 如果这些类不需要调用Dispose(),为什么将它们实现为IDisposable?

  5. If they require, or if it's a recommended practice, are the Microsoft examples misleading or unsafe? 如果他们有要求,或者如果推荐这样做,Microsoft的示例是否会引起误解或不安全?


#1楼

参考:https://stackoom.com/question/13tbw/是否必须处置HttpClient和HttpClientHandler


#2楼

In my understanding, calling Dispose() is necessary only when it's locking resources you need later (like a particular connection). 据我了解,仅当它锁定以后需要的资源(例如特定连接)时,才需要调用Dispose() )。 It's always recommended to free resources you're no longer using, even if you don't need them again, simply because you shouldn't generally be holding onto resources you're not using (pun intended). 始终建议释放不再使用的资源,即使您不再需要它们,也仅仅是因为通常不应该保留不使用的资源(双关语意)。

The Microsoft example is not incorrect, necessarily. Microsoft的示例不一定是错误的。 All resources used will be released when the application exits. 当应用程序退出时,将释放所有使用的资源。 And in the case of that example, that happens almost immediately after the HttpClient is done being used. 在该示例中,这几乎在使用HttpClient之后立即发生。 In like cases, explicitly calling Dispose() is somewhat superfluous. 在类似情况下,显式调用Dispose()有点多余。

But, in general, when a class implements IDisposable , the understanding is that you should Dispose() of its instances as soon as you're fully ready and able. 但是,总的来说,当一个类实现IDisposable ,可以理解的是,一旦完全准备好并有能力,就应该立即对其实例进行Dispose() I'd posit this is particularly true in cases like HttpClient wherein it's not explicitly documented as to whether resources or connections are being held onto/open. 我认为这在HttpClient之类的情况下尤其如此,因为在其中未明确记录有关资源或连接是否保持/打开的情况。 In the case wherein the connection will be reused again [soon], you'll want to forgo Dipose() ing of it -- you're not "fully ready" in that case. 在很快将再次使用连接的情况下,您将要放弃Dipose()处理-在这种情况下,您还没有“完全准备好”。

See also: IDisposable.Dispose Method and When to call Dispose 另请参见: IDisposable.Dispose方法何时调用Dispose


#3楼

The general consensus is that you do not (should not) need to dispose of HttpClient. 普遍的共识是您不需要(不应)处置HttpClient。

Many people who are intimately involved in the way it works have stated this. 许多与它的工作方式密切相关的人都说过这一点。

See Darrel Miller's blog post and a related SO post: HttpClient crawling results in memory leak for reference. 请参阅Darrel Miller的博客文章和相关的SO文章: HttpClient爬网导致内存泄漏,以供参考。

I'd also strongly suggest that you read the HttpClient chapter from Designing Evolvable Web APIs with ASP.NET for context on what is going on under the hood, particularly the "Lifecycle" section quoted here: 我也强烈建议您阅读使用ASP.NET设计可演化的Web API》中的HttpClient一章, 了解有关幕后情况的上下文,尤其是此处引用的“生命周期”部分:

Although HttpClient does indirectly implement the IDisposable interface, the standard usage of HttpClient is not to dispose of it after every request. 尽管HttpClient确实间接实现了IDisposable接口,但是HttpClient的标准用法是在每次请求后都不要处理它。 The HttpClient object is intended to live for as long as your application needs to make HTTP requests. 只要您的应用程序需要发出HTTP请求,HttpClient对象就可以存在。 Having an object exist across multiple requests enables a place for setting DefaultRequestHeaders and prevents you from having to re-specify things like CredentialCache and CookieContainer on every request as was necessary with HttpWebRequest. 在多个请求中都存在一个对象,这为设置DefaultRequestHeaders提供了空间,并且使您不必在HttpWebRequest所必需的每个请求上重新指定CredentialCache和CookieContainer之类的东西。

Or even open up DotPeek. 甚至开放DotPeek。


#4楼

In my case, I was creating an HttpClient inside a method that actually did the service call. 就我而言,我正在实际上执行服务调用的方法内创建HttpClient。 Something like: 就像是:

public void DoServiceCall() {
  var client = new HttpClient();
  await client.PostAsync();
}

In an Azure worker role, after repeatedly calling this method (without disposing the HttpClient), it would eventually fail with SocketException (connection attempt failed). 在Azure工作人员角色中,在反复调用此方法(不处理HttpClient)之后,它最终将因SocketException失败(连接尝试失败)。

I made the HttpClient an instance variable (disposing it at the class level) and the issue went away. 我将HttpClient设置为实例变量(将其放置在类级别),然后问题消失了。 So I would say, yes, dispose the HttpClient, assuming its safe (you don't have outstanding async calls) to do so. 因此,我想说的是,假设HttpClient可以安全地处理(您没有未完成的异步调用),则可以将其丢弃。


#5楼

I think one should use singleton pattern to avoid having to create instances of the HttpClient and closing it all the time. 我认为应该使用单例模式来避免不得不创建HttpClient实例并一直关闭它。 If you are using .Net 4.0 you could use a sample code as below. 如果使用的是.Net 4.0,则可以使用以下示例代码。 for more information on singleton pattern check here . 有关单例模式的更多信息,请在这里检查。

class HttpClientSingletonWrapper : HttpClient
{
    private static readonly Lazy<HttpClientSingletonWrapper> Lazy= new Lazy<HttpClientSingletonWrapper>(()=>new HttpClientSingletonWrapper()); 

    public static HttpClientSingletonWrapper Instance {get { return Lazy.Value; }}

    private HttpClientSingletonWrapper()
    {
    }
}

Use the code as below. 使用如下代码。

var client = HttpClientSingletonWrapper.Instance;

#6楼

In typical usage (responses<2GB) it is not necessary to Dispose the HttpResponseMessages. 在典型用法中(respons <2GB),不需要处置HttpResponseMessages。

The return types of the HttpClient methods should be Disposed if their Stream Content is not fully Read. 如果未完全读取HttpClient方法的返回类型,则应丢弃它们的流类型。 Otherwise there is no way for the CLR to know those Streams can be closed until they are garbage collected. 否则,CLR无法知道这些流可以被关闭直到被垃圾回收。

  • If you are reading the data into a byte[] (eg GetByteArrayAsync) or string, all data is read, so there is no need to dispose. 如果要将数据读取到byte [](例如GetByteArrayAsync)或字符串中,则将读取所有数据,因此无需进行处理。
  • The other overloads will default to reading the Stream up to 2GB (HttpCompletionOption is ResponseContentRead, HttpClient.MaxResponseContentBufferSize default is 2GB) 其他重载将默认读取最多2GB的流(HttpCompletionOption为ResponseContentRead,HttpClient.MaxResponseContentBufferSize默认为2GB)

If you set the HttpCompletionOption to ResponseHeadersRead or the response is larger than 2GB, you should clean up. 如果将HttpCompletionOption设置为ResponseHeadersRead或响应大于2GB,则应清除。 This can be done by calling Dispose on the HttpResponseMessage or by calling Dispose/Close on the Stream obtained from the HttpResonseMessage Content or by reading the content completely. 这可以通过在HttpResponseMessage上调用Dispose或在从HttpResonseMessage内容获取的流上调用Dispose / Close或完全读取内容来完成。

Whether you call Dispose on the HttpClient depends on whether you want to cancel pending requests or not. 是否在HttpClient上调用Dispose取决于是否要取消挂起的请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值