views:

2993

answers:

7

In WebForms, I would normally have code like this to download a PDF:

Response.Clear()
Response.ClearHeaders()
'//Send the file to the output stream
Response.Buffer = True

Response.AddHeader("Content-Length", pdfData.Length.ToString())
Response.AddHeader("Content-Disposition", "attachment; filename= " & Server.HtmlEncode(filename))

'//Set the output stream to the correct content type (PDF).
Response.ContentType = "application/pdf"

'//Output the file
Response.BinaryWrite(pdfData)

'//Flushing the Response to display the serialized data
'//to the client browser.
Response.Flush()
Response.End()

How do I accomplish the same task in ASP.NET MVC?

A: 

I don't think it's the best answer, but you CAN still do that in a view.

GeekyMonkey
+1  A: 

You should look at the File method of the Controller. This is exactly what it's for. It returns a FilePathResult instead of an ActionResult.

Martin Peck
+26  A: 

Return a FileResult or FileStreamResult from your action, depending on whether the file exists or you create it on the fly.

public ActionResult GetPDF( string filename )
{
    return File( filename, "application/pdf", Server.HtmlEncode( filename ) );
}
tvanfosson
This is a great example of why ASP.NET MVC awesome. What you previously had to do in 9 lines of confusing looking code can be done in one line. So much easier!
Jon Kruger
Thanks tvanfosson, I searched for the best solution to do this, and this is great.
Mark Kadlec
A: 

Use .ashx file type and use the same code

ifesdjeen
+1  A: 

mgnoonan,

You can do this to return a FileStream:

/// <summary>
/// Creates a new Excel spreadsheet based on a template using the NPOI library.
/// The template is changed in memory and a copy of it is sent to
/// the user computer through a file stream.
/// </summary>
/// <returns>Excel report</returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult NPOICreate()
{
    try
    {
        // Opening the Excel template...
        FileStream fs =
            new FileStream(Server.MapPath(@"\Content\NPOITemplate.xls"), FileMode.Open, FileAccess.Read);

        // Getting the complete workbook...
        HSSFWorkbook templateWorkbook = new HSSFWorkbook(fs, true);

        // Getting the worksheet by its name...
        HSSFSheet sheet = templateWorkbook.GetSheet("Sheet1");

        // Getting the row... 0 is the first row.
        HSSFRow dataRow = sheet.GetRow(4);

        // Setting the value 77 at row 5 column 1
        dataRow.GetCell(0).SetCellValue(77);

        // Forcing formula recalculation...
        sheet.ForceFormulaRecalculation = true;

        MemoryStream ms = new MemoryStream();

        // Writing the workbook content to the FileStream...
        templateWorkbook.Write(ms);

        TempData["Message"] = "Excel report created successfully!";

        // Sending the server processed data back to the user computer...
        return File(ms.ToArray(), "application/vnd.ms-excel", "NPOINewFile.xls");
    }
    catch(Exception ex)
    {
        TempData["Message"] = "Oops! Something went wrong.";

        return RedirectToAction("NPOI");
    }
}
Leniel Macaferi
+4  A: 

To force the download of a PDF file, instead of being handled by the Browser PDF plugin:

public ActionResult DownloadPDF()
    {
        return File("~/Content/MyFile.pdf", "application/pdf", "MyRenamedFile.pdf");
    }

If you want to let the browser handle by its default behavior (plugin or download), just send two parameters.

public ActionResult DownloadPDF()
    {
        return File("~/Content/MyFile.pdf", "application/pdf");
    }

You'll need to use the third parameter to specify a name for the file on the browser dialog.

Technically what's happening is that the MIME type of "application/force-download" doesn't exist and the default action for the browser is to show a file download dialog.

UPDATE: Charlino is right, when passing the third parameter (download filename) Content-Disposition: attachment; gets added to the Http Response Header. My solution was to send application\force-download as the mime-type, but this generates a problem with the filename of the download so the third parameter is required to send a good filename, therefore eliminating the need to "force a download".

UberNeet
Technically that's not what is happening. Technically when you add the third parameter, the MVC framework adds the header `content-disposition: attachment; filename=MyRenamedFile.pdf` - this is what forces the download. I would suggest you put the MIME type back to `application/pdf`.
Charlino
Thank you Charlino, I didn't realized the third parameter was doing that, I thought it was just to change the filename.
UberNeet
+1 for updating your answer and explaining the third parameter + `Content-Disposition: attachment;` relationship.
Charlino
A: 

My question is after returning Stream in FileStreamResult, how to display that stream as PDF in a view

Anil