Click here to Skip to main content
Click here to Skip to main content

Rotativa, how to print PDF in ASP.NET MVC

By , 24 Feb 2012
 

Creating PDF docs in Asp.Net MVC is a fairly common functionality requested by LOB applications. Usually either for reporting or, more often, for having printable friendly documents (invoices, receipts etc).

I used to design a Crystal Report document and then evaluate it and convert it to PDF in the web application. The desing part was OK but what really bothered me was the problems that often came up with deploying it. Version mismatches could really turn it into a nightmare.

Lately I came up using the excellent wkhtmltopdf tool to convert html content to PDF. It uses the WebKit engine (used by Chrome and Safari) to render HTML. The nice thing about it is that I can leverage my knowledge of html and css to obtain a good looking PDF and also it's quite fast.

It's an exe file not a DLL library (a DLL actually exists but it's not managed code and it has some problems related to usage in a multi-threaded app). It has to be executed from the Asp.net app spawning a process, so it requires some unusual coding from a web development perspective. Another downside is that it requires some work to set it up: copying exe and dll files in the web app solution, make sure they get copied over when building and publishing and some config stuff needed to make it access authenticated actions.

It seemed to me a perfect candidate to become a Nuget package. It was fairly easy to build it, except some quirks when trying to modify package properties.

I've named it Rotativa /rota'tiva/, which is Italian for rotary printing press. With Rotativa, all it takes to print a PDF is:

  1. Install using the Nuget package manager (search for Rotativa) or, more conveniently, with the package manager console, typing:
  2. Install-Package Rotativa
  3. Writing a controller action to return a view representing the desired PDF output. This means just coding as usual to serve the data as regular MVC action. Such as:
  4. public ActionResult Invoice(int invoiceId)
    {
        var invoiceViewModel;
        // code to retrieve data from a database
        return View(invoiceViewModel);
    }

    Nothing special here, just an action. Perhaps the view used will have a different master page (or layout page) then the other views of the web app (or you’ll define a separete css for the print media, see http://www.w3.org/TR/CSS2/media.html). You can test and “preview” the results just using the browser, since we are working with a regular action, returning a html result.

  5. When the html is ok you can just setup a special action returning a custom ActionResult: ActionAsPdf. The code will look like this:
  6. public ActionResult PrintInvoice(int invoiceId)
    {
      return new ActionAsPdf(
                     "Invoice", 
                     new { invoiceId= invoiceId }) 
                     { FileName = "Invoice.pdf" };
    }

ActionAsPdf requires a string parameter with the name of the action to be converted to PDF. It can accept a parameter with other route data, in this case we are defining the invoiceId parameter. You can specify the name of the file being returned using the FIleName property.

To link to the PDF file in other views you just have to insert a regular link to the PrintInvoice action. Something like:

@Html.ActionLink(“PrintInvoice”)

if you’re working with razor views.

And voila, that’s all and it just works, even if the printed action is protected with forms authentication.

Source code is on GitHub https://github.com/webgio/Rotativa.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Giorgio Bozio
Italy Italy
Member
Software architect. At present working on C# development, with mainly Asp.net Ajax and MVC user inteface. Particularly interested in OOP, test driven, agile development.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralBravo!memberpeter gabris21 Apr '13 - 18:03 
Pleasure to read, pleasure to use.
 
Thank you for the great work.
 
Peter
GeneralRe: Bravo!memberGiorgio Bozio26 Apr '13 - 4:12 
Thank you Peter!
 
I appreciate a lot user support!
 
Ciao,
 
Giorgio
QuestionDefault type problemmemberfedericolaggiard19 Apr '13 - 0:07 
Hi!
 
First of all thanks for the library, is very useful.
I've implemented it in my project and everything works fine until I move it to production servers (as usual!), here a strange error came up: "Impossibile caricare il tipo 'NBC.Default'" which stands for "unable to load 'NBC.Default' type" (NBC is my namespace, ".Default" means nothing to me...) the action that I'm trying to call which renders the page is never called, that error is raised instead. Authentication is performed outside of my application (everything runs into an iframe) so my web.config use .
 
Can somebody help me?
Thanks
AnswerRe: Default type problemmemberGiorgio Bozio26 Apr '13 - 4:11 
Ciao Federico,
that's a strange exception! Did you manage to solve the problem? You could check Rotativa on the server by running the demo project you can find in the Github repository: https://github.com/webgio/Rotativa
QuestionReturn PDF only?memberCodeDog Billy11 Apr '13 - 12:25 
Hello!
 
I have implemented the latest version of your Rotativa package (an MVC website application) and am REALLY loving how easy this is/was to install and use! It performs well and 'just as shown on TV', as it were! So, thank you VERY much.
 
Question
Now... is there a way to return 'just' the PDF that was built? I am wanting to route the PDF back into the SQL database, instead of showing the user a 'summary' page, or even using the ViewAsPdf(viewModel) in an Action to have the 'view' downloaded to the user's machine as a PDF.
 
Intent
I am showing the user a 'summary' page (similar to a shopping cart's Order Preview). On this page, they must 'approve' the settings AND eSign (a digital signature). Those two new settings, along with the 'summary' are then transformed into a PDF via your ViewAsPdf(viewModel) mechanism... but, I'd really rather just save that PDF RIGHT back into the database (MS SQL) and not rely on the user printing the document and uploading it back to us. We need/want a copy of the Summary (order) they submitted.
 
So... hoping you have a workaround or some guidance as to how I can just get the PDF file into an object (Btye[]), and I can pass that back to the database table as a varbinary field.
Bill Elliott, MDiv, MCP

AnswerRe: Return PDF only?memberGiorgio Bozio11 Apr '13 - 23:11 
Thanks Bill, you can use the new BuildPdf method, it returns a byte[].
 
Here you can find a example:
https://github.com/webgio/Rotativa/blob/master/Rotativa.Demo/Controllers/HomeController.cs#L130[^]
GeneralRe: Return PDF only?memberCodeDog Billy12 Apr '13 - 5:45 
Thank you, Giorgio! I didn't spot the TestBinary action in my snooping around earlier, so this is good! Here is how I am trying/wanting to implement this;
 
Adapted Method
In my HomeController, I put the 'adapted' method below;
public FileContentResult MakePdf(Guid requestId, string fileName)
{
var pdfResult = new ActionAsPdf("RoiRelease", new { rid = requestId }) { FileName = fileName };
var binary = pdfResult.BuildPdf(this.ControllerContext);
return File(binary, "application/pdf");
}
 

In the Approve POST Action
Then, in the POST action (for the user's "approve" page), I have the following code snippet;
//make the PDF from the 'release' action
FileContentResult binaryOfPdf = MakePdf(viewModel.RequestId, pdfFileName);
 
//save that PDF back to the DB
string resultsFromUpdate = MonetaData.SaveRoiReleasePdf(viewModel.RequestId , pdfFileName, binaryOfPdf, viewModel.RoiMain.RequestStatus);
 

 
So, I am trying to use my "SaveRoiReleasePdf" to pass this down to the DB via an SP.
 
I am a bit confused how to use the TestBinary as-is, since it is an Action... can I call that 'like' it was an actual method/function??
GeneralRe: Return PDF only?memberCodeDog Billy12 Apr '13 - 6:12 
Got it!! I adapted the TestBinary to just return a byte[] object, as;
 
public byte[] MakePdf(Guid requestId, string fileName)
{
var pdfResult = new ActionAsPdf("RoiRelease", new { rid = requestId }) { FileName = fileName };
 
var binary = pdfResult.BuildPdf(this.ControllerContext);
 
return binary;
//return File(binary, "application/pdf");
}
 

And THAT allowed my 'save to database' method to work perfectly!! Now, I'll go a little further and apply a 'get file from database' method so the user can review the PDF from their Profile page (similar to getting your monthly statement from a bank or investment account).
 
Again thought... this package of yours is a GEM!! Thank you, again. Thumbs Up | :thumbsup:
Bill Elliot, MDiv, MCP

Questiongr8 solution to something i think the framework should havememberUsha Pini3 Apr '13 - 0:56 
It is working perfect on my win 7 64bit but when i try to run it on my hosting server Windows 2012 + IIS8, support both 32bit and 64bit pool , I'm getting the bellow error
 
"The specified executable is not a valid application for this OS platform."
 
you can see it in the following link
http://www.softclinic.co.il/Reports/PrintPDF/1?patientName=%D7%A4%D7%99%D7%A0%D7%99_%D7%90%D7%95%D7%A9%D7%94[^]
 
Any idea why?
AnswerRe: gr8 solution to something i think the framework should havememberGiorgio Bozio11 Apr '13 - 23:08 
Did you check if the setup is correct? The Rotativa folder is in the asp.net mvc folder with correct security settings? I'll try to setup a similar VM and test it myself though, I didn't test on IIS 8 yet.
Thanks,
Giorgio
GeneralMy vote of 5memberAnkhara9 Jan '13 - 10:33 
Superb piece of work. Just saved me weeks of coding
QuestionGreat Work!memberzyck24 Feb '12 - 15:51 
5up!
GeneralMy vote of 5memberWilliam John Adam Trindade24 Feb '12 - 7:21 
Excellent! Grazie!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 24 Feb 2012
Article Copyright 2012 by Giorgio Bozio
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid