2017-02-15 3 views
2

17 января 09:32, одна из наших служб внезапно начала выбросить 500 ошибок. Это сервис-адаптер для сторонней службы, и мы используем HttpClient для создания POST (поэтому мы делаем GET для нашей службы с параметрами строки запроса, и мы передаем это стороннему приложению с помощью POST и параметров в тело). Когда я отправляю третью сторону вручную, используя почтальон или завиток, он ответил отлично. Так что это была проблема с нашим сервисом. Это .NET-сервис, который использует промежуточное ПО OWIN, похожее на то, как работает ядро ​​.NET. Проблема состояла в том, что некоторое время назад инфраструктура .NET была обновлена ​​с 4.5.2 до 4.6, и при выполнении этого в VS она добавляет элемент <httpRuntime targetFramework="4.5.2"/> в web.config. Это должно сделать все возможное, чтобы сохранить существующее поведение приложения в случае каких-либо изменений в рамочных версиях. Человек, который обновил, не реализовал и не оставил элемент в web.config. Он отлично работал на протяжении веков, а затем внезапно во всех средах одновременно (в том числе и локально) был разорен. Я думал, что это должно быть время, связанное с платформой .NET, но при этом откатывание системных часов не исправляет! Что я могу искать, любые идеи относительно этой тайны? Просто повышение версии web.config до 4.6 исправляет его, но мне поручено расследовать его.Служба внезапно бросает SocketException без видимых изменений

Здесь основная ошибка:

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, и есть некоторые потенциально разрушающие изменения вокруг HttpClient, если не использовать TLSv1.0 + в качестве протокола, я проверил использование Wireshark на одном из серверов, и мы используем TLSv1.2 , Но это не объясняет, почему это внезапно прекратилось.

Update - Выход из trace.log для SSL/TLS трассировку согласно @Trumpi предложению

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. 

Update 2 - Удалены ненужные журналы ^^

+0

_ «Когда я отправляю на службу третьей стороны, вручную с помощью почтальона или локон, он ответил хорошо. Так что это была проблема с нашим сервисом [...] Третья сторона не вносить никаких изменений» _ - то, что отличается, - это время, когда запрос был выполнен. Возможно, сторонняя служба была перегружена на данный момент, в процессе обновления или что-то еще. Если запущена .NET 4.5.2, эта ошибка возникает, и .NET 4.6 не работает, а затем просматривайте различия в заголовках HTTP между ними. – CodeCaster

+0

«принудительно закрыт удаленным хостом» отлаживает проблему с неправильного конца сокета. Листья не догадываются, почему другой конец решил отказаться. Следуйте за проводом. –

+0

@HansPassant другой конец сокета - стороннее приложение, к которому у меня нет доступа. Я связался с их группой поддержки, и они сказали, что не могут видеть никаких запросов. – Rodders

ответ

1

Интересно, что на прошлой неделе я столкнулся с очень похожими проблемами (хотя это не было с .NET Core). Я ежедневно вызывал конечную точку API через ежедневную работу, и внезапно я получал ту же ошибку. Мне потребовалось несколько дней, чтобы найти исправление, но для меня добавлена ​​следующая строка кода, исправленная проблема. Вероятно, вы можете просто добавить его в первую строку вашего метода.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 
+0

Очень приятно! Это устраняет проблему, даже если мой httpRuntime по-прежнему установлен в 4.5.2. Это очень полезно, спасибо. Это не объясняет, почему это внезапно прекратилось, но это реальный прогресс. Возможно, мы использовали Tls1.2, и что-то заставило его вернуться к 1.0 – Rodders

+0

Или, думая об этом, скорее всего, я думаю, что мы всегда использовали 1.0, а сторонняя сторона внесла некоторые изменения, которые отказались от поддержки. – Rodders

+0

Я чувствовал то же самое. Я потратил столько времени, пытаясь понять, почему это произошло, но через некоторое время я решил, что я счастлив, что нашел решение. Если вы выясните, что вызвало проблему, сообщите мне. – MDiesel

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>

Это лучшее, что я могу делать с информацией в этом вопросе, и я надеюсь, что это помогает.

EDIT: после публикации результатов похоже, что вызов пытается согласовать соединение TLS 1.0, которое сервер больше не поддерживает. Я добавил подробности в комментарии ниже.

+1

Приятная находка, я обновляю свой пост с выходом. Спасибо – Rodders

+0

В байтовом блоке после 'Data from Socket # 52088480 :: PostCompletion' первый байт представляет собой тип контента (' 0x16'), который является рукопожатием. Следующие два байта - это версия ('0x03' и' 0x01'), которая является TLS 1.0. TLS 1.2 отправляет '0x03' и' 0x03'. Источник [RFC 5246 - TLS 1.2] (https://tools.ietf.org/html/rfc5246) и [RFC 2246 - TLS 1.0] (https://www.ietf.org/rfc/rfc2246.txt) – Trumpi

+0

I видеть. Таким образом, мы используем TLS1.0. Кроме того, если я исправлю эту проблему, обновив targetFramework до 4.6, запрос будет работать, но я не получаю никаких журналов в этом файле трассировки. Возможно ли, что мы использовали TLS1.2, и что-то заставило его вернуться к 1.0? – Rodders

Смежные вопросы