December 26, 2011

Delayed Download Prompt in ASP.NET MVC 3

There may be times when it's handy to prompt users to download a file after a slight delay. Such a delay can be useful because it gives users time to review a page's content before they are prompted to save. A good example of this technique can be found on SourceForge whenever a visitor attempts to download a project.

How can this be accomplished using ASP.NET MVC 3? Let's make a small use case to illustrate our goal and then dig into some sample code:
  1. Load a "download" page.
  2. After a 2 second delay, prompt the user to save a PDF document. (In this case we do not want the browser to use any plugins to render the document).
As per usual, Stack Overflow had a great post to get me started:
$(function() {
 $(window).bind('load', function() { 
  $("div.downloadProject").delay(2000).append(
    ''); 
   });
});
Be sure to include the following in our Html:
This code inserts an iframe into the DOM after a 2 second delay. This iframe is responsible for triggering the prompt to save the PDF. Unfortunately, I could not get this to work in ASP.NET MVC 3 by just referencing the path to the PDF in the source attribute of the iframe. To solve this, I added an action (and associated routing rules) to my Home controller for downloading the PDF as a FileContentResult.
public ActionResult DownloadPDF()
{
 return File("~/FileToDownload.pdf", "application/pdf", "FileToDownload.pdf");           
}
Including the third parameter in the "File" method adds the "Content-Disposition: attachment;" header - this forces the browser to handle the file using the save dialog prompt instead of any browser plugins.

To finish up, we'll revisit the jQuery code we started with and point the iframe to our new action instead of the direct path to the PDF.
$(function() {
 $(window).bind('load', function() { 
  $("div.downloadProject").delay(2000).append(
    ''); 
   });
});

No comments: