Verification: a143cc29221c9be0

New bitrix main web httpclient

1. Where can we find the official advocate on reusing HttpClient?

I mean, if reusing HttpClient is intended and doing so is important, such advocate is better documented in its own API documentation, rather than being hidden in lots of "Advanced Topics", "Performance (anti)pattern" or other blog posts out there. Otherwise how is a new learner supposed to know it before it is too late?

As of now (May 2018), the first search result when googling "c# httpclient" points to this API reference page on MSDN, which does not mention that intention at all. Well, lesson 1 here for newbie is, always click the "Other Versions" link right after the MSDN help page headline, you will probably find links to the "current version" there. In this HttpClient case, it will bring you to the latest document here containing that intention description.

I suspect many developers who was new to this topic did not find the correct documentation page either, that's why this knowledge is not widely spread, and people were surprised when they found it out later, possibly in a hard way.

2. The (mis?)conception of using IDisposable

This one is slightly off-topic but still worth pointing out that, it is not a coincidence to see people in those aforementioned blog posts blaming how HttpClient 's IDisposable interface makes them tend to use the using (var client = new HttpClient()) {...} pattern and then lead to the 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.

3. Do we have to put HttpClient into a static property, or even put it as a singleton?

Based on the understanding of the previous section, I think the answer here becomes clear: "not necessarily". It really depends on how you organize your code, as long as you reuse an HttpClient AND (ideally) dispose it eventually.

Hilariously, not even the example in the Remarks section of the current official document does it strictly right. It defines a "GoodController" class, containing a static HttpClient property that will not be disposed; which disobeys what another example in the Examples section emphasizes: "need to call dispose ... so app doesn't leak resources".

And lastly, singleton is not without its own challenges.

"How many people think global variable is a good idea? No one.

How many people think singleton is a good idea? A few.

What gives? Singletons are just a bunch of global variables."

-- Quoted from this inspiring talk, "Global State and Singletons"