Creating PDFs from ASP.NET MVC Applications with Rotativa

As much as the business world has shifted toward a paperless environment, business applications still frequently need to produce paper documents. This often presents a challenge, as printing documents directly from a Web browser cedes control regarding the layout and output to the end users and their preferred browsers. PDF generation libraries are available, but they are often costly. Those costs aren’t just in terms of purchase price. The costs are also in terms of the time required for developers to learn a new technology tool or stack followed by the time to re-invent existing views so that they can be displayed and printed as PDF documents. This is often a point of frustration, especially when printing needs are both small, and important. Some documents still absolutely must be printed, but not enough that we want to invest in buying and learning expensive tools to do it.

Enter Rotativa, a free, open source product, built on top of the wkhtmltopdf command line tool and Web Kit rendering engine. Available as a NuGet package, it can be added to your MVC Web Application simply and easily. Rotativa allows developers to produce a PDF from ASP.NET MVC views and actions, simply by wrapping the action with a call to Rotativa’s ActionAsPDF or ViewAsPdf method.

Does It Work?

I was initially skeptical of using a tool like this. While other tools such as Telerik Reporting might require a learning curve, they literally allow developers to drag and drop controls onto a paper-sized canvas and specify countless print related settings. Does Rotativa handle page breaks well? Does it support document headers, repeating page headers, margin settings, and the like? The answer is a resounding yes!

As an example, consider a document like an invoice or bill of lading. The document will need to include a document header, displaying a logo, business address, customer name and address, and the date of the transaction. The document will also need to include individual line items, possibly spanning multiple pages. The column headings for the line item should display on the first page, but also be repeated at the top of subsequent pages. Rotativa fully supports a scenario like that, leveraging a well-structured HTML element tree. If a page break is needed inside of a table, the thead element for the active table is repeated on each page that table body displays on.

In addition, standard CSS print rules, such as page-break-after, page-break-before, and page-break-inside are honored. If a block of the document needs to stay together, setting the page-break-inside: avoid rule for that block element forces a page break before the element if it won’t fit on the remaining space of the current page.

Rotativa also exposes the command line switches for the wkhtmltopdf engine. This provides the developer with control over page orientation, margins, and paper size, among others, giving the developer nearly limitless control over the appearance of the document, something that is lost when printing a web page from the browser and relying on each individual user’s browser selection and preferences.

Modern Documents

Using a WYSIWIG tool to generate PDFs also introduces some limitations that Rotativa avoids. For instance, modern client side technologies have made us expect fluid, dynamic interfaces, whereas many of these reporting tools are more analogous to creating a fixed layout report with Microsoft Access or building a Windows Forms desktop application. With Rotativa developers can leverage the dynamic layouts that we expect on the web and translate them to paper. No more fixed column widths or awkward proprietary scripting hacks to change the appearance and position of data on the document. Just about everything you can do in a web application with MVC, CSS, HTML, and JavaScript (minus live interaction, of course) is available. Rather than a hardened, fixed layout for documents, elements can be added, removed and resized, just as they would in a responsive web application.

Tips and Tricks

Working with Rotativa, while it doesn’t require developers to learn to use a new WYSIWIG editor, or scripting language, does have some learning curve and quirks of its own.

First, the wkhtmltopdf command line engine embedded with Rotativa significantly increases your project’s footprint; it’s roughly a 30 MB executable that must be deployed with the application. Depending on the environments you work with, that can greatly slow deployments. Once the “Rotativa” folder is added to your target environment, it’s helpful to remove it from subsequent deployments, either manually or by modifying your build scripts.

Second, because Rotativa delegates the rendering of an MVC page to another browser (WebKit) before it renders the output to PDF, errors can occur in that process that have undesired effects. In one instance, we had the WebKit engine fail to load a stylesheet, rendering an ugly, unstyled version of the PDF, with no errors or explanations. After updating the MVC solution so that it rendered the contents of stylesheets and script files inline into the MVC view, the speed and reliability of the PDF generation improved significantly.

Finally, some command line switches for wkhtmltopdf have been exposed as easy-to-use properties (e.g. PageSize, PageOrientation), but some parameters can only be set as part of a long command line string, such as the URL for a page footer and margin settings. If you are going to be working with those properties a lot, or making them dynamic based on user input, consider investing in a helper class that exposes those properties in a more granular fashion, and renders the custom switch string programmatically. This can help avoid some frustrating errors when changing those settings.

A Nice Addition to the Arsenal

Printing is often a frustrating afterthought in web applications. Having a tool like Rotativa in your arsenal, you can treat printing like a first-class activity, making both users and developers happy.

Leave a Reply

Your email address will not be published. Required fields are marked *