MVC Controller returning Chunked content encoding
Asked Answered
A

1

8

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) 
Asset answered 25/7, 2013 at 1:9 Comment(0)
A
3

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.

Asset answered 25/7, 2013 at 17:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.