org generar example downloads desde crear con html asp.net pdf pdf-generation wkhtmltopdf

generar - wkhtmltopdf example



Llamar a wkhtmltopdf para generar PDF a partir de HTML (10)

Consulte la biblioteca contenedora C # (usando P / Invoke) para la biblioteca wkhtmltopdf: https://github.com/pruiz/WkHtmlToXSharp

Estoy intentando crear un archivo PDF a partir de un archivo HTML. Después de mirar un poco, he encontrado que wkhtmltopdf es perfecto. Necesito llamar a este .exe desde el servidor ASP.NET. He intentado:

Process p = new Process(); p.StartInfo.UseShellExecute = false; p.StartInfo.FileName = HttpContext.Current.Server.MapPath("wkhtmltopdf.exe"); p.StartInfo.Arguments = "TestPDF.htm TestPDF.pdf"; p.Start(); p.WaitForExit();

Sin éxito de que se creen archivos en el servidor. ¿Alguien puede darme un puntero en la dirección correcta? Puse el archivo wkhtmltopdf.exe en el directorio de nivel superior del sitio. ¿Hay algún otro lugar donde deba celebrarse?

Editar: si alguien tiene mejores soluciones para crear dinámicamente archivos pdf desde html, házmelo saber.


El proceso ASP .Net probablemente no tiene acceso de escritura al directorio.

Intente decirle que escriba en %TEMP% , y vea si funciona.

Además, haga que su página ASP .Net haga eco de stdout y stderr del proceso, y compruebe si hay mensajes de error.


Generalmente, el código de retorno = 0 viene si el archivo pdf se crea correctamente y correctamente. Si no se crea, entonces el valor está dentro del rango.


Gracias por la pregunta / respuesta / todos los comentarios anteriores. Me encontré con esto cuando escribía mi propio contenedor C # para WKHTMLtoPDF y respondía a algunos de los problemas que tenía. Terminé escribiendo sobre esto en una publicación de blog, que también contiene mi envoltorio (sin duda verás la "inspiración" de las entradas que se filtran en mi código ...)

http://icanmakethiswork.blogspot.de/2012/04/making-pdfs-from-html-in-c-using.html

Gracias de nuevo chicos!


Hay muchas razones por las cuales esto generalmente es una mala idea. ¿Cómo vas a controlar los ejecutables que se generan pero terminan viviendo en la memoria si se produce un bloqueo? ¿Qué sucede con los ataques de denegación de servicio o si algo malintencionado entra en TestPDF.htm?

Según entiendo, la cuenta de usuario ASP.NET no tendrá los derechos para iniciar sesión localmente. También necesita tener los permisos de archivo correctos para acceder al ejecutable y escribir en el sistema de archivos. Debe editar la política de seguridad local y dejar que la cuenta de usuario ASP.NET (quizás ASPNET) inicie sesión localmente (puede estar en la lista de denegación por defecto). Luego necesita editar los permisos en el sistema de archivos NTFS para los otros archivos. Si se encuentra en un entorno de alojamiento compartido, puede ser imposible aplicar la configuración que necesita.

La mejor forma de utilizar un ejecutable externo como este es poner en cola trabajos desde el código ASP.NET y tener algún tipo de servicio que controle la cola. Si haces esto, te protegerás de todo tipo de cosas malas que suceden. En mi opinión, los problemas de mantenimiento con el cambio de la cuenta de usuario no valen la pena, y aunque configurar un servicio o un trabajo programado es un problema, es simplemente un mejor diseño. La página ASP.NET debe sondear una cola de resultados para la salida y puede presentar al usuario una página de espera. Esto es aceptable en la mayoría de los casos.


OK, esta es una vieja pregunta, pero excelente. Y como no encontré una buena respuesta, hice la mía :) Además, publiqué este proyecto súper simple en GitHub.

Aquí hay un código de muestra:

var pdfData = HtmlToXConverter.ConvertToPdf("<h1>SOO COOL!</h1>");

Aquí hay algunos puntos clave:

  • Sin P / Invocar
  • Sin crear un nuevo proceso
  • Sin sistema de archivos (todo en RAM)
  • Native .NET DLL con intellisense, etc.
  • Posibilidad de generar un PDF o PNG ( HtmlToXConverter.ConvertToPng )

Puede decirle a wkhtmltopdf que envíe su salida a sout especificando "-" como el archivo de salida. A continuación, puede leer el resultado del proceso en la secuencia de respuesta y evitar los problemas de permisos al escribir en el sistema de archivos.


Tuve el mismo problema cuando traté de usar msmq con un servicio de Windows, pero fue muy lento por alguna razón. (la parte del proceso).

Esto es lo que finalmente funcionó:

private void DoDownload() { var url = Request.Url.GetLeftPart(UriPartial.Authority) + "/CPCDownload.aspx?IsPDF=False?UserID=" + this.CurrentUser.UserID.ToString(); var file = WKHtmlToPdf(url); if (file != null) { Response.ContentType = "Application/pdf"; Response.BinaryWrite(file); Response.End(); } } public byte[] WKHtmlToPdf(string url) { var fileName = " - "; var wkhtmlDir = "C://Program Files//wkhtmltopdf//"; var wkhtml = "C://Program Files//wkhtmltopdf//wkhtmltopdf.exe"; var p = new Process(); p.StartInfo.CreateNoWindow = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.RedirectStandardInput = true; p.StartInfo.UseShellExecute = false; p.StartInfo.FileName = wkhtml; p.StartInfo.WorkingDirectory = wkhtmlDir; string switches = ""; switches += "--print-media-type "; switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm "; switches += "--page-size Letter "; p.StartInfo.Arguments = switches + " " + url + " " + fileName; p.Start(); //read output byte[] buffer = new byte[32768]; byte[] file; using(var ms = new MemoryStream()) { while(true) { int read = p.StandardOutput.BaseStream.Read(buffer, 0,buffer.Length); if(read <=0) { break; } ms.Write(buffer, 0, read); } file = ms.ToArray(); } // wait or exit p.WaitForExit(60000); // read the exit code, close process int returnCode = p.ExitCode; p.Close(); return returnCode == 0 ? file : null; }

Gracias Graham Ambrose y todos los demás.


Actualizar:
Mi respuesta a continuación, crea el archivo pdf en el disco. Luego transmití ese archivo al navegador de los usuarios como una descarga. Considere usar algo como la respuesta de Hath a continuación para obtener wkhtml2pdf para enviarlo a una transmisión en su lugar y luego enviarlo directamente al usuario; eso omitirá muchos problemas con los permisos de archivos, etc.

Mi respuesta original:
Asegúrese de haber especificado una ruta de salida para el PDF que se puede escribir en el proceso ASP.NET de IIS que se ejecuta en su servidor (generalmente creo que NETWORK_SERVICE).

El mío se ve así (y funciona):

/// <summary> /// Convert Html page at a given URL to a PDF file using open-source tool wkhtml2pdf /// </summary> /// <param name="Url"></param> /// <param name="outputFilename"></param> /// <returns></returns> public static bool HtmlToPdf(string Url, string outputFilename) { // assemble destination PDF file name string filename = ConfigurationManager.AppSettings["ExportFilePath"] + "//" + outputFilename + ".pdf"; // get proj no for header Project project = new Project(int.Parse(outputFilename)); var p = new System.Diagnostics.Process(); p.StartInfo.FileName = ConfigurationManager.AppSettings["HtmlToPdfExePath"]; string switches = "--print-media-type "; switches += "--margin-top 4mm --margin-bottom 4mm --margin-right 0mm --margin-left 0mm "; switches += "--page-size A4 "; switches += "--no-background "; switches += "--redirect-delay 100"; p.StartInfo.Arguments = switches + " " + Url + " " + filename; p.StartInfo.UseShellExecute = false; // needs to be false in order to redirect output p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.RedirectStandardInput = true; // redirect all 3, as it should be all 3 or none p.StartInfo.WorkingDirectory = StripFilenameFromFullPath(p.StartInfo.FileName); p.Start(); // read the output here... string output = p.StandardOutput.ReadToEnd(); // ...then wait n milliseconds for exit (as after exit, it can''t read the output) p.WaitForExit(60000); // read the exit code, close process int returnCode = p.ExitCode; p.Close(); // if 0 or 2, it worked (not sure about other values, I want a better way to confirm this) return (returnCode == 0 || returnCode == 2); }


using System; using System.Diagnostics; using System.Web; public partial class pdftest : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } private void fn_test() { try { string url = HttpContext.Current.Request.Url.AbsoluteUri; Response.Write(url); ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = @"C:/PROGRA~1/WKHTML~1/wkhtmltopdf.exe";//"wkhtmltopdf.exe"; startInfo.Arguments = url + @" C:/test" + Guid.NewGuid().ToString() + ".pdf"; Process.Start(startInfo); } catch (Exception ex) { string xx = ex.Message.ToString(); Response.Write("<br>" + xx); } } protected void btn_test_Click(object sender, EventArgs e) { fn_test(); } }