When building an application with ASP.NET, an instance of the HttpClient class is used to make an HTTP request. Using HttpClient may seem simple. However, some potential issues are not noticed until the application is under heavy load.
Issues related to the original HttpClient class provided in .NET:The hyperlink login is visible.
HttpClient, while implementing IDisposable, declaring and instantiating it in the using statement is not a preferred operation, becauseWhen releasing an HttpClient object, the underlying socket does notinstantlyrelease, which can cause socket exhaustion issues.
The problem is not really HttpClient itself, but the default constructor of HttpClient, as it creates a new actual HttpMessageHandler instance with the "socket exhaustion" and DNS change issues mentioned above.
Creating HttpClient directly (incorrect use)
Instantiate the HttpClient object directly, and add using to guarantee the call to the Dispose method, the code is as follows:
Call the interface 5 times, send an HTTP request using HttpClient, and check the network connection with the following command:
You can see that when the HttpClient is released, the connection between the local computer and the target server isTIME_WAITIn the case of high concurrency, the error will be reported as follows:
Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
For questions, you can also refer to:
Create an HttpClinet with IHttpClientFactory (correct usage)
Using DI dependency injection IHttpClientFactory is the same as HttpLinet, which is created using IHttpClientFactory.
Add the service to the Startup file, the code is as follows:
The HomeController controller code is as follows:
We also use HttpClinet to send 5 requests through the call interface, and the machine only establishes a connection with the target server, and the connection is reused during the request process. As shown below:
IHttpClientFactory pools factory-created HttpMessageHandler instances into a pool to reduce resource consumption. When you create a new HttpClient instance, you may reuse the HttpMessageHandler instance in the pool if the lifetime has not expired.
{ "Lifetime": "Singleton", "ServiceType": "System.Net.Http.IHttpClientFactory", "ImplementationType": "Microsoft.Extensions.Http.DefaultHttpClientFactory" }, { "Lifetime": "Singleton", "ServiceType": "System.Net.Http.IHttpMessageHandlerFactory", "ImplementationType": "Microsoft.Extensions.Http.DefaultHttpClientFactory" } IHttpClientFactory is implemented by default as DefaultHttpClientFactory, with the source code address:The hyperlink login is visible.
By using IHttpClientFactory in a DI-enabled application, you can avoid:
- Solve the problem of resource exhaustion by sharing the HttpMessageHandler instance.
- Resolve DNS staleness by periodically looping through HttpMessageHandler instances.
In addition, there are other ways to solve the above problems using long-lifetime SocketsHttpHandler instances.
- Create an instance of SocketsHttpHandler at app startup and use it throughout the app's lifecycle.
- Configure PooledConnectionLifetime to the appropriate value based on the DNS refresh time.
- Create an instance of HttpClient using new HttpClient(handler, disposeHandler: false) as needed.
The above approach solves resource management problems in a similar way to IHttpClientFactory.
- SocketsHttpHandler between the HttpClient instancesShared connections。 This sharing prevents socket exhaustion.
- SocketsHttpHandler loops connections based on PooledConnectionLifetime to avoid DNS staleness.
For more usage and configuration, please refer to:
The hyperlink login is visible.
The hyperlink login is visible.
|