Download binary files in IE6 with ASP.NET MVC 2.0

On an ASP.NET MVC 2.0 application I was supporting, the application had a download link for downloading a PDF. When clicked, the browser would popup the usual question – what do you want to do with the file? Open, Save or Cancel?

If they click Save it would always work fine with all browsers, but if they click Open it would work fine in all browsers except IE6. With IE6, when they click Open, the file gets downloaded to IE6’s temporary files folder, and then (for PDFs) Acrobat Reader would try to open it. However, it would fail with the error message: “There was an error opening this document. This file cannot be found.” The same problem would also happen with Word documents.

This was only happening in IE6, all other browsers were fine.

Currently, the  Download method on the Controller would write an audit entry and then send the file to the browser using MVC’s File() method, like so:

public ActionResult Download(int id)
{
    Document doc = _documentRepository.GetById(id);

    if (doc != null)
    {
        return File(doc.Filepath, doc.FileType1.Mimetype, Path.GetFilename(doc.Filepath));
    }
    return RedirectToAction("Index");
}

After a lot of Fiddler investigation, playing around with the headers (content-type and content-disposition), and playing with the browser settings I still couldn’t get it to work. I finally found the solution via a stack overflow post. Here’s my version:

public class BinaryFileResult : ActionResult
{
    public string Filename { get; set; }
    public string Path { get; set; }
    public string ContentType { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        FileStream sourceFile = new FileStream(context.HttpContext.Server.MapPath(Path), FileMode.Open);
        int length = (int)sourceFile.Length; // NB. this will only allow download of the first 2Gb of the file.
        byte[] buffer = new byte[length];
        sourceFile.Read(buffer, 0, length);
        sourceFile.Close();

        context.HttpContext.Response.ClearContent();
        context.HttpContext.Response.ClearHeaders();
        context.HttpContext.Response.Buffer = true;
        context.HttpContext.Response.ContentType = ContentType;
        context.HttpContext.Response.AddHeader("Content-Length", length.ToString());
        context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + Filename + "\"");
        context.HttpContext.Response.BinaryWrite(buffer);
        context.HttpContext.Response.Flush();
        context.HttpContext.Response.End();
    }
}

And it is called via:


public ActionResult Download(int id)
{
    Document doc = _documentRepository.GetById(id);

    if (doc != null)
    {
        BinaryFileResult res = new BinaryFileResult
        {
            Path.GetFileName(doc.filepath).Trim(),
            Path = doc.filepath,
            ContentType = doc.FileType1.mimetype.Trim()
        };

        return res;
    }
    return RedirectToAction("Index");
}

And that worked fine in IE6 and all later browsers (Fx 3.6, Chrome 8, IE8).

Advertisements

One thought on “Download binary files in IE6 with ASP.NET MVC 2.0

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s