How to render an ASP.NET MVC View in PDF format
Solution 1
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.
Solution 2
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)
Solution 3
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
Related videos on Youtube
Comments
-
nkirkes almost 2 years
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!
-
jim tollan about 13 yearsmannish - were you ever able to post your solution to this anywhere?? it would be increadibly useful. tia
-
-
nkirkes over 14 yearsI saw that post. I ended up using a similar solution, based on a comment on the brightmix post. I'll post the solution soon.
-
nkirkes over 14 yearsI 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.
-
Hector Minaya about 12 yearsthis is by far the easiest solution I have come across for asp.net mvc, thanks a lot...
-
Mark Carpenter over 11 yearsThis 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!
-
detay about 11 yearsRotativa seems to fail with MVC4. When I return an ActionAsPdf I see a string displayed on the screen instead of a PDF.
-
Giorgio Bozio almost 11 yearsWorks in Azure Web Roles but doesn't work on Azure Web Sites because of limitations to the trust level.
-
Xavier John about 10 yearsis there a solution for azure website?
-
Kurt Wagner about 10 yearsAny updates to the website issue? Would really like to use this library for an Azure website if possible~ :X
-
Giorgio Bozio about 10 yearsNo, sorry, the only solution is to use a Web Role instead of Website. This is due to limitations of Azure Websites.
-
abenci almost 10 yearsWhat about saving these PDF docs on disk before displaying? For storing an invoice copy would be great...
-
Giorgio Bozio almost 10 years@Alberto you can use the BuildPdf method.
-
HenrikP over 9 years@GiorgioBozio This works great even locally and on my webhost. But I've heard that wkhtmltopdf uses a lot of resources, but those comments are kinda old by now. How stable is it nowadays? or can you expect the server to run out of process power when running this? I'm not really run these functions a lot though.
-
Giorgio Bozio over 9 years@HenrikP wkhtmltopdf should be pretty fast but didn't do any load testing. Never heard of performance problems though. I has other problems that make me think about providing different "pdf engines" other that wkhtmltopdf. But actually I don't have time to work on it. If you have it will be great if you could collaborate...
-
Nic almost 9 yearsOh man , you are the hero, Great solutions, very simple to use.Awesome.Thanks a lot.
-
Slinky over 8 yearsUnfortunately, Rotativa does not work with MVC 4 for some reason: stackoverflow.com/questions/32014929/… @GiorgioBozio
-
JoshYates1980 over 8 yearsThis...is...amazing. Just one line of code! return new ActionAsPdf("BillingLetter", null) { FileName = "Bill.pdf" };
-
Giorgio Bozio about 8 yearsI'm developing a SaaS solution that will also solve server install and execution issues, like running on Azure websites. You can register at rotativahq.com
-
MSTdev almost 8 years@Giorgio Bozio not working for me it is showing only scroll bar and backgrounds only
-
Guruprasad J Rao almost 8 yearsHow to pass
model
withActionAsPdf
? -
Giorgio Bozio almost 8 years@GuruprasadRao you don't, you ca do that when using ViewAsPdf. With ActionAsPdf you can pass route values.
-
Guruprasad J Rao almost 8 years@GiorgioBozio.. Yea, am using this right now.. :) Thanks so much for the awesome library.. :) You rock.. :)
-
SAR over 7 years@GuruprasadRao , it's resulting wiht login page on pdf
-
Saurabh almost 6 years@GiorgioBozio , in asp.net mvc5 , able to include in from nuget but its not available in controller , 'using Rotavita' statement gives error that cant find the reference
-
Giorgio Bozio almost 6 years@Saurabh what version of .Net are you using? if it's an old one you should try an older version of Rotativa.
-
Saurabh almost 6 years@GiorgioBozio , i was trying on 4.5 , i also tried changing the target framework to 4.6.1 , it does create pdf but its blank and funny thing is if i check bookmark section than it show bokkmark there but pdf is white blank. Works well with .net core 2.0 . Which version of Rotattiva you suggesting for .net 4.5
-
Moiz Tankiwala almost 4 yearsI have flexbox based CSS and Rotativa fails to render that properly, so looking for a Rotativa alternative.
-
Belarmino Vicenzo over 3 years@GiorgioBozio I don't think it works with [Authorize] I had to create an action only to print and had the [Allow Anonymous] to be able to print. Now it works, if u say it works with [Authorize], I would like a hand, bro
-
Light about 2 years@GiorgioBozio - with [Authorize] it does not work, if we use allow anonymous i'm able to print. Is this expected ?