1

I have a problem with calling a external service with post method via HttpClient. When I call the external service to get data the HttpClient throws following exception:

System.IO.IOException: Unable to read data from the transport connection: The connection was closed.

This error only occurs when the response message contains larger amount of data. When I prepare requests that return a JSON with an empty array in it the post call proceeds correctly. But when I try a request, which result should be populated with larger amount of data I get this exception. I have searched for the solution of this problem on Internet, and I found a solution that implies, that I should set properly System.Net.ServicePointManager.SecurityProtocol correctly with following line:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

But this didn’t help in my case. I noticed that when I send my request through Postman, the service responds correctly, no matter how big the response payload will be. On Postman I checked the headers in requests and after a while I noticed, that when I do not include Accept-Encoding: gzip header in my request, Postman will have too problems with returning response.

I tried to use this in my code and force HttpClient to use Accept-Encoding header but with no success. Below is my current HttpClient configuration:

using (HttpClient client = new HttpClient(new HttpClientHandler
{
    AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
}))
{
    client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
    client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));

    client.BaseAddress = _uri;
    client.DefaultRequestHeaders.Accept.Clear();
    client.Timeout = TimeSpan.FromSeconds(_timeout);
    client.DefaultRequestHeaders.Add("ApiKey", _apiKey);
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.ConnectionClose = false;
    System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
    
    HttpResponseMessage result = await client.PostAsync(uri, content)

    if (result.IsSuccessStatusCode)
    {
        string resultString = await result.Content.ReadAsStringAsync();
        model = JsonConvert.DeserializeObject<T>(resultString);
    }
    else
    {
        await ResponseErrorThrow(result);
    }

    return model;
}

I have no more ideas at the moment. Can you help me with this problem?

Roman Suska
  • 527
  • 2
  • 7
  • 21
  • Use Fiddler (or a similar tool) to capture the request sent from Postman. Then use it to capture the request from your program. Compare them line by line and find the differences. – John Wu Sep 13 '22 at 15:11
  • Do not set `ServicePointManager.SecurityProtocol`, it's not relevant to the question anyway, and is a bad idea. If you have very large amount of data you might need to increase the timeout – Charlieface Sep 13 '22 at 15:52
  • What is the timeout? – jdweng Sep 13 '22 at 16:40
  • The timeout is set to 240 seconds on the client side and 120 seconds on the server side, but I don't think this is a problem as the error shows up 2-3 seconds after the method call. I can read in the server logs that the request is processed correctly and the results are returned, but the client is not able to read the response. – Roman Suska Sep 14 '22 at 06:15

1 Answers1

0

I recently faced the same issue and through logging around our retry logic we found that the request had gone through.

Through some research I found that the issue might be because of client side connection being open to more than the default timeout of 100s.

Unable to read data from the transport connection: Operation canceled

The client code tries to read the response even when the remote connection is closed and thats when it throws this exception.

C# Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. Reading networkstream

As suggested in the answer above, the best way is to handle the exception thrown and check (if you can) that the request went through.

There are ways to check tcp connection before reading from it but one must remember that any check is at that point in time. A check can return a connection-alive but that still doesn't mean the connection wouldn't die out while reading.