Cómo renderizar una vista ASP.NET MVC en formato PDF

Estoy trabajando con la utilidad de conversión de Html a PDF de ExpertPDF para esta pregunta (aunque estoy abierto a otras bibliotecas si hay suficiente documentación).

En resumen, tengo una vista que está formateada de una manera específica y me gustaría presentarla como un documento PDF que el usuario puede guardar en el disco.

Lo que tengo hasta ahora es un PrintService (que implementa una interfaz IPrintService) y esta implementación tiene dos sobrecargas para PrintToPDF (), una que toma solo una URL y otra que toma una cadena HTML, y ambas devuelven un byte []. Solo he resuelto los detalles de la segunda sobrecarga que requiere la cadena HTML.

Lo que me gustaría hacer desde mi controlador es algo como:

public FileStreamResult Print(int id) { var model = _CustomRepository.Get(id); string renderedView = SomethingThatRendersMyViewAsAString(model); Stream byteStream = _PrintService.PrintToPdf(renderedView); HttpContext.Response.AddHeader("content-disposition", "attachment; filename=report.pdf"); return new FileStreamResult(byteStream, "application/pdf"); } 

que en teoría convertiría un PDF a la página. Es el “SomethingThatRendersMyViewAsAString” con el que estoy buscando ayuda. ¿Hay una manera rápida de obtener la representación de cadena de una Vista? O tal vez debería seguir con la sobrecarga de URL y pasar una URL a la vista … ¿Alguna otra idea?

¡Gracias!

Es posible que pueda acceder a la respuesta durante OnResultExecuting y reemplazar la propiedad Filter con algo que almacene el HTML resultante en un MemoryStream. Luego puede borrar la respuesta durante OnResultExecuted y reemplazarla con los resultados de su conversión de PDF. Sin embargo, no estoy seguro de que esto sea mejor que obtener el HTML de la URL.

  public FileStreamResult Print(int id) { var model = _CustomRepository.Get(id); this.ConvertToPDF = true; return View( "HtmlView" ); } public override OnResultExecuting( ResultExecutingContext context ) { if (this.ConvertToPDF) { this.PDFStream = new MemoryStream(); context.HttpContext.Response.Filter = new PDFStreamFilter( this.PDFStream ); } } public override OnResultExecuted( ResultExecutedContext context ) { if (this.ConvertToPDF) { context.HttpContext.Response.Clear(); this.PDFStream.Seek( 0, SeekOrigin.Begin ); Stream byteStream = _PrintService.PrintToPDF( this.PDFStream ); StreamReader reader = new StreamReader( byteStream ); context.HttpContext.Response.AddHeader( "content-disposition", "attachment; filename=report.pdf" ); context.HttpContext.Response.AddHeader( "content-type", "application/pdf" ); context.HttpContext.Response.Write( reader.ReadToEnd() ); } } 

El PDFStreamFilter necesitaría anular el (los) método (s) “Escribir” y enviar los datos a la secuencia de la memoria en su lugar.

Empaqueté mi solución en un paquete de Nuget: Rotativa http://nuget.org/packages/Rotativa . Está basado en wkhtmltopdf.

El uso es realmente simple.

Tener una acción que le gustaría servir como Pdf, en lugar de la página Html. Puede definir una acción que devuelva un ActionResult del tipo ActionAsPdf (RouteAsPdf también está disponible). Entonces el código es simplemente:

 public ActionResult PrintIndex() { return new ActionAsPdf("Index", new { name = "Giorgio" }) { FileName = "Test.pdf" }; } 

Con name = “Giorgio” es un parámetro de ruta.

Funciona incluso si la acción para imprimir está protegida por autenticación de formularios web (atributo [Authorize])

Esto suena como un problema similar que tuve donde quería utilizar Vistas como plantillas de correo electrónico. La mejor respuesta que encontré para obtener la representación de cadena de una Vista fue aquí: Renderizar una vista como una cadena

El mejor paquete que he encontrado es el RazorPDF , disponible como paquete en NuGet.org, basado en iTextSharp . Funciona en los sitios web de Azure:

https://nuget.org/packages/RazorPDF