System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

I have a helper method below that uses the new HttpClient Class introduced in .NET 4.5 as shown below.

public static async Task<HttpResponseMessage> GetWebRequestAsync(string uri)
{
    using (var httpClient = new HttpClient())
    {
         //set Accept headers
         httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/html,application/xhtml+xml,application/xml,application/json");
         //set User agent
         httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; EN; rv:11.0) like Gecko");
         httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Charset", "ISO-8859-1");
         return = await httpClient.GetAsync(uri); 
    }
}

I tested it in both http and https scenarios with different URLs and they passed with flying colors. Satisfied, I pointed my URL to one of my production websites for final testing. The production website uses https protocol. Of course, my expectation should be no different from my testing but boom, I got this error!

GetWebRequestAsyncTest threw exception: 
System.AggregateException: One or more errors occurred. --->
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> 
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. --->
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> 
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

Switching to http protocol did not threw any exception so I was able to isolate that the culprit was https protocol. However, It worked for other website using https and not in my production website. And that made me googling for a day without resolving the problem.

The next day, I turned my attention to my production website and reviewed all the configurations done with the web server particularly interested with https protocol. I noticed that my web server was configured to accept TLS 1.2 only. It was configured this way for PCI compliance.

That gave me a hint that led me to find out that HttpClient is connecting  using TLS 1.0.  I cannot find any documentation that this is the default but I suspect it is because SSL 3.0 and below is already deprecated.

Armed with this information, I now have to force my HttpClient to connect using TLS 1.2 first then TLS 1.1 then TLS 1.0 so that it can support three versions of TLS. And that gave me the ServicePointManager.SecurityProtocol configuration. So, simply with a single line of code, it worked!. See code below

public static async Task<HttpResponseMessage> GetWebRequestAsync(string uri)
{
    using (var httpClient = new HttpClient())
    {
          //make sure to use TLS 1.2 first before trying other version
          ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

         //set Accept headers
         httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/html,application/xhtml+xml,application/xml,application/json");
         //set User agent
         httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; EN; rv:11.0) like Gecko");
         httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Charset", "ISO-8859-1");
         return = await httpClient.GetAsync(uri); 
    }
}

I hope you will find this helpful for your next use of HttpClient class. Happy coding!

4 thoughts on “System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

  1. Paul Ghattas

    OMG, I was going crazy searching for how to ignore invalid SSL cert and none of the solutions worked. Stumbled upon yours and it worked great. Thank you So much.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.