omg, wkhtmltopdf & mvc3?
Blog
October 5, 2011
By Michael Johnson in Programming
Most commented
Why a commercial website CMS is a smarter investment than a homegrown agency solution
The reports of Windows Phone lacking in apps are greatly exaggerated
How the demise of Adobe Fireworks will change our workflow
It’s time for an open source, global social network
Managing the chaos with Task Ave.
Our Windows Phone app, Rhythmatic, wins at the Fast Track to the Mobile App Design Challenge
Building PDFs dynamically using wkhtmltopdf in a MVC3 application
While working on a recent project, I needed to build a series of PDF documents dynamically, then zip them up into a single file. I checked out a couple of options, including iTextSharp and some non-open-source options. I then decided that I liked the looks of wkhtmltopdf.
In my previous life as a Java developer, I had a similar requirement and used iReport to design and fill a Jasper report with data. I knew that I wanted to stay as far away from that solution as possible. I had to have the ability to quickly make data/style/layout changes and have them all testable, without having to recompile or redeploy anything.
The solution I came up with used Razor views just like any other MVC3 page. So, I was able to preview and debug those views without having to actually generate the PDF, download it, and open it. Once I had the views perfected, I built a few helper classes that would render the view in the background, then use the wkhtmltopdf engine to build my PDF.
wkhtmltopdf introduced a couple of interesting problems, not the least of which is that it uses an executable to generate the PDF. I got around that by putting the executable into my application’s bin directory. This gave me the ability to fire it up in a process, sending in the appropriate parameters, then wait for it to finish and grab the file it created.
I put the following method into a helper class and pass into it an instance of my HttpServerUtilityBase so that I can get the executable’s path, and the url to my view that I had previously developed. It saves the PDF to a temp file, then I read the bytes from it, and promptly delete it.
public byte[] ConvertHtmlToPDF(HttpServerUtilityBase server, string inputUrl)
{
byte[] bytes = null;
FileInfo tempFile = new FileInfo(Path.GetTempFileName());
StringBuilder argument = new StringBuilder();
argument.Append(" --disable-smart-shrinking");
argument.Append(" --no-pdf-compression");
argument.Append(" " + inputUrl);
argument.Append(" " + tempFile.FullName);
try
{
// to call the exe to convert
using (Process p = new System.Diagnostics.Process())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = server.MapPath("/bin/wkhtmltopdf.exe");
p.StartInfo.Arguments = argument.ToString();
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.Start();
p.WaitForExit();
}
using (FileStream stream = new FileStream(tempFile.FullName, FileMode.Open, FileAccess.Read))
{
bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
}
}
catch (Exception)
{
//logging
}
tempFile.Delete();
return bytes;
}
Depending on your application, once you have the byte array, you can just return that to the client in a FileResult using the appropriate mime-type or drop them into a ZIP file like I did. Hopefully this will help you guys out there that need to produce PDFs in your next MVC3 project.
Comments
No comments available.