Reusing HttpClient with Dependency Injection

Full source code available here.

If you are using HttpClient to make requests for you, you might have come across some articles discussing how to reuse HttpClient. They strongly advocate for using a single HttpClient for as many requests as possible, i.e. not creating a new HttpClient for every request. Not having to create/dispose of the HttpClient for every request should improve the performance of you application. One estimate states that every time you instantiate a HttpClient takes 35ms.

In this article I will show you how to use dependency injection to reuse the HttpClient in .Net Core, but the same principle applies in Framework 4.x applications.

The one advantage of creating a new HttpClient for every request is that you don’t need to worry about the DNS record of an endpoint changing during the lifetime of the application, this is common if you are swapping staging and production instances during a deployment. But this is easyly(ish) handled by the ServicePointManger.

Adding HttpClient to the DI Container

In Startup.cs add the below lines.

 1public void ConfigureServices(IServiceCollection services)
 2{
 3    Uri endPointA = new Uri("http://localhost:58919/"); // this is the endpoint HttpClient will hit
 4    HttpClient httpClient = new HttpClient()
 5    {
 6        BaseAddress = endPointA,
 7    };
 8
 9    ServicePointManager.FindServicePoint(endPointA).ConnectionLeaseTimeout = 60000; // sixty seconds
10
11    services.AddSingleton<HttpClient>(httpClient); // note the singleton
12    services.AddMvc();
13}

This approach is ideal if you have a limited number of endpoints and you know them at application startup. If you don’t know then endpoints at startup you can add the call to ServicePointManager where you HttpClient requests occur.

Using the HttpClient

Now I have the HttpClient registered with the Dependency Injection container, let’s take a look at the controller that uses it to make a request. See the inline comments.

 1public class ValuesController : Controller
 2{
 3    private readonly HttpClient _httpClient; // declare a HttpClient
 4
 5    public ValuesController(HttpClient httpClient) // this is the singelton instance of HttpClient
 6    {
 7        _httpClient = httpClient; // assign it to the local HttpClient
 8    }
 9
10    // GET api/values
11    [HttpGet]
12    public async Task<IActionResult> Get()
13    {
14        string requestEndpoint = "api/products";
15
16        HttpResponseMessage httpResponse = await _httpClient.GetAsync(requestEndpoint); // make request
17        List<Product> products = await httpResponse.Content.ReasAsJsonAsync<List<Product>>();
18        return Ok(products);
19    }
20}
 
Full source code available here.

comments powered by Disqus

Related