1

By executing the following code, we get 1

public class Program
    {
        public static int count = 0;
        static async Task Main(string[] args)
        {
            var handler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation
            };

            var client = new HttpClient(handler);
            var tasks = new List<Task> {
                    client.GetAsync("https://www.microsoft.com"),
            };

            await Task.WhenAll(tasks);
            var tasks2 = new List<Task> {
                    client.GetAsync("https://www.microsoft.com"),
            };

            await Task.WhenAll(tasks2);
            Console.WriteLine("Count: "+count);
            Console.ReadLine();
        }

        static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2 certificate, X509Chain chain,
                SslPolicyErrors sslErrors)
        {
            Interlocked.Increment(ref count);
            return true;
        }
    }

And no matter how many times we run requests, using the pool, the certificate verification will be interrupted.

This is bad, because I want to get the current expiration date for each request, is it possible to do something without disposing the handler?

  • Have you tried disabling keepalive? See [this answer](https://stackoverflow.com/questions/36357943/c-sharp-how-to-set-httpclient-keep-alive-to-false) – John Wu Jun 06 '23 at 18:16
  • I tried setting the handler lifetime and it led me to socket exceptions. Won't a large number of connections be open if you don't leave them open? I would like to get the certificate release date without introducing it into the connection pool mechanism – Сергей toff Jun 06 '23 at 18:19
  • John, it's worked, thank for your fast answer. I will try to check for socket exception – Сергей toff Jun 06 '23 at 18:26
  • 1
    @Сергейtoff what's the point in validating certificate multiple times, when requests run over single transport connection? The certificate cannot change. Disabling keep-alive to do such thing is pointless, you artificially introduce unnecessary overhead. – freakish Jun 06 '23 at 18:41
  • Why would you expect the expiry to change? Why wouldn't you want to use the connection pooling and keepalive, they are major performance boosts? If the client is still connected from the old conenction then the expiry of that connection *is* the correct one for the current request. – Charlieface Jun 06 '23 at 20:46
  • I agree that using a new connection each time will hurt performance and is almost always unnecessary. The only time the OP's code would be appropriate is if he were writing an application specifically to monitor a certificate for changes. – John Wu Jun 06 '23 at 21:32
  • Yes, you are right, we are trying to track changes in certificates online. Someone can change it just in the middle of the day, not even released and we want to be notified about this – Сергей toff Jun 07 '23 at 09:12
  • The framework had the ability to obtain a certificate in a different way. In theory, it would be normal for us to know that certificate X was reused for this request and clear the cache every couple of hours, and not every request test it, but I also have no idea how to do this on HttpClient – Сергей toff Jun 07 '23 at 09:18
  • Well you could just open a new `SslStream` manually, grab the certificate and immediately close it if you really want. But this sounds like an XY problem. Why do you care someone changed the certificate if your connection is still open? – Charlieface Jun 07 '23 at 13:30
  • Sounds right. Probably the problem is more that it is difficult to understand which certificate to bind to which resource, if the checks are repeated. But anyway John Wu's solution works, as in general with slStream, can anyone issue any of these answers? Regarding bindings, I'll try to start another question – Сергей toff Jun 08 '23 at 14:49
  • solution with ConnectionClose on some services get a "System.ComponentModel.Win32Exception (0x80090302): The function requested is not supported" – Сергей toff Jun 20 '23 at 09:07

1 Answers1

0

If you want to force the HttpClient to check the certificate on every request, you have an option: You can disable connection pooling in the HttpClientHandler to ensure that each request uses a new connection. Set the HttpClientHandler's MaxConnectionsPerServer property to 1. This will prevent connection reuse and trigger the certificate validation callback on every request. For example:

var handler = new HttpClientHandler()
{
 ServerCertificateCustomValidationCallback = 
 ServerCertificateCustomValidation,
 MaxConnectionsPerServer = 1
};

var client = new HttpClient(handler);

With this configuration, each request will use a new connection, and the certificate validation callback will be invoked for each request.