27

I'm working with ExpertPDF's Html-to-PDF conversion utility for this question (although I'm open to other libraries if there's sufficient documentation).

In short, I have a view that is formatted a specific way and I would like to render it as a PDF document the user can save to disk.

What I have so far is a PrintService (which implements an IPrintService interface) and this implementation has two overloads for PrintToPDF(), one that takes just a URL and another that takes an HTML string, and both of which return a byte[]. I've only worked out the details of the second overload which requires the HTML string.

What I would like to do from my controller is something like:

public FileStreamResult Print(int id)
{
    var model = _CustomRepository.Get(id);
    string renderedView = SomethingThatRendersMyViewAsAString(model);
    Stream byteStream = _PrintService.PrintToPdf(renderedView);
    HttpContext.Response.AddHeader("content-disposition", 
        "attachment; filename=report.pdf");
    return new FileStreamResult(byteStream, "application/pdf");  
}

which in theory would render a PDF to the page. It's the "SomethingThatRendersMyViewAsAString" that I'm looking for help with. Is there a quick way to get the string representation of a View? Or perhaps I should just stick with the URL overload and pass in a URL to the view... Any other thoughts?

Thanks!

1
  • 6
    mannish - were you ever able to post your solution to this anywhere?? it would be increadibly useful. tia Commented Mar 8, 2011 at 10:41

4 Answers 4

104
+250

I packaged my solution in a Nuget package: Rotativa http://nuget.org/packages/Rotativa. It's based on wkhtmltopdf.

Usage is really simple.

Having an action you would like to serve as Pdf, instead of Html page. You can define an action that returns an ActionResult of the type ActionAsPdf (RouteAsPdf is also available). So the code is just:

public ActionResult PrintIndex()
{
    return new ActionAsPdf("Index", new { name = "Giorgio" }) { FileName = "Test.pdf" };
}

With name = "Giorgio" being a route parameter.

It works even if the action to print is protected by web forms authentication ([Authorize] attribute)

Sign up to request clarification or add additional context in comments.

26 Comments

this is by far the easiest solution I have come across for asp.net mvc, thanks a lot...
This is fantastic - thank you! I'll note that I had to specify the forms authentication cookie name (otherwise the login page would be rendered) and change the renderer to use print media styles (FormsAuthenticationCookieName = "MyCookie", CustomSwitches = "--print-media-type"). Very easy!
Rotativa seems to fail with MVC4. When I return an ActionAsPdf I see a string displayed on the screen instead of a PDF.
Works in Azure Web Roles but doesn't work on Azure Web Sites because of limitations to the trust level.
@GuruprasadRao , it's resulting wiht login page on pdf
|
10

You might be able to tap into the Response during OnResultExecuting and replace the Filter property with something that stores the resultant HTML in a MemoryStream. Then you could clear the Response during OnResultExecuted and replace it with the results of your PDF conversion. I'm not sure that this would be better than just getting the HTML from the URL, though.

 public FileStreamResult Print(int id)
 {
     var model = _CustomRepository.Get(id);
     this.ConvertToPDF = true;
     return View( "HtmlView" );
 }

 public override OnResultExecuting( ResultExecutingContext context )
 {
      if (this.ConvertToPDF)
      {
          this.PDFStream = new MemoryStream();
          context.HttpContext.Response.Filter = new PDFStreamFilter( this.PDFStream );
      }
 }

 public override OnResultExecuted( ResultExecutedContext context )
 {
      if (this.ConvertToPDF)
      {
          context.HttpContext.Response.Clear();
          this.PDFStream.Seek( 0, SeekOrigin.Begin );
          Stream byteStream = _PrintService.PrintToPDF( this.PDFStream );
          StreamReader reader = new StreamReader( byteStream );
          context.HttpContext.Response.AddHeader( "content-disposition",
                 "attachment; filename=report.pdf" );
          context.HttpContext.Response.AddHeader( "content-type",
                 "application/pdf" );
          context.HttpContext.Response.Write( reader.ReadToEnd() );
      }
}

The PDFStreamFilter would need to override the "Write" method(s) and send the data to the memory stream instead.

1 Comment

I got a solution worked out that resulted in less code, but the answer you provided was a potential solution. Good idea to intercept the Result execution... I'll post my solution soon.
1

This sounds like a similar problem I had where I wanted to use Views as email templates. The best answer I found for getting the string representation of a View was here: Render a view as a string

1 Comment

I saw that post. I ended up using a similar solution, based on a comment on the brightmix post. I'll post the solution soon.
0

The best package I've found is the RazorPDF, available as a package at NuGet.org, based on iTextSharp. Works on Azure Web Sites:

https://nuget.org/packages/RazorPDF

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.