MVC 导出PDF

时间:2023-03-09 00:58:31
MVC 导出PDF

http://www.simple-talk.com/dotnet/asp.net/asp.net-mvc-action-results-and-pdf-content/

http://www.subvert.ca/Blog/wkhtmltopdf-in-MVC3

http://www.cnblogs.com/ryanding/archive/2010/12/26/1915915.html

http://www.cnblogs.com/shanyou/archive/2012/09/07/2676026.html

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.