0

I'm trying to download an excel CSV file using jquery's $.post method but I'm having trouble getting it to work.

I can see that the server is creating the file and sending it back to the client but after that, I can't get the file to actually download.

My jquery post function looks like this:

$.post("/GenerateFile", { id: id, startDate: startDate, endDate: endDate }, function (data) {

    window.location = data;

}).fail(function (XMLHttpRequest, textStatus, errorThrown) {

});

And my server side function looks like this:

public async Task<ActionResult> GenerateFile(string id, string startDate, string endDate)
{
    try
    {
        // My logic to create the file here, this is of type Task<MemoryStream>
        var outputFile = await CreateFile(sDate, eDate);

        return File(outputFile, "text/comma-separated-values", "Download.csv");
    }
    catch (Exception e)
    {
        return new HttpStatusCodeResult(400, e.Message);
    }
}

When this data comes back to the client, it tries to navigate to a new page using the data from the CSV file (as can be seen on the URL link) with the message

Bad Request - Invalid URL

HTTP Error 400. The request URL is invalid.

There is no problem with the file generation itself as I can create the file locally onto disk, it's just when I'm trying to use a browser to download it.

I've seen guides which show this method working but there seems to be something that I'm missing that's stopping the download from working.

Hanho
  • 229
  • 1
  • 4
  • 16

1 Answers1

0

File downloads work like a redirect. Ajax methods, including post, do not handler redirects and just return the server result as-is. In your case a file stream.

Rather than return the file from the post, which requires you to do something with the actual file stream (not the URL), just get the post method to create a temp file on the server, then return a URL to that file.

Then when you set window.location to the file URL, it will download as you wanted.

This is a pretty standard approach, but you then need to deal with deleting the temp files afterwards. Strategies for that include:

  • data-time expiry checking of any/all temp files when any file is created/requested
  • only having 1 temp download filename available per user
iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • Thanks for the answer, I was sure I could download it just using window.location but it doesn't seem to work as I thought (after trying to figure it out for a few hours =.= ). Anyway instead of creating a file on the server, I stored the value in a session (as per this guide - http://stackoverflow.com/questions/14138872/how-to-use-sessions-in-an-asp-net-mvc-4-application) and its downloading perfectly now. – Hanho May 03 '15 at 10:59
  • Assuming you could just pass an entire file as an encoded string, `window.location` has very small size limits so that would never be practical. While a session *will* work, that is really not recommended for large data items and certainly will not work well across multiple servers (e.g. a real production environment with min of 2 server instances) – iCollect.it Ltd May 03 '15 at 11:32
  • Ah right, thanks for the heads up, how large are we talking about when you say large data items? Over 1 megs? 5 megs? 100megs? Also, can you give me a brief overview of what a server instances mean? (or a link regarding this?) – Hanho May 04 '15 at 10:31