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
The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.
AddHttpClient(IServiceCollection) Adds the IHttpClientFactory and related services to the IServiceCollection. AddHttpClient(IServiceCollection, String) Adds the IHttpClientFactory and related services to the IServiceCollection and configures a named HttpClient.
IHttpClientFactory is a contract implemented by DefaultHttpClientFactory , an opinionated factory, available since . NET Core 2.1, for creating HttpClient instances to be used in your applications.
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 that.
This means that you're not managing the lifetime of the HttpClient
. The ServiceProvider
is doing that behind the scenes.
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:
CaptchaHttpClient
is transient so that each time it's resolved, a new instance is created.HttpClient
is created and injected. 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.
I found this article helpful in furthering my understanding of IHttpClientFactory
patterns.
When defining typed clients in your ConfigureServices method, the typed service is registered with transient scope. This means that a new instance is created by the DI container every time one is needed. The reason this occurs is that a [sic] HttpClient instance is injected into the typed client instance. That HttpClient instance is intended to be short lived so that the HttpClientFactory can ensure that the underlying handlers (and connections) are released and recycled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With