Should the HttpClient, or should it not, be used within a using block?

While reading this answer, to a question related to the use of using, I was curious about the following statement:

In fact everyone uses HttpClient Wrong, I already used it myself and did not know everything, because I trusted that the documentation had everything I needed, but I learned the lesson.

The way I have seen HttpClient be used is within a block using.

using (var http = new HttpClient())
{
    //
}

Not knowing for sure if it was the this what the air was referring to, I asked him and, through a comment , he confirmed that yes.

Since the comment was not sufficiently enlightening, then the question remains:

Should

Or should HttpClient not be used within a using block?

Author: Maniero, 2019-11-21

2 answers

The big problem is precisely that it is misleading. For having implemented the IDisposble interface everyone thinks they should use using. And I do not know if in the first implementation of this class I did not need, what I know is that the documentation initially did not speak anything of this, either because it taught wrong or because before it was so (can not rely 100% on documentation, something close to this can, but it never gives all details).

Does it make any sense to have this interface in this class because in fact it may have grounds for at some point the resource bound to this object to be discarded. But the most common in the correct use is that it lasts the entire application.

Think Well of the object, starting with the name. People think of him as a connection but he's a customer. How many HTTP Clients do you need in your application? One, right? For what others? It's a mechanism, it's like a file system, it doesn't have to have more than one. The fact that you have one does not mean that you can only make one request, being there you can request whenever you want, as long as you have access to the object.

For some reason there is something static in it like the file system , probably because the client is little heavy and creating will always be something expensive for most applications, while creating every time it needs is too expensive (which is the error that "everyone" makes).

In the correct form it is very common for this object to be placed in a static field, so creates once, possibly in the first effective use, and no longer need, then just use.

The example of the other answer is not very good because it was written anyway. I imagine the intention there was for the field to be static. Unless in a very simple example it does not seem appropriate to create in the main class, it should have a class with responsibility to take care of this, but there is not an error of use of HttpClient but of Organization of the code.

I learned that if the class has IDisposable it should always use using

Is not quite so, should in methods, i.e. when the object should be created locally. And this should be relative, it also has cases not to use, although it probably has a better way to do.

There are cases that you can create the object there, return it and then the object must retain the resource bound to it, so it's not there that using will use it, but it will probably use it elsewhere so that the release be made. Luckily you don't see it out there, but it's something that can exist and even be useful in some scenario. Something like this:

void Metodo() {
    ...
    using (var arquivo = CriaRecurso()) { ... }
    ...
}

FileStream CriaRecurso() {
    ...
    var file = new FileStream("abc.txt", FileMode.Create)
    ...
    return file;
}

In addition it may be that the object with the resource can be saved within a class through a field and not a local variable. In this case you have no way to use the using what you will have to do is at some point call the Dispose() of this object. This can be through a destructor/Finalizer method that every object has or through a Dispose() created in this class, so if you use an object that is IDisposable in a field pretty much forces that class to implement IDisposable, it's viral. Then an object of this class will probably be placed in a using.

It's rarer to do this, but I've seen several scenarios you need. If people did so much code would be optimized when there are gains.

In some cases it must be even in a static field that can dispense this class to pass through some destruction.

The Life Time required for the object will determine where and whether to have the using.

Can't you ever use using in this class?

Can, if you know that your application will only use the HTTP client ali a single time or a very limited amount, then better not to do. And I'm not saying it does anyway. It is worse to do this if it is more than once, it only makes sense if it is even once, at every runtime. In fact in such a scenario it is better with using, but it is rare to have such a scenario.

What goes wrong if you do this?

It will create sockets in the operating system. It is not clear why but it does not seem to release immediately and so an hour can run out of free sockets. Or even if this does not occur every new socket spends resources on the machine.

There is a page that shows this with property :

using static System.Console;
using System.Net.Http;

public class Program {
    public static async Task Main() {
        WriteLine("Starting connections");
        for (int i = 0; i<10; i++) {
            using (var client = new HttpClient()) {
                var result = await client.GetAsync("http://aspnetmonsters.com");
                WriteLine(result.StatusCode);
            }
        }
        WriteLine("Connections done");
    }
}

This works and produces this:

C:\code\socket> dotnet run
Project socket (.NETCoreApp,Version=v1.0) will be compiled because inputs were modified
Compiling socket for .NETCoreApp,Version=v1.0

Compilation succeeded.
    0 Warning(s)
    0 Error(s)

Time elapsed 00:00:01.2501667


Starting connections
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
Connections done

But investigating the operating system see what happened:

C:\code\socket>NETSTAT.EXE
...
  Proto  Local Address          Foreign Address        State
  TCP    10.211.55.6:12050      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12051      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12053      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12054      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12055      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12056      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12057      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12058      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12059      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12060      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12061      waws-prod-bay-017:http  TIME_WAIT
  TCP    10.211.55.6:12062      waws-prod-bay-017:http  TIME_WAIT
  TCP    127.0.0.1:1695         SIMONTIMMS742B:1696    ESTABLISHED
...

Bad, right? Imagine this happening thousands of times.

using static System.Console;
using System.Net.Http;

public class Program {
    private static HttpClient Client = new HttpClient();
    public static async Task Main() {
        WriteLine("Starting connections");
        for (int i = 0; i<10; i++) {
            var result = await client.GetAsync("http://aspnetmonsters.com");
            WriteLine(result.StatusCode);
        }
        WriteLine("Connections done");
    }
}

The result is the same but now the operating system reports only one socket.

Note that this is ok because it is an example only for testing, the object and resource will be discarded at the end of the application that is when we want it, but there are cases that need more control sophisticated. Do not think that always this form is the most suitable for your case, for this it is necessary to learn to do things broadly and not just decorate cake recipes.

Conclusion.

We need to understand everything about what we are going to use. Often it is not enough to read the official documentation, have to look for other documents, question. Programming is difficult, even trying to do everything right can still give something wrong.

The problem is that in the past the documentation it did not say that the lifetime should probably be the same as the entire application.

Some recommended readings:

 5
Author: Maniero, 2020-06-11 14:45:34
HttpClient client = new HttpClient();

    static async Task Main()
    {
      try   
      {
         HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
         response.EnsureSuccessStatusCode();
         string responseBody = await response.Content.ReadAsStringAsync();

         Console.WriteLine(responseBody);
      }  
      catch(HttpRequestException e)
      {
         Console.WriteLine("\nException Caught!");  
         Console.WriteLine("Message :{0} ",e.Message);
      }
    }

The instance of the HttpClient class acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, each HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.

According to the documentation found in Microsoft, when there is a single instance of HttpClient for the whole application the ideal is not to use the " using {}", otherwise it is important to use the" using {} " when there is more than one instance of HttpClient.

 5
Author: Adjair Costa, 2019-11-21 17:14:38