1

I've read at several places (like here, here or here) that it's a bad practice to dispose of the HttpClient directly after a request and it's better to dispose of it after all the request have been made, to allow reuse of the connection.

To try that out, I've created an instance of HttpClient and added to a static field in my class this way:

public class Test
{
    private static X509Certificate2 _certificate;
    private static HttpClient HttpClient { get; set; }

    ...

    public Test()
    {
        ...

        if (HttpClient == null)
        {
            LoadCertificate();

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                                                    | SecurityProtocolType.Tls11
                                                    | SecurityProtocolType.Tls12
                                                    | SecurityProtocolType.Ssl3;

            var handler = new WebRequestHandler();
            handler.ClientCertificates.Add(_certificate);
            HttpClient = new HttpClient(handler, false);
        }
    }

    private void LoadCertificate()
    {
        using (var store = new X509Store(StoreName.My, CertificateStoreLocation))
        {
            store.Open(OpenFlags.ReadOnly);
            var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateFriendlyName, true);
            if (certificates.Count != 1)
                throw new ArgumentException(
                    $"Cannot find a valid certificate with name {CertificateFriendlyName} in {CertificateStoreLocation}");
            _certificate = certificates[0];

            store.Close();
        }

        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    }

}

I'm then using my instance to call a web service through this command:

var result = await HttpClient.PostAsJsonAsync(completeUri, request);

The first time I'm running the code, everything works fine and I get a response correctly, but then, all the following time I get an unauthorized from the server telling me that I didn't use a client certificate.

It's like if for the following calls, the WebRequestHandler wasn't took into consideration.

Community
  • 1
  • 1
Gimly
  • 5,975
  • 3
  • 40
  • 75
  • Regarding disposing of HttpClient - that's not entirely true. The connection management is done by `ServicePointManager`, but not directly by HttpClient (which uses HttpClientHandler, which uses WebRequest under the hood). So if you have a setting to keep the TCP connection alive or you have multiple requests running at the same time to the same `ServicePoint`, the disposal of HttpClient won't close the underlying connection. – Serge Semenov Sep 02 '16 at 14:48
  • Yes, that's what I meant. Disposing of the HttpClient will keep the connections alive, and putting it in a using() is considered bad practice because it'll create a big number of connections that will stay open. It's what the posts and website I've linked explain. – Gimly Sep 02 '16 at 14:52

1 Answers1

1

Your fix should look like this:

handler.PreAuthenticate = true;

Once you establish a connection to a service, you can re-use it to communicate with it using different clients with different auth information. That means, the service needs to know which client sent a request each time, otherwise it could be a security breach - e.g. executing a request under last connected client. It depends on your authentication mechanism, but basically WebRequestHandler sets flag IsAuthenticated after the first request, and stops sending the auth information on next requests. The PreAuthenticate options forces to send the auth info on every request.

Serge Semenov
  • 9,232
  • 3
  • 23
  • 24
  • That doesn't seem to fix it, I still have the same behavior, works fine on first request, but fails on all the following. – Gimly Sep 02 '16 at 15:10
  • Never mind, it was actually it. I thought it was still not working but it was another completely unrelated issue. Marked your answer as correct, thanks. – Gimly Sep 02 '16 at 15:24