12

I've got a .Net Core project that needs to connect to around 4 different API services, I'm no expert with any of the HttpClient code, but from what I found, was that you'd generally only want to reuse one instance of your HttpClient. From what I can tell the general consensus is to use the HttpClientFactory in .Net Core by registering it in your Startup class and then requesting it using DI.

Now most of my default headers and such are all generally the same besides the BaseAddress url, how should I go about this when connecting to 4 diff API services? Should I register 4 different named clients or have one client with all the default information pre-set and then manually configure it as needed e.g. configuring the address?

General questions would be as I'm fairly new to this is, it's been said to re-use one instance of an HttpClient.

  1. If I create 4 different named clients for each API service, wouldn't this create 4 instances of the HttpClient when I call the .CreateClient() method?
  2. The .CreateClient() creates a new instance every time it's called, doesn't this defeat the purpose of having one instance of the HttpClient if say I need to make 3 different calls to one API service, each of those calls will call a .CreateClient() to establish some sort of connection and that will create 3 instances of the HttpClient?

Any help for clarity would be appreciated,

Thanks!

6
  • 3
    You have a few options, just register for IHttpClientFactory, and add the headers when you call factory.CreateClient(), or create a named client with the headers you need, and use factory.CreateClient("namedclient") both are extremely easy to do and which one you choose would have little difference on anything Commented Sep 9, 2020 at 23:32
  • 4
    Take a look at the docs on IHttpClientFactory Consumption Patterns. Generated clients with Refit are a very simple solution, if you don't mind using a third-party library. Otherwise, named or typed clients would work as well Commented Sep 9, 2020 at 23:40
  • 1
    @MichaelRandall Ahh okay, what about when actually calling the factory.CreateClient() every time I need to make an api call i'd assume we have to call that. Wouldn't that create multiple httpclient instances or would an If() check be necessary and check if the httpClient is null then create otherwise just return it? I'm just not entirely understanding how this fixes the issues of re-using one instance of the HttpClient? Commented Sep 10, 2020 at 0:07
  • 3
    IHttpClientFactory was a rebuild to all the problems a regular HttpClient used to have. In short you can safely call CreateClient as many times as you want and its all taken care-of for you under the hood (in fact its recommended, unless you have a very specific use case), there is no need to cache the client, and all resulting clients are thread safe. Commented Sep 10, 2020 at 0:10
  • 1
    From the IHttpClientFactory.CreateClient documentation remarks: Each call to CreateClient(String) is guaranteed to return a new HttpClient instance. Callers may cache the returned HttpClient instance indefinitely or surround its use in a using block to dispose it when desired. The default IHttpClientFactory implementation may cache the underlying HttpMessageHandler instances to improve performance. Callers are also free to mutate the returned HttpClient instance's public properties as desired. (emphasis mine). Commented Sep 10, 2020 at 0:13

1 Answer 1

9

The purpose of using IHttpClientFactory is not to reuse instances of HttpClient. Instead, it is to reuse (by pooling) instances of HttpMessageHandler (actually HttpClientHandler, which is derived from the abstract HttpMessageHandler) that is the underlying object that manages HTTP connections & sockets. This diagram from Microsoft Docs shows it well.

You were worried that frequent calls to IHttpClientFactory.CreateClient() will create the same problem as frequent calls to new HttpClient(). However, this is not the case. As explained by Microsoft docs, the reason that frequent calls to new HttpClient() will result in socket exhaustion is that this constructor will create a new instance of HttpMessageHandler:

However, the issue isn't really with HttpClient per se, but with the default constructor for HttpClient, because it creates a new concrete instance of HttpMessageHandler, which is the one that has sockets exhaustion and DNS changes issues mentioned above.

You can see from the source code of IHttpClientFactory that it does not use the parameterless constructor of HttpClient in CreateClient(). Instead, it gets the HttpMessageHandler from a pool and inject it into the created HttpClient.

Whether you are using typed or named clients, you should use the HttpClient instance as if it's a transient object: it is cheap to create and you don't need to cache it for long periods of time.

Sign up to request clarification or add additional context in comments.

2 Comments

@scarnyw What if one would pass 'factory.CreateClient()' as argument to a method in a "helper" class lib? Instead of register that class lib as a service in the DI container?
Since .NET Core 2.1, the default message handler used by HttpClient is actually SocketsHttpHandler, not HttpClientHandler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.