This is my second network error in 2 weeks. When trying to retrieve an image using a WebRequest I get the following error:
Exception: System.IO.IOException Message: Unable to read data from the transport connection: The connection was closed.
Source: System
at System.Net.ConnectStream.Read(Byte[] buffer, Int32 offset, Int32 size)
The code has been working fine for years, but suddently it fails. After some Googling I found some hints to why this might happen:
- If the IIS “Keep Alive” is set, it might crash WCF and .NET in general. Apparently, IIS 7.5 was updated, enabling Keep-Alive as default.
- The remote side closes the connection prior to it being finished. Setting the HttpVersion to 1.0 can fix this issue.
- The remote side didn’t specify the “Content-Length” when sending data. Apparently when updating to .NET 4.0 this becomes an issue.
The trick that helped me was to quit using a WebRequest and use a HttpWebRequest instead. The HttpWebRequest allows me to play with 3 important settings:
- KeepAlive: The KeepAlive can be turned on and off
- ProtocolVersion: The HTTP protocol version can be switched between 1.0 and 1.1
- ServicePoint.Connectionlimit: The number of available connections to a service point can be tuned.
The code that worked for me is:
private Byte[] RetrieveAsset(Uri uri, out string contentType) { try { Byte[] bytes; HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(uri); webRequest.KeepAlive = true; webRequest.ProtocolVersion = HttpVersion.Version10; webRequest.ServicePoint.ConnectionLimit = 24; webRequest.Headers.Add("UserAgent", "Pentia; MSI"); using (WebResponse webResponse = webRequest.GetResponse()) { contentType = webResponse.ContentType; using (Stream stream = webResponse.GetResponseStream()) { using (MemoryStream memoryStream = new MemoryStream()) { // Stream the response to a MemoryStream via the byte array buffer Byte[] buffer = new Byte[0x1000]; Int32 bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { memoryStream.Write(buffer, 0, bytesRead); } bytes = memoryStream.ToArray(); } } } return bytes; } catch (Exception ex) { throw new Exception("Failed to retrieve asset from '" + uri + "': " + ex.Message, ex); } }
In this case all I needed was to set the ProtocolVersion to 1.0, but other scenarios migth require you to disable KeepAlive or limiting the number of connections.
Therefore you should set the KeepAlive, ProtocolVersion and ConnectionLimit using variable settings as different scenarios require different values (see An existing connection was forcibly closed by the remote host).
Why is KeepAlive set to true in your example? Based on the explanation, I would expect it to be either commented out or set to false…
LikeLike
To be honst I have no idea why the KeepAlive must be true, but if it’s false, the scenario fails.
I guess that’s just the magic of being a software engineer…
LikeLike
Pingback: C# HttpClient File Download Error – Unable to read data from the transport connection
Pingback: Requesting Azure API Management URL’s | Brian Pedersen's Sitecore and .NET Blog
Pingback: HttpClient POST or PUT Json with content type application/json | Brian Pedersen's Sitecore and .NET Blog
Pingback: Unable to read data from the transport connection : An existing connection was forcibly closed by the remote host – inneka.com
Pingback: [c#] 전송 연결에서 데이터를 읽을 수 없습니다. 기존 연결이 원격 호스트에 의해 강제로 닫혔습니다. - 리뷰나라
Pingback: [C#] Unable to read data from the transport connection : An existing connection was forcibly closed by the remote host - Pixorix