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).
