Explain how to use IHttpClientFactory in ASP. NET Core

  • 2021-11-24 01:16:00
  • OfStack

IHttpClientFactory allows you to create HttpClient instances seamlessly, avoiding manually managing their lifecycle.

When developing applications using ASP. Net Core, it may often be necessary to call the methods of WebAPI through HttpClient to check that the endpoint is working properly. To achieve this point, you usually need to instantiate HttpClient and use this instance to call your method. However, using HttpClient directly also has one drawback, which is mainly related to manually managing the life cycle of the instance.

You can use IHttpClientFactory to create HttpClient to avoid these problems. Introduced in. Net Core 2.1, IHttpClientFactory provides a core function for naming, configuring, and creating HttpClient instances, and automatically manages the pooling and lifecycle of instances.

Let's go one step further through the code to discuss HttpClient and IHttpClientFactory, and the design concepts. To use the provided code, you need to install Visual Studio 2019.

Create an ASP. NET Core MVC project in Visual Studio 2019

Assuming you have Visual Studio 2019 installed on your system, follow the steps listed below to create a new ASP. NET Core project.
1. Start Visual Studio IDE.
2. Click Create New Project.
3. In the Create New Project window, select the ASP. NET Core Web application from the template list.
4. Click Next.
5. In the Configure New Project window, specify the name and location of the new project.
6. You can select the "Place solutions and projects in the same directory" check box.
7. Click Create.
8. In the "Create a new ASP. NET Core Web application" window, select. NET Core as the runtime, and then select asp. net Core as the runtime. NET Core 3.1 (or later).
9. Select "Web Application (Model-View-Controller)" as the project template to create a new ASP. NET Core MVC application.
10. Make sure that the check boxes "Enable Docker support" and "Configure HTTPS" are not selected, because we will not use these features here.
11. Make sure that authentication is set to No Authentication, because we will not use authentication either.
12. Click Create.

Following these steps will create a new ASP. NET Core MVC application. In the new project, create a new API Controller and save it with the default name, ValuesController. We will use this project in the next section.

Challenge HttpClient

Although HttpClient does not directly implement the IDisposable interface, it extends System. Net. Http. HttpMessageInvoker, which implements IDisposable. However, when using HttpClient instances, you should not release them manually. Although you can call the Dispose method on an HttpClient instance, this is not recommended.
What should be done? One option is to make HttpClient static, or to wrap a non-static instance of HttpClient in a custom class and make it a singleton class. But a better alternative is to use IHttpClientFactory to generate an instance of HttpClient and then use that instance to invoke the operation method.

IHttpClientFactory and HttpClientFactory

IHttpClientFactory is an interface implemented by the DefaultHttpClientFactory class, which is a factory pattern. DefaultHttpClientFactory implements the IHttpClientFactory and IHttpMessageHandlerFactory interfaces. IHttpClientFactory provides ASP. NET Core provides excellent built-in support for creating, caching, and processing HttpClient instances.
Note that HttpClientFactory is just a helper class for creating an instance of HttpClient using the provided handler configuration. This class has the following methods:


Create(DelegatingHandler[])
Create(HttpMessageHandler,DelegatingHandler[])
CreatePipeline(HttpMessageHandler,IEnumerable<DelegatingHandler>)

The Create method of the overloaded HttpClientFactory class looks like this:


public static HttpClient Create(params DelegatingHandler[] handlers)
{
 return Create(new HttpClientHandler(), handlers);
}
public static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
{
 HttpMessageHandler pipeline = CreatePipeline(innerHandler, handlers);
 return new HttpClient(pipeline);
}

HttpClientFactory and IHttpClientFactory were introduced to better manage the lifecycle of HttpMessageHandler instances.

Why use IHttpClientFactory?

When you release the HttpClient instance, the connection will remain open for up to 4 minutes. In addition, there is a limit to the number of sockets that can be opened at any point in time-you cannot open too many sockets at the same time. Therefore, when too many HttpClient instances are used, socket may be exhausted.
This is the meaning of IHttpClientFactory. You can avoid the problems faced by HttpClient by using IHttpClientFactory to create an HttpClient instance that calls the HTTP API method. The primary goal of implementing IHttpClientFactory in ASP. NET Core is to ensure that HttpClient instances are created in factory mode while avoiding socket exhaustion.

Register an IHttpClientFactory instance in ASP. NET Core

You can register an instance of IHttpClientFactory in the ConfigureServices method of the Startup class by calling the AddHttpClient extension method on the IServiceCollection instance, as follows:


public void ConfigureServices(IServiceCollection services)
{
  services.AddControllersWithViews();
  services.AddHttpClient();
}

Injecting an IHttpClientFactory instance into the controller

The IHttpClientFactory instance can be injected into the controller with the following code:


public class HomeController : Controller
{
   private IHttpClientFactory _httpClientFactory;
   private readonly ILogger<HomeController> _logger;
   public HomeController(ILogger<HomeController> logger,
   IHttpClientFactory httpClientFactory)
   {
      _logger = logger;
      _httpClientFactory = httpClientFactory;
   }
}

Calling HttpClient in Action

To create an HttpClient by using IHttpClientFactory, you should call the CreateClient method. 1 Once an HttpClient instance is available, you can call the Get method of the ValuesController class using the following code in the index method of the HomeController class.


public async Task<IActionResult> Index()
{
  HttpClient httpClient = _httpClientFactory.CreateClient();
  httpClient.BaseAddress = new Uri("http://localhost:1810/");
  var response = await httpClient.GetAsync("/api/values");
  string str = await response.Content.ReadAsStringAsync();
  List<string> data = JsonSerializer.Deserialize<List<string>>(str);
  return View(data);
}

Using IHttpClientFactory to create and manage HttpClient instances in ASP. NET Core

There are several ways to use IHttpClientFactory in your application. This includes using IHttpClientFactory directly, using the named client and the type client.
The basic or 1-type usage pattern, that is, using IHttpClientFactory directly-has been discussed in the previous section. Please refer to section 1, "Registering an IHttpClientFactory instance", which discusses how to register an HttpClient instance.

If you want to use HttpClient instances with different configurations, here is a good choice. The following code snippet shows how to create.


services.AddHttpClient("github", c =>
{
  c.BaseAddress = new Uri("https://api.github.com/");
  c.DefaultRequestHeaders.Add("Accept",
  "application/vnd.github.v3+json");
  c.DefaultRequestHeaders.Add("User-Agent", "This is a test user agent");
});

The second approach is to use a custom class that wraps the HttpClient instance, which encapsulates the logic to invoke all endpoints through the HTTP protocol. The following code snippet shows how to define a custom HttpClient class.


public class ProductService : IProductService
{
  private IHttpClientFactory _httpClientFactory;
  private readonly HttpClient _httpClient;
  private readonly string _baseUrl = "http://localhost:1810/";
  public ProductService(HttpClient httpClient)
  {
    _httpClient = httpClient;
  }
  public async Task<Catalog> GetAllProducts()
  {
    _httpClient = _httpClientFactory.CreateClient();
    _httpClient.BaseAddress = new Uri(_baseUrl);
    var uri = "/api/products";
    var result = await _httpClient.GetStringAsync(uri);
    return JsonConvert.DeserializeObject<Product>(result);
  }
}

Register the custom client with the following code:


services.AddHttpClient<IProductService, ProductService>();

Adding MessageHandler to a named pipe

MessageHandler is an extension of the HttpMessageHandler class that accepts an HTTP request and returns an HTTP response. If you want to build your own MessageHandler, you should create a class that inherits DelegatingHandler.

You can add HttpMessageHandler to the request processing pipeline. You can add HttpMessageHandler to the pipeline using the following code in the ConfigureServices method of the Startup class.


public void ConfigureServices(IServiceCollection services)
{
  services.AddHttpClient("github", c =>
  {
    c.BaseAddress = new Uri("https://api.github.com/");
  })
  .AddHttpMessageHandler<DemoHandler>();
  services.AddTransient<DemoHandler>();
}

IHttpClientFactory is a factory class that has been available since. net Core 2.1. If you use IHttpClientFactory to create an HttpClient instance, the pooling and lifecycle of the underlying HttpClientMessagehandler instance will be automatically managed. IHttpClientFactory also handles some common problems, such as logging.


Related articles: