I have an MVC 5 application that includes a controller action that makes a HTTP request. To do this, I am using HttpClient.
I have learnt from others (like this blog post) and from my own experiences as well that instantating numerous HttpClients simultaneously can have a negative effect on the performance of not just the application but the server as a whole.
So far my requirements of reusing a HttpClient instance could be solved by code like this
using (var handler = new HttpClientHandler() { Credentials = new NetworkCredential(getUsername(), getHashedPassword())})
using (var client = new HttpClient(handler))
{
// Long running loop that makes a different HTTP request
// on each iteration but using the same HttpClient instance
}
Requiring similar re-use in a controller action, I elected to use
a static instance of HttpClient in the controller class. The problem is that
the credentials passed to the HttpClientHandler change with each request since
they partially depend on a timestamp value(the getHashedPassword() method produces a different password each time it is called).
Because of the way authentication is carried out on the remote server, I have to include the password in the XML content that forms the body of the request as well.
And this is where I run into the problem:
How can I re-use the same HttpClient instance across different calls to the controller action while making sure it is using a handler with up to date credentials?
Is it even possible to do this?
Is it possible to update the handler after passing it to the HttpInstance?
Or would I need to modify the client object's DefaultRequestHeaders which according to some sources may introduce subtle bugs if the object is used concurrently by different threads?
Instead of using HTTPClient directly, it is advised to create a client instance using HTTPClientFactory.
Once done, you can create named clients which can be reused based on your handlers.
Here is a useful link on the same.
If you want to further optimize your code, you can maintain a concurrent dictionary.
private readonly ConcurrentDictionary<string, HTTPClient> _clientMap = new ConcurrentDictionary<string, HTTPClient>();
This can then be leveraged like this:
using(var client = _clientMap.GetOrAdd($"{handlerName}", _clientFactory.CreateClient("handlerName"));
In the above snippet, _clientFactory refers to IHttpClientFactory instance.
The HttpClientHandler object is a component that handles requests used by the HttpClient. You want to update the HttpClientHandler for every request that requires new credentials. There are several ways to do this. You can set up-to-date credentials by creating a new HttpClientHandler instance before each request.
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
handler.Credentials = new NetworkCredential(getUsername(), getHashedPassword());
// HttpClient örneğini kullanarak istekleri gerçekleştirin
}
By updating the DefaultRequestHeaders you can pass new credentials on every request.
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{getUsername()}:{getHashedPassword()}")));
// HttpClient örneğini kullanarak istekleri gerçekleştirin
}
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