2

I have a web application that pulls data from an API using the HttpClient class. I have a few questions.

  1. Is HttpClient optimal for getting data from API? I get a string from APi and deserialize it into an object.
  2. A new instance of HttpClient is created each time it is used (for each user). Is it best to use: using (HttpClient client = new HttpClient()) for each request?

Try to find best and optimal solution.

Tsko
  • 33
  • 6

2 Answers2

5
  1. Yes, HttpClient is certainly appropriate for using web APIs and deserialization.

  2. Creating a new HttpClient for each request is not a good usage. The recommended way is to create HttpClient objects using the IHttpClientFactory interface. Here is a basic usage from MSDN:

     class TodoService
     {
         private readonly IHttpClientFactory _httpClientFactory = null!;
         private readonly ILogger<TodoService> _logger = null!;
    
         public TodoService(
             IHttpClientFactory httpClientFactory,
             ILogger<TodoService> logger) =>
             (_httpClientFactory, _logger) = (httpClientFactory, logger);
    
         public async Task<Todo[]> GetUserTodosAsync(int userId)
         {
             // Create the client
             using HttpClient client = _httpClientFactory.CreateClient();
    
             try
             {
                 // Make HTTP GET request
                 // Parse JSON response deserialize into Todo types
                 Todo[]? todos = await client.GetFromJsonAsync<Todo[]>(
                     $"https://jsonplaceholder.typicode.com/todos?userId={userId}",
                     new JsonSerializerOptions(JsonSerializerDefaults.Web));
    
                 return todos ?? Array.Empty<Todo>();
             }
             catch (Exception ex)
             {
                 _logger.LogError("Error getting something fun to say: {Error}", ex);
             }
    
             return Array.Empty<Todo>();
         }
     }
    

    }

You can refer to IHttpClientFactory with .NET and Guidelines for using HttpClient

Mustafa Özçetin
  • 1,893
  • 1
  • 14
  • 16
  • You're not incorrect ... but you should *ALSO* mention how the app can *INVOKE* the IHttpClientFactory. Here's a good tutorial illustrating one method (register the service, and use Dependency Injection): https://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core – paulsm4 Apr 06 '23 at 20:23
  • You are right but my first link already shows how to register the `IHttpClientFactory`. Your tutorial is better though. – Mustafa Özçetin Apr 06 '23 at 20:27
  • So each time a request is made, a new instance of the class to work with the API will be created, but the Httpclient instances will be maintained by the IHttpClientFactory ? And IHttpClientFactory will be created using DI. – Tsko Apr 06 '23 at 21:05
  • 1
    @Tsko: like beautifulcoder said, although you can create a new HttpClient for each request, it's *MEANT* to be used as a [singleton](https://dotnetcoretutorials.com/2019/06/11/singleton-pattern-in-net-core/). In general, an application manages singletons with a "Factory". Mustafa Özçetin illustrates how to do all this as an ASP.Net "Service". The client will presumably get (the single instance) of the `TodoService` from dependency injection, then call `TodoService.GetUserTodosAsync()` on that instance. – paulsm4 Apr 06 '23 at 22:40
  • You'll notice that TodoService could get IHttpClientFactory from Dependency Injection too (via the constructor parameter). – paulsm4 Apr 07 '23 at 00:27
2
  1. Yes, you can also set HTTP headers to compress the data to optimize payload size assuming gzip/brotli are available.

  2. The HttpClient is not meant to be instantiated per use. But, it is designed to be a singleton. Every instance opens up sockets at the OS level. Once .NET disposes of the instance it takes a bit for sockets to completely close so creating too many instances can choke the server making HTTP requests via HttpClient.

beautifulcoder
  • 10,832
  • 3
  • 19
  • 29
  • So.. one static HttpClent will work? Or must be singleton as it should be..? – Tsko Apr 06 '23 at 20:31
  • @Tsko MS docs is very clear that if you instantiate multiple clients then you will exhaust your connection pool. It should be one static HttpClient in the class, most likely it can also be `readonly` and init inline/the constructor, and you will use that instance for the class. Or use the factory `IHttpClientFactory` – Narish Apr 06 '23 at 20:41
  • Ok, i will try both ways... – Tsko Apr 06 '23 at 20:53