2010-05-07 3 views
30

Nach 10 Stunden und versuchen 4 andere HTML zu PDF-Tools bin ich bereit zu explodieren.Wie wkhtmltopdf.exe in ASP.net zu verwenden

wkhtmltopdf klingt wie eine ausgezeichnete Lösung ... das Problem ist, dass ich nicht so einen Prozess mit genügend Berechtigungen von asp.net ausführen kann ...

Process.Start("wkhtmltopdf.exe","http://www.google.com google.pdf"); 

startet, aber nichts tun. Ich

-a) erlauben asp.net Prozesse zu starten (das tatsächlich etwas tun kann) oder
-b) kompilieren/wrap/was auch immer wkhtmltopdf.exe in somthing:

Gibt es eine einfache Möglichkeit, entweder zu kann von C# wie folgt verwenden: WkHtmlToPdf.Save("http://www.google.com", "google.pdf");

+0

Dies ist keine gute Idee. IIS7 im integrierten Modus verbietet dies, einschließlich Identitätswechsel. –

Antwort

18

Sie könnten auch Pechkin

.NET Wrapper für wkhtmltopdf DLL-Bibliothek verwenden, die Webkit-Engine zu konvertieren HTML-Seiten in PDF verwendet.

Nuget Pakete:

Pechkin.Synchronized

Pechkin

+0

Das habe ich nach all den Jahren als akzeptiert markiert, weil ich wkhtmltopdf einfach wieder für ein neues Projekt verwenden musste und Pechkin hat perfekt funktioniert! –

+0

Ich habe Probleme mit Pechkin oder Codaxy oder sogar WkhtmlXSharp, Sie alle zeigen keine Thai-Schriftarten (Utf-8) oder Unicode-Fonts richtig. Während der Verwendung von iutxtsharp und die exe gibt dieses Problem nicht – WickStargazer

+0

@DavidMurdoch haben Sie Datei sperren Fehler bei der Bereitstellung von neuem Code? Wenn ich es richtig verstehe, verwendet Pechkin eine native DLL (WkHtmlToPdf) und diese native DLL wird möglicherweise nicht als Ihre verwalteten DLLs entladen, wenn Sie neue Dateien hochladen? – Peter

4

Hier ist der eigentliche Code, den ich verwendet habe. Bitte zögern Sie nicht, dies zu bearbeiten, um einige der Gerüche und andere Schrecklichkeit loszuwerden ... Ich weiß, es ist nicht so toll.

using System; 
using System.Diagnostics; 
using System.IO; 
using System.Web; 
using System.Web.UI; 

public partial class utilities_getPDF : Page 
{ 
    protected void Page_Load(Object sender, EventArgs e) 
    { 
     string fileName = WKHtmlToPdf(myURL); 

     if (!string.IsNullOrEmpty(fileName)) 
     { 
      string file = Server.MapPath("~\\utilities\\GeneratedPDFs\\" + fileName); 
      if (File.Exists(file)) 
      { 
       var openFile = File.OpenRead(file); 
       // copy the stream (thanks to http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances-c) 
       byte[] buffer = new byte[32768]; 
       while (true) 
       { 
        int read = openFile.Read(buffer, 0, buffer.Length); 
        if (read <= 0) 
        { 
         break; 
        } 
        Response.OutputStream.Write(buffer, 0, read); 
       } 
       openFile.Close(); 
       openFile.Dispose(); 

       File.Delete(file); 
      } 
     } 
    } 

    public string WKHtmlToPdf(string Url) 
    { 
     var p = new Process(); 

     string switches = ""; 
     switches += "--print-media-type "; 
     switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm "; 
     switches += "--page-size Letter "; 
     // waits for a javascript redirect it there is one 
     switches += "--redirect-delay 100"; 

     // Utils.GenerateGloballyUniuqueFileName takes the extension from 
     // basically returns a filename and prepends a GUID to it (and checks for some other stuff too) 
     string fileName = Utils.GenerateGloballyUniqueFileName("pdf.pdf"); 

     var startInfo = new ProcessStartInfo 
         { 
          FileName = Server.MapPath("~\\utilities\\PDF\\wkhtmltopdf.exe"), 
          Arguments = switches + " " + Url + " \"" + 
             "../GeneratedPDFs/" + fileName 
             + "\"", 
          UseShellExecute = false, // needs to be false in order to redirect output 
          RedirectStandardOutput = true, 
          RedirectStandardError = true, 
          RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none 
          WorkingDirectory = Server.MapPath("~\\utilities\\PDF") 
         }; 
     p.StartInfo = startInfo; 
     p.Start(); 

     // doesn't work correctly... 
     // read the output here... 
     // string output = p.StandardOutput.ReadToEnd(); 

     // 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, it worked 
     return (returnCode == 0) ? fileName : null; 
    } 
} 
+3

Es ist nicht "wenn 0 oder 2, es hat funktioniert". Es funktioniert nur wenn 0. Andere Werte: 1: (oder 8?) Generischer Fehlercodewert von EXIT_ERROR. 2: Fehler 404, nicht gefunden (und leeres PDF). 3: Fehler 401, nicht autorisiert. Gemäß der Unix-Spezifikation signalisiert ein anderer Wert als 0, der von einem Prozess zurückgegeben wird, eine Art Fehler. Dies gilt auch für Windows-Programme. – Christian

+0

danke, +1 für die Korrektur. Der Code (und die Kommentare) stammen ursprünglich von http://stackoverflow.com/questions/1331926/asp-net-calling-exe/1698839#1698839 –

+0

Ich habe sowohl 0.99 und die neuere RC versucht und keiner von ihnen scheint zu Support --redirect-delay - irgendwelche Ideen? Welche Version hast du benutzt? Es macht mich verrückt! Es funktioniert perfekt, abgesehen davon, nicht auf meine Ajax Anrufe zu warten. –

22

Ich habe gerade ein neues Projekt gestartet, um einen C# P/Invoke-Wrapper um wkhtmltopdf bereitzustellen. https://github.com/pruiz/WkHtmlToXSharp

Greets:

Sie können meinen Code an der Kasse.

+0

Wow, das sieht ziemlich glatt aus. Danke für das Teilen! –

+3

Ich bekomme Fehler, wenn ich MultiplexingConverter wie "versucht, geschützten Speicher zu lesen oder zu schreiben. Dies ist oft ein Hinweis darauf, dass anderer Speicher beschädigt ist." Gibt es eine Möglichkeit, diesen Fehler zu vermeiden? – Brennan

+1

Ich bekomme meine Bilder nicht in das PDF eingebettet. Nichts zeigt an, wo das Bild angezeigt werden soll. Ich habe überprüft, ob es aufgrund der relativen URL des Bildes auftrat und es in absolute umgewandelt. Immer noch kein Erfolg. Was würde funktionieren? – sangam

12

Dank Paul habe ich die gute wrapper von Codaxy geschrieben, die auch einfach über NuGet heruntergeladen werden kann.

Nach einigen Versuchen, habe ich dieses MVC Aktion geschafft, das schafft sofort und gibt die PDF-Datei als Stream:

public ActionResult Pdf(string url, string filename) 
{ 
    MemoryStream memory = new MemoryStream(); 
    PdfDocument document = new PdfDocument() { Url = url }; 
    PdfOutput output = new PdfOutput() { OutputStream = memory }; 

    PdfConvert.ConvertHtmlToPdf(document, output); 
    memory.Position = 0; 

    return File(memory, "application/pdf", Server.UrlEncode(filename)); 
} 

Hier ist die PDF * Klassen in der Wrapper implementiert wurden, mit einem Netter, sauberer Code, leider fehlende Dokumentation.

Innerhalb des Konverters wird die URL in ein PDF konvertiert, in einer temporären Datei gespeichert, in den Stream kopiert, den wir als Parameter angegeben haben, und anschließend wird die PDF-Datei gelöscht.

Schließlich müssen wir den Stream als FileStreamResult schieben.

Vergessen Sie nicht, die Position des Ausgabestroms auf Null zu setzen, sonst werden PDF-Dateien als Null-Bytes der Größe heruntergeladen.

+0

Um PDF-Stream über MVC ActionResult direkt im Webbrowser auszugeben, demonstrierte @endy-tjahjono einen guten Ansatz über [hier] (http://stackoverflow.com/questions/6168846/open-pdf-result-in-browser-tab-mit-mvc-3) –

+0

Es funktioniert gut, aber hängen, wenn ich versuche, eine Kopfzeile zu verwenden (die normalerweise mit dem Befehlszeilentool direkt funktioniert). – marquito

+0

@marquito: Meinst du "Header" -Tag in HTML5? Ich habe keine Erfahrung, aber hast du versucht, es durch einen guten alten Freund "div" zu ersetzen? –