How can I call an MVC FileContentResult by Jquery and get it to prompt the user to save on it's return?

23,514

Solution 1

You can't do that. Forget about that. It is impossible to download files using AJAX. In fact the AJAX call will work, you will hit the server, the server will send the file contents back to the client, the AJAX success callback will be triggered and passed as argument the contents of the file and that's where everything ends for you. Using javascript you cannot, for absolutely obvious reasons, save directly the file to the client computer and you cannot prompt for the Save As dialog.

So instead of using AJAX simply create an anchor:

@Html.ActionLink("download spreadsheet", "GetSpreadsheet", new { id = "123" })

Now if the server set the Content-Disposition header to attachment the browser will prompt the user to download and save the file at some chosen location on his computer.

Solution 2

If you don't want to use an anchor, use a hidden iframe and set the src of the iframe to the url of the file to be downloaded.

<iframe id="hiddenFrame" src="" style="display:none; visibility:hidden;"></iframe>

Instead of the '$.post(...)' line use:

 downloadSpreadsheet('123');

 function downloadSpreadsheet(id) {
    var url = '@Url.Content("~/YourControllerName/GetSpreadsheet")' + "?id=" + id;
    $('#hiddenFrame').attr('src', url);
}

Or you can give a try on the jQuery Plugin for Requesting Ajax-like File Downloads

Using the plugin, you can download by invocking:

jQuery.download(url, data, method)

Solution 3

You can use this in JavaScript:

function downloadSpreadsheet(id) {
    window.location.href = '@Url.Action("GetSpreadsheet", "Home")?id=' + id;
}
Share:
23,514
Andy Clarke
Author by

Andy Clarke

I've been programming since I first tried Basic on my green-screen Amstrad CPC 464. I think I came into it at perfect time - I'm old enough to talk about programming ADA on a VAX/VMS Mainframe, but young enough to not have endured punch cards.

Updated on March 11, 2020

Comments

  • Andy Clarke
    Andy Clarke about 4 years

    I'm generating a CSV from an MVC 3 website and using a FileContentResult to pass this to the user. This worked great but it took 30 seconds for the csv to generate and therefore 30 seconds before the prompt to save was given to the user.

        public virtual FileContentResult GetSpreadsheet(string id)
        {
            var service = new SpreadsheetService();
            var result = service.GetCSV();
            return File(new System.Text.UTF8Encoding().GetBytes(result.Message), "text/csv", "Report123.csv");
        }
    

    So I thought I'd just call it via JQuery - but this (unsurprisingly!) just dumps the CSV to the page.

                $.post("/Home/GetSpreadsheet/" + id, null, function (data) {
                    $('#resultDiv').html(data);
                });
    

    Does anyone know how I'd generate the prompt to save now I've got the data back? Thanks

  • Hal
    Hal about 12 years
    You can also set the content-type header to the appropriate type if known, to prompt an open or save dialog (in most cases) For example: Content-type: application/vnd.ms-excel or text/csv
  • vapcguy
    vapcguy about 9 years
    Love the answer. Made me think about that song "Screamager" by Therapy.
  • Nick
    Nick almost 6 years
    What are those "absolutely obvious" reasons? I managed to get the file bytes using ajax, I just need to render them
  • Peter David Carter
    Peter David Carter over 2 years
    I'm seconding what @Nick says here: one can, in fact, not only get the data, but cause the browser to download it without any further user interaction. The only problem is that the data gets mangled in the process...