¿Cómo puedo presentar un archivo para descargar desde un controlador MVC?

En WebForms, normalmente tendría un código como este para permitir que el navegador presente una ventana emergente de “Descargar archivo” con un tipo de archivo arbitrario, como un PDF, y un nombre de archivo:

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() 

¿Cómo realizo la misma tarea en ASP.NET MVC?

Devuelve un FileResult o FileStreamResult de tu acción, dependiendo de si el archivo existe o lo creas sobre la marcha.

 public ActionResult GetPdf(string filename) { return File(filename, "application/pdf", Server.UrlEncode(filename)); } 

Para forzar la descarga de un archivo PDF, en lugar de ser manejado por el complemento PDF del navegador:

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

Si desea que el navegador maneje por su comportamiento predeterminado (complemento o descarga), solo envíe dos parámetros.

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

Tendrá que usar el tercer parámetro para especificar un nombre para el archivo en el diálogo del navegador.

ACTUALIZACIÓN: Charlino tiene razón, al pasar el tercer parámetro (nombre de archivo de descarga) Content-Disposition: attachment; se agrega al encabezado de respuesta Http. Mi solución fue enviar application\force-download como mime-type, pero esto genera un problema con el nombre de archivo de la descarga, por lo que se requiere el tercer parámetro para enviar un buen nombre de archivo, eliminando así la necesidad de forzar una descarga .

Puedes hacer lo mismo en Razor o en el Controlador, así que …

 @{ //do this on the top most of your View, immediately after `using` statement Response.ContentType = "application/pdf"; Response.AddHeader("Content-Disposition", "attachment; filename=receipt.pdf"); } 

O en el controlador …

 public ActionResult Receipt() { Response.ContentType = "application/pdf"; Response.AddHeader("Content-Disposition", "attachment; filename=receipt.pdf"); return View(); } 

Intenté esto en Chrome e IE9, ambos están descargando el archivo pdf.

Probablemente debería agregar que estoy usando RazorPDF para generar mis archivos PDF. Aquí hay un blog sobre esto: http://nyveldt.com/blog/post/Introducing-RazorPDF

Debería mirar el método de Archivo del Controlador. Esto es exactamente para lo que es. Devuelve un FilePathResult en lugar de un ActionResult.

mgnoonan,

Puede hacer esto para devolver un FileStream:

 ///  /// 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. ///  /// Excel report [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"); } } 

Use el tipo de archivo .ashx y use el mismo código