Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating PDFs using Phantom JS on .NET applications

I have been looking into phantomJS and looks like it could be a great tool to use generating PDFs. I wonder if anyone have successfully used it for their .NET applications.

My specific question is: how would you use modules like rasterize.js on the server, receive requests and send back generated pdfs as a response.

My general question is: is there any best practice for using phantomJS with .NET Applications. What would be the best way to achieve it?

I am fairly new in .NET World and I would appreciate the more detailed answers. Thanks everyone. :)

like image 649
Balash Avatar asked Oct 28 '13 22:10

Balash


2 Answers

I don't know about best practices, but, I'm using phantomJS with no problems with the following 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;
}

Here is the action flow:

The user clicks on a link to DownloadStatement Action. Inside there, a new Thread is created to call the ExecuteCommand method.

The ExecuteCommand method is responsible to call phantomJS. The string passed as an argument do the following.

Go to the location where the phantomJS app is and, after that, call rasterize.js with an URL, the filename to be created and a print format. (More about rasterize here).

In my case, what I really want to print is the content delivered by the action filetoupload. It's a simple action that returns a simple view. PhantomJS will call the URL passed as parameter and do all the magic.

While phantomJS is still creating the file, (I guess) I can not return the request made by the client. And that is why I used the DoWhile method. It will hold the request until the file is created by phantomJS and loaded by the app to the request.

like image 111
Felipe Miosso Avatar answered Nov 18 '22 12:11

Felipe Miosso


If you're open to using NReco.PhantomJS, which provides a .NET wrapper for PhantomJS, you can do this very succinctly.

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();
    }
}
like image 1
user2880616 Avatar answered Nov 18 '22 13:11

user2880616