Search code examples
c#.netasp.net-core-mvcnopcommerce

When using services.AddHttpClient, where is the HttpClient created?


I am trying to understand how HttpClient has been implemented for Captcha in Nop Commerce and for the sake of testability how creating new instance of HttpClient has been manage in Nop Commerce project.

I came across ValidateCaptchaAttribute and ValidateCaptchaFilter and I see HttpClient has been wrapped inside CaptchaHttpClient class but I don't understand from where does CaptchaHttpClient receive dependency for HttpClient and from where constructor of CaptchaHttpClient class is being called.

Inside ServiceCollectionExtensions class I see below code:

public static void AddNopHttpClients(this IServiceCollection services)
 {
    //default client
    services.AddHttpClient(NopHttpDefaults.DefaultHttpClient).WithProxy();

    //client to request current store
    services.AddHttpClient<StoreHttpClient>();

    //client to request nopCommerce official site
    services.AddHttpClient<NopHttpClient>().WithProxy();

    //client to request reCAPTCHA service
    services.AddHttpClient<CaptchaHttpClient>().WithProxy();
 }

But I don't see where HttpClient object is created:

var client = new HttpClient() // Where this is done?

Am I perhaps missing something?

Nop Commerce Version = 4.20


Solution

  • From the documentation:

    Adds the IHttpClientFactory and related services to the IServiceCollection and configures a binding between the TClient type and a named HttpClient. The client name will be set to the type name of TClient.

    Roughly translated, services.AddHttpClient<CaptchaHttpClient>() means that CaptchaHttpClient has a dependency on HttpClient. This says that when injecting HttpClient into CaptchaHttpClient, don't just create a new one - use an implementation of IHttpClientFactory to provide one and inject the HttpClient it creates.

    This means that you're not managing the lifetime of the HttpClient. The ServiceProvider is doing that behind the scenes. (You're not responsible for creating the client factory either.)

    This documentation explains why this exists and how it works.

    A Typed Client is, effectively, a transient object, meaning that a new instance is created each time one is needed and it will receive a new HttpClient instance each time it's constructed. However, the HttpMessageHandler objects in the pool are the objects that are reused by multiple Http requests.

    This means:

    • The thing you're registering - in this case CaptchaHttpClient is transient so that each time it's resolved, a new instance is created.
    • Each time it is created, a new HttpClient is created and injected.
    • Although the HttpClient is new, the HttpMessageHandler it depends upon is reused.

    This uses a pool of HttpMessageHandler instances that we don't have to manage. Our class just depends on HttpClient without having to worry about the negative side effects that happen when we create/dispose an HttpClient each time we need one.