Do HttpClient and HttpClientHandler have to be disposed between requests?

前端 未结 12 2273
鱼传尺愫
鱼传尺愫 2020-11-22 02:06

System.Net.Http.HttpClient and System.Net.Http.HttpClientHandler in .NET Framework 4.5 implement IDisposable (via System.Net.Http.HttpMessageInvoker).

The usin

12条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2020-11-22 02:13

    Short answer: No, the statement in the currently accepted answer is NOT accurate: "The general consensus is that you do not (should not) need to dispose of HttpClient".

    Long answer: BOTH of the following statements are true and achieveable at the same time:

    1. "HttpClient is intended to be instantiated once and re-used throughout the life of an application", quoted from official documentation.
    2. An IDisposable object is supposed/recommended to be disposed.

    And they DO NOT NECESSARILY CONFLICT with each other. It is just a matter of how you organize your code to reuse an HttpClient AND still dispose it properly.

    An even longer answer quoted from my another answer:

    It is not a coincidence to see people in some blog posts blaming how HttpClient 's IDisposable interface makes them tend to use the using (var client = new HttpClient()) {...} pattern and then lead to exhausted socket handler problem.

    I believe that comes down to an unspoken (mis?)conception: "an IDisposable object is expected to be short-lived".

    HOWEVER, while it certainly looks like a short-lived thing when we write code in this style:

    using (var foo = new SomeDisposableObject())
    {
        ...
    }
    

    the official documentation on IDisposable never mentions IDisposable objects have to be short-lived. By definition, IDisposable is merely a mechanism to allow you to release unmanaged resources. Nothing more. In that sense, you are EXPECTED to eventually trigger the disposal, but it does not require you to do so in a short-lived fashion.

    It is therefore your job to properly choose when to trigger the disposal, base on your real object's life cycle requirement. There is nothing stopping you from using an IDisposable in a long-lived way:

    using System;
    namespace HelloWorld
    {
        class Hello
        {
            static void Main()
            {
                Console.WriteLine("Hello World!");
    
                using (var client = new HttpClient())
                {
                    for (...) { ... }  // A really long loop
    
                    // Or you may even somehow start a daemon here
    
                }
    
                // Keep the console window open in debug mode.
                Console.WriteLine("Press any key to exit.");
                Console.ReadKey();
            }
        }
    }
    

    With this new understanding, now we revisit that blog post, we can clearly notice that the "fix" initializes HttpClient once but never dispose it, that is why we can see from its netstat output that, the connection remains at ESTABLISHED state which means it has NOT been properly closed. If it were closed, its state would be in TIME_WAIT instead. In practice, it is not a big deal to leak only one connection open after your entire program ends, and the blog poster still see a performance gain after the fix; but still, it is conceptually incorrect to blame IDisposable and choose to NOT dispose it.

提交回复
热议问题