Today in work I had a requirement where I wanted to output binary content to the response output stream. I also want to stay with the MVC Controller for serving this content and so wanted a result I could add my data to and return it. To my knowledge there is a ContentResult, but with this the Content property is of type string, and is not what I wanted. I this particular case, I am physically GZipping content and then writing out to the Response.OutputStream.
Previous to this I have been seeing and using examples where you assign a GZipOutputStream as a Filter on the Response dynamically. For some strange reason on the Live environment the header and filter where being ignored on the response yet on the test, builds and sandbox everything worked as expected and the dynamic resources got GZipped.
So I had to go another way and what I came up with was to physically GZip the output content and send it to the response with the accompanying header. I cannot see why this would not work on the server as the content is physically being served already GZipped opposed to applying a filter which can obviously be removed somewhere in the pipeline. Any way after some reading I found some evidence that a library, http://www.icsharpcode.net/OpenSource/SharpZipLib/ , yields far better results than the out of the box one from .NET, so for this example I have a dependency on this assembly. Apart from that I have added a couple of properties which allow for the conditional Compression and also a list of headers to give a little more flexibility. So here is the code:
/// <summary>
/// A content result which can accept binart data and will write to the output
/// stream. If GZip is set to true the content will be GZipped and the relevant
/// header added to the response HTTP Headers
/// </summary>
public class BinaryContentResult : ActionResult
{
public byte[] Data { get; set; }
public NameValueCollection Headers { get; set; }
public bool Gzip { get; set; }
public override void ExecuteResult(ControllerContext context)
{
foreach (string s in Headers.Keys)
{
context.HttpContext.Response.AddHeader(s, Headers[s]);
}
if (Gzip)
{
using (var os = new GZipOutputStream(context.HttpContext.Response.OutputStream))
{
os.Write(Data, 0, Data.Length);
}
context.HttpContext.Response.AddHeader("Content-Encoding", "gzip");
context.HttpContext.Response.AddHeader("X-Compressed-By", "Custom-Compressor");
}
else
{
context.HttpContext.Response.BinaryWrite(Data);
}
context.HttpContext.Response.End();
}
}