web-dev-qa-db-de.com

System.Net.Http.HttpRequestException Fehler beim Kopieren von Inhalten in einem Stream

Ich verwende die Klasse HttpClient in .NET 4.5.2-Framework. Ich mache einen PostAsync-Dienst für einen Webdienst eines Drittanbieters. In 80% der Fälle funktioniert dieser Beitrag, in 20% der Fälle wird unsere Antwort verkürzt. In dieser Situation erhalten wir die folgende Ausnahme: 

System.Net.Http.HttpRequestException: Fehler beim Kopieren von Inhalten in den Stream . ---> System.IO.IOException: Daten aus der - Transportverbindung können nicht gelesen werden: Eine bestehende Verbindung wurde von Des fernen Hosts zwangsweise geschlossen. ---> System.Net.Sockets.SocketException: Eine bestehende Verbindung wurde vom fernen Host um System.Net.Sockets.NetworkStream.BeginRead (Byte [] Puffer, Int32 offset, Int32-Größe, AsyncCallback-Rückruf, Objektstatus) --- Ende der inneren Ausnahme-Stack-Ablaufverfolgung --- um System.Net.Sockets.NetworkStream.BeginRead (Byte [ ] Puffer, Int32 Offset, Int32-Größe, AsyncCallback-Rückruf, Objektstatus) um System.Net.FixedSizeReader.StartReading () um System.Net.Security._SsStream.StartFrameHeader (Byte [] Puffer, Int32 Offset, Int32-Zählung, AsyncProtocolRequest asyncRequest) um System.Net.Security._SslStream.StartReading (Byte [] Puffer, Int32 Offset, Int32 count, AsyncProtocolRequest asyncRequest) um System.Net.Security._SslStream.ProcessRead (Byte [] Puffer, Int32 Offset, Int32 Count, AsyncProtocolRequest asyncRequest) um System.Net. TlsStream.BeginRead ( Byte [] Puffer, Int32-Offset, Int32 Größe, AsyncCallback asyncCallback, Objekt asyncState) um System.Net.ConnectStream.BeginReadWithoutValidation (Byte [] Puffer, Int32-Offset, Int32 Größe, AsyncCallback-Callback, Objektstatus) um System.Net.ConnectStream.BeginRead (Byte [] Puffer, Int32-Offset, Int32 Größe, AsyncCallback-Callback, Objektstatus) um System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead (Byte [] Puffer, Int32-Offset, Int32-Zählung, AsyncCallback-Rückruf, Objekt ) Bei System.Net.Http.StreamCopy.StartRead (Zustand). )

Eine nachfolgende identische Anfrage ist erfolgreich. Es ist keine Anfrage, die wir erneut versuchen können, da das Unternehmen bereits platziert wurde. Das lässt uns in eine unangenehme Situation.

Das ist mein Code:

using (var httpClient = new HttpClient())
{
    httpClient.DefaultRequestHeaders.Authorization = authorizationHeader;
    HttpContent httpContent = new StringContent(someXml);

    //Exception occurs on next line...
    var response = await httpClient.PostAsync("https://thirdpartyendpoint", httpContent);
    var responseXml = await response.Content.ReadAsStringAsync();  
    //convert to Dto              
}

Der Dienst eines Drittanbieters speichert den Datensatz erfolgreich in seiner Datenbank und sieht am Ende keine offensichtlichen Ausnahmen. Sie stellten fest, dass die fehlgeschlagenen Anforderungen in der Regel länger (ca. 18-30 Sekunden) in die Datenbank geschrieben haben als die erfolgreichen Anforderungen.

Danke für deine Hilfe

10
jonho

wir haben dieses Problem mit 2 Codeänderungen gelöst:

  1. Entsorgen Sie die httpResponseMessage und arbeiten Sie einfach mit einem einfachen DTO

     using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
        {
            return await CreateDto(httpResponseMessage);
        }
    
  2. Downgrade der Version von HTTP auf Version 1.0 

    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(url))
    {
        Version = HttpVersion.Version10,
        Content = httpContent
    };
    
    await client.SendAsync(httpRequestMessage);
    

dies hat den Effekt, diesen Http-Header hinzuzufügen

    Connection: close 

lieber als das

    Connection: keep-alive
15
jonho

Ich hatte den gleichen Fehler (Fehler beim Kopieren von Inhalten in einen Stream) mit der HTTPClient PutAsync () -Methode:

using (StreamContent content = new StreamContent(stream))
{
    HttpResponseMessage response = await client.PutAsync(url, content))
}

Sie müssen das HttpCompletionOption.ResponseHeadersRead -Flag angeben, das in PutAsync nicht verfügbar ist, sodass ich zu SendAsync gewechselt bin:

using (StreamContent content = new StreamContent(stream))
{
    var httpRequest = new HttpRequestMessage(HttpMethod.Put, url);
    httpRequest.Content = content;

    HttpResponseMessage response = await client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);
}
0
kimphamg

Ich hatte ein ähnliches Problem mit der Verwendung eines gemeinsam genutzten HttpClient, der für REST -Aufrufe eine Verbindung zu einem Server herstellt. Das Problem war letztendlich ein Konflikt zwischen dem KeepAlive-Timeout auf dem Client und dem Server. Das clientseitige Timeout wird durch die Einstellung MaxServicePointIdleTime im ServicePointManager festgelegt und ist standardmäßig auf 100 Sekunden eingestellt. Das serverseitige Leerlaufzeitlimit wurde auf unserem Server auf einen kürzeren Wert eingestellt.

Ein kürzeres Timeout auf dem Server im Vergleich zum Client hatte zur Folge, dass der Server sporadisch eine Verbindung schloss, als der Client versuchte, eine Verbindung herzustellen. Dies führte zu der gemeldeten Ausnahme.

Beachten Sie, dass ich das Problem letztendlich gefunden habe, da ich unter den gleichen Bedingungen auch diese Ausnahme erhalten habe:

System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
0
Steve Wranovsky