İsmet Alkan
İsmet Alkan

Reputation: 5447

Save Controller Call Result as PDF

I'm developing an ASP.NET MVC3 application. I have a controller for file download:

public ActionResult PDF(string id)
{
    try
    {
        // here I unzip a file, DownName comes from here

        Response.Clear();
        Response.AddHeader("Content-Disposition", 
                           "attachment; filename=" + id + ".pdf");
        Response.ContentType = "application/pdf";
        Response.WriteFile(DownName);
        Response.Flush();
        Response.Close();
        System.IO.File.Delete(DownName);
        return View();
    }
    catch (Exception)
    {
        message = "File not found.";
    }

    return Json(new { message = message }, JsonRequestBehavior.AllowGet);
}

At client side, I need to get this PDF file. However, if the file couldn't be found, I will alert a text like "File not found.". I tried many ways and came into this finally:

$(function(){
  $(".pdf").click(function(e) {
    e.preventDefault();
    $.post("@Url.Action("PDF","Helper")",{id : $(this).data("id")},function(data){
      if(data.message == "File not found.") {
        alert(data.message);
      } else {
        alert(data);
      }
    });
  });
});

If file couldn't be found, I can successfully alert error message. How can I open a save dialog box for the data here? Any other way I can work for the controller is appreciated, too.

EDIT: I can download the file easily if I call the controller like this:

<a href="../../Helper/PDF/@Model.ID">Download PDF</a>

However, if the result of this isn't the file and JSON, page is redirected to a blank page displaying the JSON object. I want it to be alert to screen as I said before. I appreciate workarounds with this method, too.

Upvotes: 0

Views: 747

Answers (1)

Jan
Jan

Reputation: 16042

You will have to return a FileResult from your action. Otherwise you won't be able to tell the browser to download the file. When requesting the file data with an async request with javascript, you can't trigger the browser to save that data to a local file.

When you have to be able to check the file for existance you have to provide two actions:

public JsonResult PDFAvailable(string id) {
    // check if the file is there
    return Json(new { message = message }, JsonRequestBehavior.AllowGet);
}

public FileResult PDF(string id) {
    // get the filedata
    byte[] fileData = ...;
    return File(fileData, "application/pdf");
}

In your view you check with the PDFAvailable action id the file is there. When it isn't display your message, otherwise call the PDF action with a normal request:

window.location.href = 
     '@Url.Action("PDF", "YourController", new { id = "yourFileId" })';

EDIT

Regarding to your problem with chrome and setting location.href: This works definitely in chrome. Just make a test: Create a html file with the following content:

<script>
    location.href = "http://www.google.com";
</script>

And open it in chrome. It should redirect your browser to the google homepage. When it does, your code has some other issue. When it doesn't, tell me which version of chrome you are using.

Upvotes: 3

Related Questions