在 SOAP 请求 .NET CORE 2.2 上发送的 Http.WinHttpException。收到的消息是意外的或格式错误

Posted

技术标签:

【中文标题】在 SOAP 请求 .NET CORE 2.2 上发送的 Http.WinHttpException。收到的消息是意外的或格式错误【英文标题】:Http.WinHttpException sent on SOAP request .NET CORE 2.2. The message received was unexpected or badly formatted 【发布时间】:2021-11-28 23:06:30 【问题描述】:

我们的 .NETCore2.0 webapp 中有三个 IHostedService 定期执行操作。其中两个正在轮询外部系统以获取新数据;第三个将我们的 webapp 收集的一些数据发送到同一个外部系统。每个请求都是 SOAP,并使用以下代码完成:

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;

CreateSOAPWebRequest 方法定义为:

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;

自从第三个服务出现以来,前两个托管服务多年来一直很好地协同工作:一些请求在开始时正常,然后抛出这个异常,并且没有一个服务能够再发送 SOAP 请求(直到我们重启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

这个扔就行了

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

这似乎是证书/安全/SSL 问题。但是请求在一开始和/或没有第三个托管服务时运行良好,所以我们认为这可能是服务之间的同步问题,我们通过单独在一个单独的克隆 web 应用程序上运行它来分离第三个,但我们得到了无论如何,在第二个 SOAP 调用上出现同样的错误(虽然第一个有效)。

我们只能通过在生产环境中禁用服务并在本地以调试模式运行 webapp、读取和发送生产数据来在调试中重现此错误。

我们不知道是什么原因造成的,所以提前感谢您的每一个建议。

【问题讨论】:

【参考方案1】:

我终于明白了。当异常说实话时,整个事情有点误导:在我们的代码中的某个时刻,在 SOAP 请求之后,流程可能会经历这样的事情:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls

所以在这条指令之前一切都很好,当然在这条指令之后一切都坏了。

【讨论】:

以上是关于在 SOAP 请求 .NET CORE 2.2 上发送的 Http.WinHttpException。收到的消息是意外的或格式错误的主要内容,如果未能解决你的问题,请参考以下文章

从 C# .NET Core(特别是 Workday)调用 Java Web 服务。如何在soap请求中获取xml属性

从 .NET Core 2.2 迁移到 3.1 后,EF Core 随机抓取 API 请求上的用户表

尝试使用 net core / net 5 连接 SOAP 服务

将项目从 2.2 更新到 3.1(缺少程序集)或如何在 .NET Core 中使用 API POST 请求时,PostAsJsonAsync()在 .Net Core 3.1 中不起作用 [重复]

如何在 asp net core 2.2 中间件中多次读取请求正文?

最简单易懂的webService客户端之soap请求