Should or should not Httpclient be used within a using block?

Asked

Viewed 348 times

12

Reading this reply, a question relating to the use of using, I was curious about the following statement:

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

The way I’ve seen it HttpClient be used is within a block using.

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

Not knowing for sure if this is what the AR was referring to, I asked him and, through a commenting, he confirmed that yes.

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

The HttpClient should or should not be used within a block using?

  • 2

    At a time when didn’t have that in the documentation, I don’t even know if at first the object had different behavior. There are some things that teach wrong there yet. Microsoft invited me to improve some things, but it’s hard to take care of so much. And I don’t know how much I can really move. The answer here basically says what you need and it’s more important, if I think you need more I’ll give you an answer.

  • 2

    Read on this: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ and this is also useful: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2#typed-clients And I recommend reading this for deeper understanding https://softwareengineering.stackexchange.com/a/370742/389 It may also be useful: https://docs.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/

  • @Maniero Thank you, I’m clear.

  • A question, it is very common nowadays to use dependency injection. In this case, injecting an Httpclient can be a problem? It could better explain how the 'using' and 'Disposis' work in dependency injections?

  • 2

    @Brunowarmling yes, DI is very badly used, in this case it is quite wrong even :)

  • @Brunowarmling why you want to inject an Httpclient?

  • @ramaral test?

  • For example, I have been using Pattern CQRS. In one of my commands, I have Httpclient as a dependency, to consume an API. This Httpclient is in turn created by an Httpclientfactory to include decorators and handle the authentication part of this API. So now reading all this... the question has arisen whether I’m doing it all wrong...

  • @Maniero I see no need. I may be looking bad but the class that uses Httpclient should be subject to integration tests and not unit tests.

  • @ramaral may be, but you don’t see a scenario where you need to mock this class to get it to you without actually using HTTP?

  • @Maniero What you mock is the class that uses Httpclient, so you don’t need it. If the reason of the DI is tests then the injected object has to be mockable, as you would a mock of an Httpclient?

  • @ramaral even agree although I think in cases like this often does not need DI (gives long discussion), but may have some case that needs the nearest level. The mock would be a class with the same API but responding with controlled data instead of connecting.

  • @Maniero This is the definition of mock. My question is how to do it. Httpclient only implements Idisposable, does not expose the "API". So how do you inject it? Whatever the injection method used, an Httpclient type is expected.

  • 1

    @That’s true, he wasn’t even made to think about it. It’s just that I think all this is so wrong that I even tried to find a way to use it so it doesn’t look radical and... I didn’t :D

  • @Maniero Does not give directly. But if you have the necessary commitment, set up an interface with the methods you want to use from Httpclient. Then wrapper over it, implement that interface, and use it instead. However, it’s best to stay radical. :)

  • @Maniero It seems that the question of "how to use" has been solved with Httpclientfactory

Show 11 more comments

2 answers

6

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 for sending HTTP requests. An Httpclient instance is a collection of settings applied to all requests executed by that instance. In addition, each instance of Httpclient uses its own connection pool, isolating its requests from requests executed by other instances of Httpclient.

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

  • 1

    I thought it was curious how few votes I had, OK, just me and the AP, but maybe the end is to blame for this. Gives a little the impression that you can use several objects and then go dispensing with using, and even technically can even, but it’s wrong. That’s the only caveat I make.

  • 2

    @Maniero was about to comment on something like that. The second vote is not mine and that is the reason. I don’t think the answer completely answers the question. It is necessary to explain why you only use one instance or the consequences of repeatedly using Httpclient within a block using,

  • 1

    @in the end I thought it really leaves to be desired, but I can not take the vote :(

6


The big problem is precisely that it is misleading. By having implemented the interface IDisposble everyone thinks they should use the using. And I don’t know if in the first implementation of this class I didn’t need, what I do know is that the documentation initially said nothing of this, or because it taught wrong or because it was like this before (you can’t trust 100% documentation, something close to this can, but it never gives all the details).

It makes sense to have this interface in this class because it may actually have reasons for at some point the resource linked to this object being discarded. But the most common use is that it lasts the entire application.

Think about the object, starting with the name. People think of it as a connection but it is a client. How many HTTP clients do you need in your application? One, right? What for? It’s a mechanism, it’s like a file system, You don’t have to have more than one. The fact that you have only one does not mean that you can only make a request, it being there can order whenever you want, as long as you have access to the object.

For some reason there’s nothing static about him like file system, probably because the customer is little heavy and creating will always be something expensive for most applications, while creating every time it needs is too costly (which is the mistake that "everyone" makes).

In the correct form it is very common that this object is 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 that the field was static. Unless in a very simple example it does not seem appropriate to create in the main class, should have a class with responsibility to take care of it, but there is a mistake of use of the HttpClient but organization of the code.

I learned that if the class has IDisposable always use using

It is not so, it must in methods, that is, when the object must be created locally. And this must be relative, also have cases not to use, although probably has better way to do.

There are cases that you can create the object there, return it and then the object must retain the resource linked to it, so it is not there that will use the using, but will probably use it elsewhere for liberation to be made. Luckily you don’t see it out there, but it is 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 stored within a class through a field and not a local variable. In this case there is no way to use the using what you’ll have to do is at some point call the Dispose() of that 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 practically forces this class to implement the IDisposable, is viral. Then an object of this class will probably be placed in a using.

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

In some cases it must be even in a static field which can dispense this class go through some destruction.

The lifespan necessary for the object will determine where and whether the using.

You can never use the using in that class?

It can, if you know that your application will only use the HTTP client there once or a very limited amount, then better not to. And I’m not saying it’s the same. It’s worse to do this more than once, it only makes sense if it’s once, at all times of execution. In fact in a scenario like this is better with the using, but it’s rare to have such a scenario.

What goes wrong if you do it like this?

He will create sockets on the operating system. It is unclear why but it does not seem to release immediately and so an hour may run out sockets free. Or even if this does not occur each socket new spent resources on the machine.

There’s 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 in 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 it happening a thousand 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");
    }
}

I put in the Github for future reference.

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 tests, the object and resource will be discarded at the end of the application that is when we want, but there are cases that need a more sophisticated control. Don’t always think this shape is the most suitable for your case, so it is necessary to learn how to do things broadly and not just decorate cake recipes.

Completion.

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

The problem is that in the past the documentation did not say that life time should probably be the same as the whole application.

Some recommended readings:

  • 1

    "I learned that if the class has Idisposable it should always use using" - Having a teacher to teach you is good, but there are some advantages to not having. Not having a teacher allowed me to gather knowledge from various sources. From this collection "I learned that if the class has Idisposable should call Dispose()". Whether we have a teacher or not, the important thing, when we learn, is to always have a critical and "suspicious" attitude, in the good sense, in relation to what we read and tell us. (...)

  • (...) Despite this, I was caught by the phenomenon of "what is repeated over and over again is true/correct", I was one of those who misused Httpclient.

  • It’s like the Random only that this does not implement IDisposable and cheat less :)

  • Yoke which is referring to Random always returning the same number

  • That’s right.....

  • "the object and resource will be discarded at the end" The object yes, the appeal no. Right?

  • Both, when the application closes everything is discarded. It may not be by. NET (I don’t know how it is) but one way or another it will be discarded because nothing the application started can survive after its end.

  • Won’t the connection be open(ESTABLISHED)? See the last paragraph of the point 2. The (mis?)conception of using Idisposable.

  • 1

    @ramaral I will not state that kills at the time the application closes, I even think there is a kind of event that the end of the application sends to close this (internal thing of the operating system), and if it does not should do, but even in this case would still have a closure by timeout or something like that, there’s no way to be left hanging without an owner. If you stayed it would be bug and not by design.

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.