2

I have the following action that returns a PDF:

[HttpPost]
    public string GetPDF(string data, float scaleFactor)
    {
        var result = JArray.Parse(data);
        using (var fs = new FileStream(@"c:\pdf\pdftest.pdf", FileMode.Create))
        {
            MemoryStream ms = (MemoryStream)PdfMaker.CreatePDF(scaleFactor, result, dt);
            ms.WriteTo(fs);
            return Convert.ToBase64String(ms.ToArray());
        }
    }

(Ignore the FileStream, that is just for testing)
The result is basically the PDF itself, but it's not getting downloaded, how do I download the output PDF? Should I return something else? I tried using a FileResult, but it's basically the same scenario.

This is the way I'm currently "reading" the file via Ajax:

$.ajax({
    type: "POST",
    url: "home/GetPDF",
    data: { data: JSON.stringify(data), scaleFactor: $("#sf").val() },   
    success: function (data) {      

        window.location = "data:application/pdf;base64, " + data;
    }
});

Thanks.

Edit:

Used the solution in this post provided by Stephen Muecke

master2080
  • 366
  • 3
  • 15
  • What ajax? Show your code. –  Jun 07 '18 at 09:02
  • 1
    why not just do a window.location directly to the GetPDF action, and have it return a FileResult with the normal file in it? Downloading files via ajax doesn't work because the data ends up in memory in a JS object, not on the user's device. Just use a normal HTTP request. – ADyson Jun 07 '18 at 09:10
  • The file is created based on user input on the page, how can I directly window.location to it since it has dynamic parameters? – master2080 Jun 07 '18 at 09:11
  • in that case use a form postback so you can easily submit the data – ADyson Jun 07 '18 at 09:13
  • 2
    Refer [this answer](https://stackoverflow.com/questions/16670209/download-excel-file-via-ajax-mvc) for an example –  Jun 07 '18 at 09:13
  • @ADyson I need to stay on the page. – master2080 Jun 07 '18 at 09:14
  • There are also ways to generate PDFs using JavaScript without needing to post anything to the server, if you search online – ADyson Jun 07 '18 at 09:15
  • @ADyson I have to generate PDFs this way, it has to come from the server. – master2080 Jun 07 '18 at 09:16
  • Or another option is to post the data to the server using AJAX, save the file in a temp folder, return the file ID, then do a window.open to a second action using a GET and passing the file ID, which will do the download – ADyson Jun 07 '18 at 09:16
  • " it has to come from the server"...you just said the data comes from the client. so who cares if the server generates it or the browser? The result is the same. – ADyson Jun 07 '18 at 09:17
  • @ADyson The PDF has to be created on the server, not the data from the client. There's no way to create PDFs using javascript with my requirements. – master2080 Jun 07 '18 at 09:17
  • You said, quite explicitly, "The file is created based on user input on the page,". So the data is there, on the page, in the browser. It's already on the client's machine. So in that scenario, why must the PDF be generated by the server? Is extra data being added by the server? Must a copy of the file be stored on the server? You haven't mentioned either of those as being requirements. If they're not requirements, then unless you can give another reason other than the tautological "it must", then the server is not adding any value to the process as far as I can see. – ADyson Jun 07 '18 at 09:20
  • Because those were irrelevant to the problem. I am not directly creating a new PDF, but editing an existing one on the server with user input. Javascript has no access to that kind of stuff. – master2080 Jun 07 '18 at 09:21
  • well there you go, you didn't state the situation in full, hence my misunderstanding. Also your sample code does call "CreatePDF", so forgive me for thinking you were creating a new one. – ADyson Jun 07 '18 at 09:21
  • Because it's irrelevant to my question. My question is how to download the PDF, not make one. – master2080 Jun 07 '18 at 09:21
  • @ADyson Could you form the temp folder part into an answer? That seems to be a possible solution. – master2080 Jun 07 '18 at 09:22
  • Yes but if the download is awkward, as it seems to be in this case, then it's legitimate to suggest an alternative approach based on the information available. Anyway, try the link posted by Stephen, or my suggestion earlier to to post the data to the server using AJAX, save the file in a temp folder, return the file ID, then do a window.open to a second action using a GET and passing the file ID, which will do the download. I will try to write it up as a plausible answer. – ADyson Jun 07 '18 at 09:22

1 Answers1

2

Downloading files via ajax doesn't work because the data ends up in memory in a JS object, not on the user's device. Ultimately you need to use a normal HTTP request and return a FileResult.

However in your case you also need to upload some data first which needs to be added to the PDF before it's downloaded. This is awkward because the download will have to be a GET request triggered in a separate window (because you need the application to remain on the same page afterwards) and supplying that data on the querystring is unlikely to be practical.

A solution to work round this is to have a two-step process:

1) From the browser, upload your data via AJAX to a "EditPDF" action method. In the action method, edit the PDF using the new data, and save it. Then return some sort of unique ID to the client which identifies the correct PDF.

2) When the browser receives the response from the EditPDF method, it grabs the returned ID, and makes a new window.open call to the "GetPDF" action's URL. This action accepts the PDF ID as a querystring parameter, so it's easy to include it in the URL when making the request. This action locates the correct document on the server, and returns it in a FileResult. The browser will download the document, while not affecting the HTML page being browsed.

ADyson
  • 57,178
  • 14
  • 51
  • 63