0

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.

İsmet Alkan
  • 5,361
  • 3
  • 41
  • 64

1 Answers1

3

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.

Jan
  • 15,802
  • 5
  • 35
  • 59
  • Thanks, but changing `alert(data)` with `location.href = '@Url.Action("PDF", "Helper", new { id = Model.ID })';` worked. However, it doesn't work in Chrome even if I add `return false` statement. – İsmet Alkan May 07 '13 at 11:55
  • @IsmetAlkan do you get an javascript error on that line in Chrome? It should work in chrome, too - its nothing special. I use a very similar approach in my web app and it works across all browsers. – Jan May 07 '13 at 12:42
  • i get no specific error, just no response. you can edit your answer according to what I did in the question, as your answer guided me but it's not fully correct. – İsmet Alkan May 07 '13 at 12:49
  • @IsmetAlkan i have edited my answer. But location.href is definitely working in chrome. Just tried myself. – Jan May 07 '13 at 13:23
  • i wrote google link instead of `Url.Action` and it didn't work too. My chrome version is 26.0.1410.64 m. – İsmet Alkan May 07 '13 at 17:22
  • I tested it with exactly the same version. Maybe your Installatio is broken? Its really nothing fancy to set the location by javascript – Jan May 07 '13 at 17:57
  • See this link: http://stackoverflow.com/questions/13209214/document-location-href-not-working-in-chrome maybe it helps – Jan May 07 '13 at 18:08
  • tried that, for other users: if `window.event` doesn't work, use `e` instead. for me: still works for FF and IE but not chrome. response size is equal to file size, request type and method is right, but status is "failed". at the bottom of the page it even says "198 KB transferred". maybe it's a security option I closed. – İsmet Alkan May 08 '13 at 11:37
  • thanks for your effort, i'm deleting the window.location.href part as it's not the real question. – İsmet Alkan May 08 '13 at 12:15
  • i divided the operation into two parts as controlling existence and downloading, and it worked in chrome, too. here's the question link: http://stackoverflow.com/questions/16440556/window-href-location-not-working-in-chrome. i guess chrome has some security issue for something like multiple calls to a single function. however, i changed all functions result type to actionresult to make it work. anyway, THANK YOU VERY MUCH :) – İsmet Alkan May 09 '13 at 15:45