2013-10-28 2 views
8

Ich habe in PhantomJS untersucht und sieht aus, wie es ein großartiges Tool zum Generieren von PDFs sein könnte. Ich frage mich, ob jemand es erfolgreich für ihre .NET-Anwendungen verwendet hat.Generieren von PDFs mit Phantom JS auf .NET-Anwendungen

Meine spezifische Frage ist: Wie würden Sie Module wie rasterize.js auf dem Server verwenden, Anfragen empfangen und generierte PDFs als Antwort zurücksenden.

Meine allgemeine Frage ist: gibt es eine Best Practice für die Verwendung von phantomJS mit .NET-Anwendungen. Was wäre der beste Weg, dies zu erreichen?

Ich bin ziemlich neu in .NET World und ich würde die detaillierteren Antworten schätzen. Danke an alle. :)

Antwort

13

Ich weiß nicht, über die besten Praktiken, aber ich bin mit PhantomJS ohne Probleme mit dem folgenden Code.

public ActionResult DownloadStatement(int id) 
{ 
    string serverPath = HttpContext.Server.MapPath("~/Phantomjs/"); 
    string filename = DateTime.Now.ToString("ddMMyyyy_hhmmss") + ".pdf"; 

    new Thread(new ParameterizedThreadStart(x => 
    { 
     ExecuteCommand("cd " + serverPath + @" & phantomjs rasterize.js http://localhost:8080/filetopdf/" + id.ToString() + " " + filename + @" ""A4"""); 
    })).Start(); 

    var filePath = Path.Combine(HttpContext.Server.MapPath("~/Phantomjs/"), filename); 

    var stream = new MemoryStream(); 
    byte[] bytes = DoWhile(filePath); 

    return File(bytes, "application/pdf", filename); 
} 

private void ExecuteCommand(string Command) 
{ 
    try 
    { 
     ProcessStartInfo ProcessInfo; 
     Process Process; 

     ProcessInfo = new ProcessStartInfo("cmd.exe", "/K " + Command); 
     ProcessInfo.CreateNoWindow = true; 
     ProcessInfo.UseShellExecute = false; 

     Process = Process.Start(ProcessInfo); 
    } 
    catch { } 
} 

public ViewResult FileToPDF(int id) 
{ 
    var viewModel = file.Get(id); 
    return View(viewModel); 
} 

private byte[] DoWhile(string filePath) 
{ 
    byte[] bytes = new byte[0]; 
    bool fail = true; 

    while (fail) 
    { 
     try 
     { 
      using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 
      { 
       bytes = new byte[file.Length]; 
       file.Read(bytes, 0, (int)file.Length); 
      } 

      fail = false; 
     } 
     catch 
     { 
      Thread.Sleep(1000); 
     } 
    } 

    System.IO.File.Delete(filePath); 
    return bytes; 
} 

Hier ist die Wirkungsablauf:

Der Benutzer klickt auf einen Link zu DownloadStatement Action. Dort wird eine neue Thread erstellt, um die Methode ExecuteCommand aufzurufen.

Die Methode ExecuteCommand ist dafür verantwortlich, phantomJS aufzurufen. Die als Argument übergebene Zeichenfolge führt Folgendes aus.

Gehen Sie zum Speicherort der phantomJS-App und rufen Sie anschließend rasterize.js mit einer URL, dem zu erstellenden Dateinamen und einem Druckformat auf. (More about rasterize here).

In meinem Fall, was ich wirklich drucken möchte, ist der Inhalt von action Filetoupload geliefert. Es ist eine einfache Aktion, die eine einfache Ansicht zurückgibt. PhantomJS wird die als Parameter übergebene URL aufrufen und all die Magie vollbringen.

Während phantomJS immer noch die Datei erstellt, (ich schätze) kann ich die Anfrage des Clients nicht zurückgeben. Und deshalb habe ich die DoWhile Methode verwendet. Es wird die Anfrage halten, bis die Datei von phantomJS erstellt und von der App auf die Anfrage geladen wird.

+0

Danke Felipe. Das ist toll. – Balash

+4

Sie könnten Process.WaitForExit anstelle einer do while-Schleife verwenden. http://msdn.microsoft.com/en-us/library/fb4aw7b8(v=vs.110).aspx –

+0

Das funktioniert nicht, wenn die Anwendung in IIS unter Windows Server 2008+ ausgeführt wird. Diese Lösung funktioniert, wenn Sie sie aus Visual Studio testen, aber nicht in der Produktion funktionieren, wenn sie in IIS bereitgestellt wird, http://StackOverflow.com/a/5308011/1062224. –

1

Wenn Sie für die Verwendung von NReco.PhantomJS, die einen .NET-Wrapper für PhantomJS bietet, offen sind, können Sie dies sehr prägnant tun.

public async Task<ActionResult> DownloadPdf() { 
    var phantomJS = new PhantomJS(); 
    try { 
     var temp = Path.Combine(Path.GetTempPath(), 
      Path.ChangeExtension(Path.GetRandomFileName(), "pdf")); //must end in .pdf 
     try { 
      await phantomJS.RunAsync(HttpContext.Server.MapPath("~/Scripts/rasterize.js"), 
       new[] { "https://www.google.com", temp }); 
      return File(System.IO.File.ReadAllBytes(temp), "application/pdf"); 
     } 
     finally { 
      System.IO.File.Delete(temp); 
     } 
    } 
    finally { 
     phantomJS.Abort(); 
    } 
}