Http.WinHttpException 根据 SOAP 请求发送 .NET CORE 2.2。收到的消息是意外的或格式错误
Http.WinHttpException sent on SOAP request .NET CORE 2.2. The message received was unexpected or badly formatted
我们的 .NETCore2.0 webapp 中有三个 IHostedService 定期执行操作。其中两个正在轮询外部系统以请求新数据;第三个将我们的网络应用程序收集的一些数据发送到同一个外部系统。每个请求都是 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()
这似乎是一个 certificate/security/SSL 问题。但是在没有第三个托管服务的情况下,请求在一开始 and/or 工作得很好,所以我们认为这可能是服务之间的同步问题,我们通过 运行 在一个单独的克隆 webapp 上分离了第三个,一个人,但我们在第二次 SOAP 调用中遇到了同样的错误(而第一次有效)。
我们只能通过在生产环境中禁用该服务并 运行 在本地调试模式下读取和发送生产数据来在调试中重现此错误。
我们不知道是什么原因造成的,所以提前感谢您的每一个建议。
我终于明白了。整个事情有点误导,而异常却说出了真相:在我们的代码中的某个时刻,在 SOAP 请求之后,流程可能会经过这个:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
所以在这条指令之前一切都很好,当然在这条指令之后一切都坏了。
我们的 .NETCore2.0 webapp 中有三个 IHostedService 定期执行操作。其中两个正在轮询外部系统以请求新数据;第三个将我们的网络应用程序收集的一些数据发送到同一个外部系统。每个请求都是 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()
这似乎是一个 certificate/security/SSL 问题。但是在没有第三个托管服务的情况下,请求在一开始 and/or 工作得很好,所以我们认为这可能是服务之间的同步问题,我们通过 运行 在一个单独的克隆 webapp 上分离了第三个,一个人,但我们在第二次 SOAP 调用中遇到了同样的错误(而第一次有效)。
我们只能通过在生产环境中禁用该服务并 运行 在本地调试模式下读取和发送生产数据来在调试中重现此错误。
我们不知道是什么原因造成的,所以提前感谢您的每一个建议。
我终于明白了。整个事情有点误导,而异常却说出了真相:在我们的代码中的某个时刻,在 SOAP 请求之后,流程可能会经过这个:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
所以在这条指令之前一切都很好,当然在这条指令之后一切都坏了。