2016-09-02 2 views
1

Я читал в нескольких местах (например, here, here или here), что это плохая практика, чтобы избавиться от HttpClient непосредственно после запроса, и лучше избавиться от него после того, как весь запрос был чтобы обеспечить повторное использование соединения.HttpClient повторно используется с сертификатом клиента

Чтобы попробовать это, я создал экземпляр HttpClient и добавляют к статическому полю в моем классе так:

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; }; 
    } 

} 

Я тогда использую мой экземпляр для вызова веб-службы с помощью этого команда:

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

Первый раз, когда я бегу код, все работает отлично, и я получаю ответ правильно, но потом, все в следующий раз я получаю неавторизованный от сервера говорил мне, что я не сделал используйте сертификат клиента.

Это как если бы для следующих звонков, WebRequestHandler не был принят во внимание.

+0

Что касается утилизации HttpClient - это не совсем так. Управление подключением выполняется с помощью «ServicePointManager», но не напрямую с помощью HttpClient (который использует HttpClientHandler, который использует WebRequest под капотом). Поэтому, если у вас есть параметр, чтобы поддерживать соединение TCP или вы одновременно выполняете несколько запросов к одному и тому же «ServicePoint», удаление HttpClient не приведет к закрытию базового соединения. –

+0

Да, вот что я имел в виду. Утилизация HttpClient будет поддерживать соединения живыми, а использование метода use() считается плохой практикой, потому что это создаст большое количество подключений, которые останутся открытыми. Это то, что объясняют сообщения и веб-сайт, которые я связал. – Gimly

ответ

1

Ваше исправление должно выглядеть следующим образом:

handler.PreAuthenticate = true; 

После установления соединения с услугой, вы можете повторно использовать его для общения с ним, используя различные клиенты с различной Идентой информацией. Это означает, что служба должна знать, какой клиент отправил запрос каждый раз, иначе это может быть нарушение безопасности - например, выполнение запроса по последнему подключенному клиенту. Это зависит от вашего механизма аутентификации, но в основном WebRequestHandler устанавливает флаг IsAuthenticated после первого запроса и прекращает отправку аутентификационной информации о следующих запросах. Параметры PreAuthenticate заставляют отправлять информацию об аутентификации по каждому запросу.

+0

Это, кажется, не исправляет это, я все еще придерживаюсь такого же поведения, отлично работает при первом запросе, но не выполняет все следующие действия. – Gimly

+0

Ничего, это было на самом деле. Я думал, что он все еще не работает, но это еще одна совершенно не связанная с этим проблема. Отметьте свой ответ как правильный, спасибо. – Gimly