5

I want to enable file download in my MVC application, without simply using a hyperlink. I plan to use an image or the like and make it clickable by using jQuery. At the moment I have a simple just for testing.

I found an explanation of doing the download through an action method, but unfortunately the example still had actionlinks.

Now, I can call the download action method just fine, but nothing happens. I guess I have to do something with the return value, but I don't know what or how.

Here's the action method:

    public ActionResult Download(string fileName)
    {
        string fullName = Path.Combine(GetBaseDir(), fileName);
        if (!System.IO.File.Exists(fullName))
        {
            throw new ArgumentException("Invalid file name or file does not exist!");
        }

        return new BinaryContentResult
        {
            FileName = fileName,
            ContentType = "application/octet-stream",
            Content = System.IO.File.ReadAllBytes(fullName)
        };
    }

Here's the BinaryContentResult class:

public class BinaryContentResult : ActionResult
{
    public BinaryContentResult()
    { }

    public string ContentType { get; set; }
    public string FileName { get; set; }
    public byte[] Content { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {

        context.HttpContext.Response.ClearContent();
        context.HttpContext.Response.ContentType = ContentType;

        context.HttpContext.Response.AddHeader("content-disposition",

                                               "attachment; filename=" + FileName);

        context.HttpContext.Response.BinaryWrite(Content);
        context.HttpContext.Response.End();
    }
}

I call the action method via:

<span id="downloadLink">Download</span>

which is made clickable via:

$("#downloadLink").click(function () {
    file = $(".jstree-clicked").attr("rel") + "\\" + $('.selectedRow .file').html();
    alert(file);
    $.get('/Customers/Download/', { fileName: file }, function (data) {
        //Do I need to do something here? Or where?
    });
});

Note that the fileName parameter is received correctly by the action method and everything, it's just that nothing happens so I guess I need to handle the return value somehow?

Anders
  • 12,086
  • 23
  • 97
  • 148

1 Answers1

6

You don't want to download the file using AJAX, you want the browser to download it. $.get() will fetch it but there's no way to save locally from Javascript, for security reasons the browser needs to be involved. Simply redirect to the download location and the browser will handle it for you.

Ian Mercer
  • 35,804
  • 6
  • 87
  • 121
  • Ok, could you specify what you mean I should do please? What I mean is, I could use simple links to do this, as in the example I got this from, and the page won't reload, but simply open a save as dialog. I want the same behaviour, but by clicking on the span instead (which determines which file is to be downloaded by a selection class). Could you specify with some code? Thanks! – Anders Aug 30 '10 at 08:54
  • 3
    Use `document.location.href = ...` to tell the browser to go to the url for downloading the file. It'll see the content disposition header and will display it as a download not as a page. – Ian Mercer Aug 30 '10 at 14:55
  • Perfect! Just one more question before I close this issue: When the save-as dialog shows up, it has the file name sort of concatenated with underscores from the path and the filename, like so: folder_folder_file.txt. How come? I mean, the download works and all, but I want it to have its original file name. (Stepping through the action method and the BinaryContentResult the FileName variable has a regular path: folder\\folder\\file.txt. I can't figure out where this concatenation with underscores takes place. Any ideas? – Anders Aug 30 '10 at 21:02
  • 1
    The file name you pass in the content disposition should be just a file name without a path. For security reasons you can't specify where on the user's hard drive a file goes. – Ian Mercer Aug 30 '10 at 23:13
  • Right, I had mistakenly passed in the wrong variable (I was kind of tired when I did this in the middle of the night :-). Thanks for your help! – Anders Aug 31 '10 at 15:35