We've got a fairly complex httphandler for handling images. Basically it streams any part of the image at any size that is requested. Some clients use this handler without any problems. But we've got one location that gives us problems, and now it also gives problems on my development environment.
What happens is that the client never receives anything on some requests. So request 1 and 2 are fine, but request 3 and 4 never end.
- While debugging I can see that the server is ready and has completed the request.
- The client however is still waiting on a result (debugging with fiddler2 shows that there is no response received)
The code that we use to stream an image is
if (!context.Response.IsClientConnected)
{
imageStream.Close();
imageStream.Dispose();
return;
}
context.Response.BufferOutput = true;
context.Response.ContentType = "image/" + imageformat;
context.Response.AppendHeader("Content-Length", imageStream.Length.ToString());
if (imageStream != null && imageStream.Length > 0 && context.Response.IsClientConnected)
context.Response.BinaryWrite(imageStream.ToArray());
if (context.Response.IsClientConnected)
context.Response.Flush();
imageStream.Close();
imageStream.Dispose();
The imageStream is a MemoryStream with the contents of an image.
After the call to response.Flush() we do some more clean-up and writing summaries to the eventlog.
We also call GC.Collect() after every request, because the objects that we use in-memory become very large. I know that that is not a good practice, but could it give us trouble?
The problems with not returning requests happen at both IIS 5 (Win XP) and IIS 6 (Win 2003), we use .NET framework v2.
Best Solution
A client will limit the number of simultaneous requests it will make to any one server. Furthermore when requesting from a resource that requires session state (the default) other requests for resources requiring session state will block.
When using
HttpWebResponse
you must dispose either that object or the stream returned by itsGetResponseStream
method to complete the connection.Your code was very confusing. You've turned buffering on, set a content-length and used a flush. This results in some strange HTTP headers. Ordinarily with buffering on you would leave the setting of the Content-Length header to ASP.NET to handle.
When you use flush ASP.NET assumes that you may subsequently send more data. In this case it will use chunked transfer. Once the response is complete a final set of headers is sent for the final chunk, each chunk as its own length header and the total length of content is derived from these. The first chunk should not have a Content-Length header, however your code is adding that header.
If you turn off buffering and pump the bytes into the output stream yourself then you should set the Content-Length header yourself because effectively buffer off means you are taking responsibility for exactly what gets sent to the client. Marc's code is a simple example of such a pump, although I would use a bigger buffer, or on a MemoryStream the WriteTo method would be more efficient.