Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting the Content-Type of an empty response in ASP.NET MVC

In order to support a legacy application that's in the field, I need my ASP.NET MVC app to return an empty response that also has a Content-Type. One of IIS, ASP.NET, or ASP.NET MVC is removing my Content-Type when I send back a null response. Is there any way around this?

(While not requiring an empty response with a set Content-Type would obviously be the ideal solution, the clients are already out there, and many of them cannot be upgraded.)

EDIT: Since there was a request for code: I'm proxying the request from the new web application to the one that older clients rely on. To do this, I have a subclass of ActionResult, called LegacyResult, that you can simply return for those methods that need to be handled by the old software. This is the relevant part of its code:

    public override void ExecuteResult(ControllerContext context)
    {
        using (var legacyResponse = GetLegacyResponse(context))
        {
            var clientResponse = context.HttpContext.Response;
            clientResponse.Buffer = false;
            clientResponse.ContentType = legacyResponse.ContentType; /* Yes, I checked that legacyResponse.ContentType is never string.IsNullOrEmpty */
            if (legacyResponse.ContentLength >= 0) clientResponse.AddHeader("Content-Length", legacyResponse.ContentLength.ToString());

            var legacyInput = legacyResponse.GetResponseStream();
            using (var clientOutput = clientResponse.OutputStream)
            {
                var rgb = new byte[32768];
                int cb;
                while ((cb = legacyInput.Read(rgb, 0, rgb.Length)) > 0)
                {
                    clientOutput.Write(rgb, 0, cb);
                }
                clientOutput.Flush();
            }
        }
    }

If legacyInput has data, then Content-Type is set appropriately. Otherwise, it's not. I can actually kluge the old backend to send an empty v. non-empty response for exactly the same request, and observe the difference in Fiddler.

EDIT 2: Poking around with Reflector reveals that, if headers have not been written at the time that HttpResponse.Flush is called, then Flush writes out the headers itself. The problem is that it only writes out a tiny subset of the headers. One of the missing ones is Content-Type. So it seems that, if I can force headers out to the stream, I can avoid this problem.

like image 499
Benjamin Pollack Avatar asked Dec 27 '10 20:12

Benjamin Pollack


1 Answers

You have to trick the response into writing the headers, by falsely telling it there's content, then suppressing it:

/// [inside the writing block]
var didWrite = false;
while ((cb = legacyInput.Read(rgb, 0, rgb.Length)) > 0)
{
  didWrite = true;
  clientOutput.Write(rgb, 0, cb);
}
if (!didWrite)
{
  // The stream needs a non-zero content length to write the correct headers, but...
  clientResponse.AddHeader("Content-Length", "1");
  // ...this actually writes a "Content-Length: 0" header with the other headers.
  clientResponse.SuppressContent = true;
}
like image 168
kevingessner Avatar answered Oct 03 '22 06:10

kevingessner