I was able to dramatically improve the performance of HttpClient by removing one line of code. Take the below snippet;
var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true, PreAuthenticate = false, ClientCertificateOptions = ClientCertificateOption.Automatic }; var webclient = new HttpClient(httpClientHandler);
The offending line of code is highlighted.
This code averaged 20 seconds per 100 requests. Using the default ClientCertificateOption.Manual this improved to 4 seconds.
I couldn’t understand why this would be, so I cracked open HttpClient with Jetbrains dotpeek to take a closer look.
HttpClient eventually calls it’s base class SendAsync method. This calls SendAsync on the handler and it is here the importance of this property becomes clear.
The handler calls the private method CreateAndPrepareWebRequest(). This in turn calls the innocent sounding SetDefaultOptions(…) method where the below code lurks;
X509CertificateCollection clientCertificates = UnsafeNclNativeMethods.NativePKI.FindClientCertificates(); if(clientCertificates.Count <= 0) return; webRequest.ClientCertificates = clientCertificates;
It turns out the FindClientCertificates() method enumerates the users certificate store on every request.
I found this amazing and it seems extremely wasteful.
I am still trying to figure out if there is a good reason why the certificate store couldn’t be enumerated once and the certificate list stored for future requests.
But that’s for another day!
This article was originally published at Garfield's personal blog.