服务突然抛出SocketException而没有明显的变化

时间:2017-02-15 11:41:59

标签: c# .net owin dotnet-httpclient

1月17日09:32,我们的一项服务突然开始抛出500个错误。它是第三方服务的适配器服务,我们使用HttpClient对其进行POST(因此我们使用查询字符串参数对我们的服务进行GET,并使用POST和参数将其传输到第三方应用程序身体)。当我使用postman或curl手动发布到第三方服务时,它回复正常。所以这是我们服务的问题。它是使用OWIN中间件的.NET服务,类似于我认为的.NET核心工作方式。问题是前一段时间,.NET框架从4.5.2升级到4.6,在VS中执行此操作时,它会向web.config添加<httpRuntime targetFramework="4.5.2"/>元素。这是为了尽可能保留应用程序的现有行为,以防框架版本之间发生任何重大更改。升级的人没有意识到并留在web.config中的元素中。它运作良好多年,然后突然在所有环境中同时(包括本地)被破坏。我认为它必须是.NET框架中与时间相关的东西,但滚动我的系统时钟并不能解决它!我能找到什么,关于这个谜团的任何想法?只需将web.config升级到4.6即可修复它,但我的任务是调查它。

这是潜在的错误:

System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host
    at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
    at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)

这是代码,它以_client.PostAsync抛出上面的InnerException。 _client是System.Net.Http.HttpClient

public async Task<CalculateResponse> Calculate(CalculateRequest request)
{
    var env = new RequestEnvelope { Body = { RblsCalculate = request } };
    request.LoginId = _username;
    request.Password = _password;

    var body = XmlConvert.SerializeObject(env);

    var content = new StringContent(body, Encoding.UTF8, "application/soap+xml");
    var httpResponse = await _client.PostAsync(_endpointPath, content);

    var response = XmlConvert.ToObject<ResponseEnvelope>(await httpResponse.Content.ReadAsStreamAsync());

    return response?.Body?.RblsCalculateResponse;
}

第三方没有做任何更改,Windows更新没有运行(这同时影响了5个不同的环境)。我们没有做任何改变。当我们部署时,我们每次都部署到一个新实例,web.config在服务器上没有更改,之前的部署是几周之前。

我已经回顾了4.6的一些更改,如果不使用TLSv1.0 +作为协议,HttpClient周围可能会有一些可能发生的重大变化,我已经在其中一台服务器上使用Wireshark进行了检查,我们正在使用TLSv1.2工作。但它并没有解释为什么它突然停止了。

更新 - 根据@Trumpi建议从trace.log输出SSL / TLS跟踪

System.Net.Sockets Verbose: 0 : [16292] Data from Socket#52088480::PostCompletion
System.Net.Sockets Verbose: 0 : [16292] 00000000 : 16 03 01 00 88 01 00 00-84 03 01 58 A4 49 35 01 : ...........X.I5.

更新2 - 删除了不必要的日志^^

2 个答案:

答案 0 :(得分:1)

我的第一直觉是这是TLS握手的问题,第三方服务正在丢弃连接,因为它无法执行成功的握手。正如您所指出的,TLS版本可能是一个问题。无法找到兼容的密码可能是另一个问题。

我偶然发现了this blog post,它描述了如何将握手信息写入跟踪文件。以下是他添加到web.config文件中的部分:

<system.diagnostics> <trace autoflush="true"/> <sources> <source name="System.Net" maxdatasize="1024"> <listeners> <add name="TraceFile"/> </listeners> </source> <source name="System.Net.Sockets" maxdatasize="1024"> <listeners> <add name="TraceFile"/> </listeners> </source> </sources> <sharedListeners> <add name="TraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="trace.log"/> </sharedListeners> <switches> <add name="System.Net" value="Verbose" /> <add name="System.Net.Sockets" value="Verbose" /> </switches> </system.diagnostics>

这是我能对问题中的信息做得最好的,我希望这会有所帮助。

编辑:发布结果后,看起来呼叫正在尝试协商服务器不再支持的TLS 1.0连接。我已将详细信息放在下面的评论中。

答案 1 :(得分:1)

有趣的是,上周我遇到了一个非常类似的问题(虽然它不是.NET Core)。我通过日常工作几个月来一直在调用API端点,突然间我得到了同样的错误。我花了好几天才找到修复程序,但对我来说,添加以下代码行修复了这个问题。您可以将它添加到方法的第一行。

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;