WebRequest с сертификатом терпит неудачу при первом вызове и успешно выполняет все последующие вызовы - PullRequest
1 голос
/ 06 мая 2020

Инфраструктура

У меня старое. NET Приложение Framework, которое я перенес со старого сервера. Он в 4.6.2 работает на Windows Server 2012 R2.

Приложение форм выполняет вызов службы WCF, работающей также на том же сервере в том же пуле приложений, а служба WCF выполняет вызов WebRequest для внешняя служба.

Для внешнего вызова требуются сертификаты для подтверждения SSL / TLS.

На старом сервере сертификаты прикреплены к запросу, но на новом сервере это не работает и нам пришлось добавить их в доверенный магазин. Это может быть важным ключом к ответу на вопрос ниже.

Проблема

Служба WCF выполняет вызов внешней службы и первый вызов (после развертывания или перезапуска приложение) всегда является ошибкой The request was aborted: Could not create SSL/TLS secure channel.

Однако ВСЕ последующие вызовы работают успешно. Это похоже на то, как если бы сертификат не загружался должным образом в профиль пользователя при первом вызове, но потом это происходит.

Это вызывает проблемы после развертывания новой версии, все первые вызовы терпят неудачу, что влияет на живой трафик c. У нас одинаковая конфигурация на 6 ящиках под балансировщиком нагрузки, и это идентичное поведение на всех 6 ящиках.

Я хочу исправить это, чтобы вызов успешно выполнялся при первом вызове.

Код

    public static Stream SendRequest(string url, string requestXml, string clientKeyBase64, string clientKeyPassword, int requestTimeout)
    {
        Stream os = null;
        HttpWebRequest req = null;
        WebResponse resp = null;
        byte[] bytes;

        try
        {
            req = (HttpWebRequest)WebRequest.Create(url);
            req.Timeout = requestTimeout;
            req.ContentType = "application/xml; charset=utf-8";
            req.Method = "POST";
            bytes = Encoding.ASCII.GetBytes(requestXml);
            req.ContentLength = bytes.Length;

            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            if (!string.IsNullOrWhiteSpace(clientKeyBase64))
            {
                var cert = new X509Certificate2(Convert.FromBase64String(clientKeyBase64), clientKeyPassword);
                req.ClientCertificates.Add(cert);
            }
            using (os = req.GetRequestStream())
            {
                os.Write(bytes, 0, bytes.Length);
            }

            using (resp = req.GetResponse())
            {
                using (var stream = resp.GetResponseStream())
                {
                    MemoryStream memStream;
                    memStream = new MemoryStream();
                    stream.CopyTo(memStream);
                    memStream.Seek(0, SeekOrigin.Begin); // Required to reset stream pointer at the beginning
                    return memStream;
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

То, что я пробовал

  • Эта статья озаглавлена ​​ «Клиент WCF: первый звонок сбой, второй вызов успешен » связано с сертификатом и очень многообещающе. Однако предложение обойти HTTP-статус 100 с помощью ServicePointManager.Expect100Continue = true; не сработало.

  • Попытка установить протокол на TLS 1.2: ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

  • Пробовал установить X509KeyStorageFlags.MachineKeySet согласно это предложение

  • Из того же предложения попытался изменить идентификатор пула приложений на Network Service, LocalSystem и LocalService, ни один из которых

Другая информация

Пул приложений - это рекомендуемый идентификатор ApplicationPoolIdentity, а для параметра «Загрузить профиль пользователя» установлено значение true, в противном случае сертификаты не загружаются.

У меня заканчиваются идеи, что делать дальше, и мне нужна помощь, чтобы понять и исправить это поведение

1 Ответ

0 голосов
/ 07 мая 2020

Кажется, теперь это работает, добавив эти ключи:

X509KeyStorageFlags.UserKeySet |                                                                                                                                 
X509KeyStorageFlags.MachineKeySet |                                                                                                                                  
X509KeyStorageFlags.PersistKeySet |                                                                                                        
X509KeyStorageFlags.Exportable

Спасибо

...