lunes, 16 de marzo de 2015

Pdf en ASP.NET MVC - MvcRazorToPdf

Tarde o temprano, generar contenido pdf en una aplicación web es algo que nos tocará hacer.

En el caso de ASP.NET MVC, yo he optado por el paquete de Nuget MvcRazorToPdf

Esta solución se basa en iTextSharp (el port de .NET de iText) e iTextSharp XML Worker, un add-on para iText que permite convertir HTML a PDF.

Lo que agrega MvcRazorToPdf es un nuevo tipo PdfActionResult que hereda de ViewResult. De este modo, crear un documento PDF es tan sencillo como crear un método de acción que devuelva una instancia del tipo PdfActionResult (que procesará nuestra vista con normalidad y convertirá a PDF el HTML resultante).

return new PdfActionResult(model);

Actualmente parece haber un problema con el paquete de Nuget y la versión de sus dependencias. Para solucionarlo (aunque entiendo que estará solucionado en futuras versiones del paquete), bastará con ejecutar los siguientes comandos en la consola de Nuget:

Install-Package iTextSharp -version 5.5.3

Install-Package itextsharp.xmlworker -version 5.5.3

Además del ejemplo básico, PdfActionResult tiene algunas sobrecargas que pueden resultarnos muy útiles, por ejemplo hay uno donde tenemos acceso al documento que se está generando, así como al writer utilizado. Lo cierto es que no quisiera tener que lidiar mucho con la generación en bruto de PDF a través de iTextSharp, pero para algunos escenarios podría ser necesario:

return new PdfActionResult(model, (writer, document) => document.SetPageSize (PageSize.A4));

Incluso podemos especificar que directamente devuelva el PDF como un archivo para su descarga:

return new PdfActionResult(model, (writer, document) => document.SetPageSize (PageSize.A4))

{

    FileDownloadName = "Example.pdf"

};

También podemos generar ficheros PDF en el servidor (gracias a un método extensor de ControllerContext) y ya después hacer con él lo que creamos oportuno:

byte[] output = ControllerContext.GeneratePdf();

var path = Server.MapPath("~/App_Data/Order.pdf");

if (System.IO.File.Exists(path))

{

    System.IO.File.Delete(path);

}

System.IO.File.WriteAllBytes(path, output);

return File(path, "application/pdf", Path.GetFileName(path));

Si hasta aquí todo ha sido contar las bondades de MvcRazorToPdf, la parte negativa la encontramos no ya en el propio paquete, sino en su dependencia con iTextSharp XML Worker. Durante el proceso de convertir el HTML a PDF, hay perdidas…He empleado más tiempo en bregar con las rarezas de iTextSharp XML Worker, que en todo lo demás. Cierto es que encontré tarde la documentación de iTextSharp XML Worker e incluso un editor WYSIWYG, pero cosas como tener que utilizar el atributo valign en vez de la propiedad CSS vertical-align, o tener que generar para las imágenes rutas absolutas en vez de relativas, son cosas que tendrás que aprender con el manido método ensayo-error. En cualquier caso, para algo sencillo seguiré apostando por esta solución.

Un saludo!

4 comentarios:

  1. Hace cierto tiempo tuve que enfrentarme al problema de pasar un html que venía de un wysiwyg a pdf usando itext.

    Efectivamente, un auténtico infierno imposible de manejar. Cienmilmillones de tutoriales con el xml worker / html worker que no llevaban a ningún lado salvo a la desesperación y frustración más absoluta.

    Al final encontré un tuto de un señor de oriente medio que tenía el cacho de código que necesitaba y que hacía bien la transformación.

    A pesar de ello, no hubo manera de integrarlo al 100% con el resto del estilo del pdf...

    Sinceramente, no entiendo cómo a estas alturas de la vida y la tecnología este tipo de cosas siguen siendo complejas :-/

    ResponderEliminar
    Respuestas
    1. Buenos días, tenéis toda la razón es una odisea poder generar pdf complejos con esta herramienta.
      Ahora mismo estoy con el problema del wysiwyg, podrías indicarme algún camino oriental que seguir.

      Saludos y gracias.

      Eliminar
  2. Estoy de acuerdo, mi experiencia no ha sido muy positiva, ya lo decía en el post, para algo sencillito sí, para el resto no lo tengo claro.
    Para un WYSIWYG no quiero ni pensarlo, tuvo que ser un buen dolor de cabeza. :(
    Me he quedado con ganas de probar esto http://wkhtmltopdf.org/ aunque imagino no será ninguna solución definitiva tampoco (con pdf mi pesimismo ha ido in crescendo)
    Habrá que seguir viendo alternativas.
    Un saludo.

    ResponderEliminar