So I have an MVC project. This MVC project contains one Controller, that needs to stream content back to the client. When the streaming starts, there is no way to determine the content length (it is calculated on-the-fly). So I open HttpContext.Current.Response.OutputStream, and start writing and Flushing periodically (I've already disabled buffered output, and attached the appropriate http headers):
while (some condition){
HttpContext.Current.Response.OutputStream.Write(buffer, 0, buffer.Length);
HttpContext.Current.Response.Flush();
}
If I then force the stream to close:
HttpContext.Current.Response.Close();
It does not properly end the Chunked content (it does not append a 0 length chunk at the end, to indicate EOF to the client).
If I instead close the output stream more gracefully:
HttpContext.Current.Response.End();
OR
HttpContext.Current.ApplicationInstance.CompleteRequest();
It properly closes the stream (zero length chunk appended to end), but I get an exception thrown by the application, indicating that it can't insert HTTP headers into the output stream, because the stream was already written!
In both cases, the Controller goes on to return null (or EmptyActionResult).
I assume the exception is caused because the MVC stack requires that every ActionResult set HTTP headers after the Controller finishes executing. If this is the case, how does one implement a Chunked stream in MVC?
Thanks in advance!
EDIT: The exact exception being thrown is:
Uncaught Exception: System.Web.HttpException (0x80004005): Server cannot set status after HTTP headers have been sent.
at System.Web.Http.WebHost.HttpControllerHandler.EndProcessRequest(IAsyncResult result)
at System.Web.Http.WebHost.HttpControllerHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Try adding "&headers=false" to your request. That should shorten it up and cause the response to be less likely to be chunked. Also, are you sending a HTTP/1.1 or HTTP/1.0 request? Try sending a HTTP/1.0 if your device cannot handle a HTTP/1.1 request.
Chunked transfer encoding is a streaming data transfer mechanism available in version 1.1 of the Hypertext Transfer Protocol (HTTP). In chunked transfer encoding, the data stream is divided into a series of non-overlapping "chunks". The chunks are sent out and received independently of one another.
Chunked transfer-coding, also known as chunking, involves transferring the body of a message as a series of chunks, each with its own chunk size header. The end of the message is indicated by a chunk with zero length and an empty line.
I found the solution.
The HTTP 1.1 standard specifies that chunked encoding must be closed with a 0 length chunk, only when the request mode is keep-alive
In keep-alive mode, the connection between client/server is persisted for multiple request/responses. Chunked encoding needs to be ended with the zero length chunk in this context, because there is no other way for the client to know when the preceding response ends.
If you specify "Connection: close" as a header, as opposed to "Connection: keep-alive", then the connection is not persisted between request, the client can use the connection closing as an indication of response termination, and does not require the 0 length chunk indicating EOF.
I have just decided to manually close the HttpResponse using:
HttpContext.Current.Response.Close();
While having previously specified in the code to tell the client that the connection will close upon EOF. This has solved the issue where the client wasn't receiving the 0 length chunk, because now the client does not require it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With