Search code examples
c#.net-coresoaphttpwebrequestsystem.net.webexception

Http.WinHttpException sent on SOAP request .NET CORE 2.2. The message received was unexpected or badly formatted


We have three IHostedService in our .NETCore2.0 webapp performing operations periodically. Two of them are in polling on an external system asking for new data; the third sends to the same external system some data gathered by our webapp. Every request is SOAP and it's done with the following code:

try
{
    #region PFC Certificate
    // Pfx certificate management
    string certPath = GetCertPath();
    string certPass = GetCertPassword();
    X509Certificate2Collection X509collection = new X509Certificate2Collection();
    X509collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet);
    #endregion

    if (X509collection.Count > 0)
    {
        X509Certificate2 x509 = X509collection[0];
        var request = CreateSOAPWebRequest(url, x509);
        byte[] bytes;
        bytes = Encoding.ASCII.GetBytes(xmlRequestContent);
        request.ContentType = "application/xml; encoding='utf-8'";
        request.ContentLength = bytes.Length;

        Stream requestStream = request.GetRequestStream();

        requestStream.Write(bytes, 0, bytes.Length);
        requestStream.Close();

        if (request == null) throw new Exception($"url:{url}: Request NULL - xml: {xmlRequestContent}");

        try
        {
          using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
          {
              if (response.StatusCode == HttpStatusCode.OK)
              {
                  using (Stream responseStream = response.GetResponseStream())
                  {
                      // Response deserialization
                      string responseStr = await new StreamReader(responseStream).ReadToEndAsync();
                      T result = new T();
                      XmlSerializer serializer = new XmlSerializer(typeof(T));
                      using (StringReader reader = new StringReader(responseStr))
                      {
                          result = (T)(serializer.Deserialize(reader));
                          return result;
                      }
                  }
              }
          }
        }
        catch (WebException ex)
        {
            _logger.LogError(ex);
            throw;
        }
    }

    return default(T);
}
catch(Exception ex)
{
    _logger.LogError(ex);
    throw;
}

The CreateSOAPWebRequest method is defined as:

private HttpWebRequest CreateSOAPWebRequest(string url, X509Certificate certificate)
{
  Uri uri = new Uri(url);

  HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
  webRequest.Proxy = null;
  webRequest.Headers.Add("SOAP:Action");
  webRequest.KeepAlive = true;
  webRequest.ContentType = "text/xml;charset=\"utf-8\"";
  webRequest.Accept = "text/xml";
  webRequest.Method = "POST";
  webRequest.AuthenticationLevel = AuthenticationLevel.MutualAuthRequired;
  
  if (certificate != null) 
    webRequest.ClientCertificates.Add(certificate);
  
  return webRequest;
}

The first two hosted services worked very well together for years since the third cames in: some requests go OK in the beginning, then this exception is thrown and no one of the services is able to send the SOAP request anymore (until we restart the webapp):

The SSL connection could not be established, see inner exception. Authentication failed, see inner exception.
---> The SSL connection could not be established, see inner exception.  
---> Authentication failed, see inner exception.
---> The message received was unexpected or badly formatted

This is thrown on the line

HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync()

This seems to be a certificate/security/SSL problem. But the requests work well in the beginning and/or without the third hosted service, so we thought it could be a syncronization problem between the services and we detached the third one by running it on a separate cloned webapp, alone, but we got the same error on the second SOAP call anyway (while the first worked).

We were able to reproduce this error in debug only by disabling the service in the production environment and running the webapp locally in debug mode, reading and sending production data.

We have no idea on what is causing this, so thank you in advance for every advice.


Solution

  • I finally figured it out. The whole thing was a bit misleading while the exception was telling the truth: at some point in our code, after the SOAP request, the flow COULD go through this:

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
    

    So everything was fine until this instruction and of course everything was broken after this instruction.