0

Im in the process of creating a base class for typed HttpClient services (yes, I'm utilizing IHttpClientFactory). I wrote the process in such a way that for each CRUD method invoked from the service, the first thing said service does is check for and assign an access token to attach to the HttpClient header. Example:

public abstract class BaseNetworkService : IBaseNetworkService {
   protected HttpClient _httpClient { get; }

   public BaseNetworkService(HttpClient client, ...) {
      _httpClient = client;
   }
   
   public async Task<T> GetAsync<T>(string extendedUrl, ICacheContext cacheContext = null) {
      ... check Redis Cache, return result if there ...
      
      Http client = GetcurrentAccessToken(_httpClient);
      var response = await client.GetAsync(extendedUrl);
      ...
   }
}

I'll admit upfront that I am not entirely sure why I have always made my HttpClients readonly and upon Googling for answers, it's probably because every document and guide on HttpClient with dependency injection makes the client readonly. I didn't find any material explaining the reason for that.

With that in mind, should your HttpClientremain readonly? Should any customization, such as attaching an access token, be done in the classes constructor?

1
  • 6
    The readonly keyword does not prevent you from mutating the client. It prevents you from replacing the client.
    – John Wu
    Nov 14 '20 at 0:57
3

The readonly keyword does not prevent mutability of an object. It only makes sure that you do not replace it by doing myReadonlyObject = new Object().

As for why your HttpClient is readonly - because there is no need to ever replace it with a new HttpClient. In fact, in case of HttpClient, you should be aiming to reuse it, instead of creating a new client for each web request. That is how HttpClient was designed to be used.

The reason for that is, that even after your request went through, you got the response and the connection was closed, the underlying socket still stays open and listens for any packets that might have been delayed in the network traffic. This is obviously not a huge deal if the application only makes a couple of requests and is done. However it might become a bigger issue when we make tens of thousands requests in relatively short amount of time and use a new instance of HttpClient for each request, since the amount of sockets that can be open at once is limited by the OS.

9
  • ` Http client = GetcurrentAccessToken(_httpClient);` So this would leave an underlying socket open?
    – 8protons
    Nov 15 '20 at 19:08
  • @8protons Yes, for a while. In Windows it's around 4 minutes. So ideally you would not create new HttpClients, and instead reuse one instance of it throughout the whole application run time to avoid having too many open sockets.
    – Aleksander
    Nov 15 '20 at 20:32
  • Just to add to this, HttpClient is an awful footgun as this excellent blog post from 2016 shows ( aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong ). Ive personally seen this happen in production, and it is awful to troubleshoot. Always reuse one instance of it if you use it. Or use some of the other http client libraries on .net that doesnt have this awful design built in.
    – wasatz
    Nov 16 '20 at 7:07
  • @Aleksander Are you sure? Because the initial http client is managed watched by IHttpClientFactory. When I created a new instance and closed the original, the clone seemed to close as well.
    – 8protons
    Nov 16 '20 at 17:43
  • @8protons How and where are you creating a new instance?
    – Aleksander
    Nov 16 '20 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.