code blog foo - tag line bar

Return a Binary File From an MVC Controller Action

Returning a file from a database, or returning a file that is created on the fly is ridiculously easy in ASP.NET MVC (easy cheesy I tell ya!). If you were to attempt the same thing in ASP.NET WebForms, you would have to:

1. Create an ashx file that implements IHttpHandler (or create a class that implements IHttpHander)

2. Implement the IHttpHandler interface

3. Register the ashx file in the web config and define which HTTP verbs it can accept

4. Then you have to deal with a clunky url like: http://www.example.com/getfile.ashx?fileId=39188

5. And if you want a prettier url, then you have to go through all of the hoops for that...

This is how you do it in ASP.NET MVC...

Just inherit from ActionResult:

public class BinaryResult : ActionResult
{
    private byte[] _fileBinary;
    private string _contentType;
    private string _fileName;

    public BinaryResult(byte[] fileBinary, string contentType, string fileName)
    {
        _fileBinary = fileBinary;
        _contentType = contentType;
        _fileName = fileName;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.Clear();
        context.HttpContext.Response.ContentType = _contentType;
        context.HttpContext.Response.AddHeader("Content-Disposition", "filename=" + _fileName);

        if (_fileBinary != null)
        {
            context.HttpContext.Response.BinaryWrite(_fileBinary);
        }
    }
}

And use it!

[AcceptVerbs(HttpVerbs.Get)]
[ActionName("File")]
public ActionResult File(string id)
{
   //some file retriever implemenation that returns a file as a byte array
    byte []fileBytes = _fileRetriever.GetFile(id); 
    string contentType = _fileRetirever.GetContentType(id);
    string fileName = _fileRetriever.GetFileName(id);
    return new BinaryResult(fileBytes "text/plain", fileName);
}

Here is another version that returns a .txt file created on the fly.

[AcceptVerbs(HttpVerbs.Get)]
[ActionName("File")]
public ActionResult File(string id)
{
    //arbitrarily write 100 guids to a memory stream and return it as a text file
    MemoryStream memoryStream = new MemoryStream();
    for(int i = 0; i < 100; i++)
    {
        Write(Guid.NewGuid().ToString() + Environment.NewLine, memoryStream);
    }

    return new BinaryResult(memoryStream.ToArray(), "text/plain", "randomguids.txt");
}

private static byte[] StringToByteArray(string value)
{
    System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    return encoding.GetBytes(value);
}

private static void Write(string value, MemoryStream memoryStream)
{
    byte[] bytes = StringToByteArray(value);
    foreach (byte @byte in bytes)
    {
        memoryStream.WriteByte(@byte);
    }
}

Written: 4/2/2010