0% found this document useful (0 votes)
12 views8 pages

Using ASP - NET MVC and Razor To Generate PDF Files

The document explains how to generate PDF files in an ASP.NET MVC application using the Razor view engine, allowing for the use of view models and HTML helpers. It introduces the PdfResult class, which handles the rendering of views and the generation of PDF files using libraries like Aspose.Pdf. The article provides a step-by-step guide on implementing this functionality, including controller methods and sample views for generating PDFs.

Uploaded by

johonson
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
0% found this document useful (0 votes)
12 views8 pages

Using ASP - NET MVC and Razor To Generate PDF Files

The document explains how to generate PDF files in an ASP.NET MVC application using the Razor view engine, allowing for the use of view models and HTML helpers. It introduces the PdfResult class, which handles the rendering of views and the generation of PDF files using libraries like Aspose.Pdf. The article provides a step-by-step guide on implementing this functionality, including controller methods and sample views for generating PDFs.

Uploaded by

johonson
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
You are on page 1/ 8
Using ASP.NET MVC and Razor To Generate PDF Files From reports to scan sheets, the need to generate PDF files has been present in every line-of-business application I've ever worked on. In the past, I've used a variety of tools to achieve this such as SQL ‘Server Reporting Services or Telerik Reporting. While these kinds of tools work well enough for generating reports straight from the database, it's been surprising how few resources exist to aid in generating PDF files from arbitrary data. It turns out there is a pretty simple way to enable the generation of PDF files in an ASP.NET MVC application using the same Razor view engine that you're probably already using. This allows you to make use of view models, HTML helpers, etc. in your PDF logic. The code here is based primarily on the code in MVC itself, specifically the actiongesult and ViewResuit classes. It's also based on general concepts used in two open source projects, MycRazorToPdf and RazorPDF, In a nutshell, the commands necessary to create a given PDF file (typically as XML) are placed in a standard .cshtml view, rendered and interpreted as any Razor view would be, passed to a PDF generation library (Iuse the excellent Aspose.Pdf, but this approach can also work with {TextSharp or any other PDF generation library that takes markup such as XML), and then returned to the client as PDF content. This is what the process looks like in a nutshell: Razor View (.eshtm|), PdfResult Controller abe Request Razor View |» enaine f+ Generation Action |-——+ Library esponte PDF File The PdfResult Class ‘The Pd¢Result class is the heart of this approach. It contains all of the logic necessary to locate the view, set up the view context, render the view, and generate the PDF file. Though it does all the heavy lifting, there actually isn’t that much code involved: public class PdfResult : PartialViewResult K // Setting FileDownloadName downloads the POF instead of viewing it public string FileDownloadName { get; set; ) public override void ExecuteResult (ControllerContext context) { if (context == null) { ‘throw new ArgumentNullexception("context"); } J/ Set the model and date context.Controller.Viewbata.Model = Model; VienDate = context.controller.Viewoata; Tenpbata = context.Controller. Tenpbata; 11 Get the view name if (string. TsNullorempty (ViewName) ) { ViewNane context .RouteData.GetRequiredString(“action") ; // Get the view ViewEngineResult viewEngineResult = null; Lf (View == null) { viewEngineResult = FindView(context); View = viewengineResult.Views U1 Render the view StringBuilder sb = new StringBuilder(); using (Textwniter te = new Stringhriter(sb)) { ViewContext viewontext = new ViewContext (context, View, ViewData, Tempbata, tr); View.Render(viewContext, tr); } if (viewEngineResult I= null) { vilewEngineResult. ViewEngine.ReleaseView(context, View); } // Create a POF from the rendered view content Aspose.PdF.Generator.PdF pdf = new Aspose.Pdf.Generator.PdF(); using (MenoryStrean ms = new MenoryStream(Encoding.UTF8.GetBytes(sb.ToString()))) ‘ poF.BindXML (ms, null); // Save the PDF to the response stream Using(MenoryStream ms = new MenoryStrean()) { paF.Save(ms)5 FileContentResult result = new FileContentResult(ms.ToArray(), “application/pdt") { FileDownloadName = FileDownloadNane h result. ExecuteResult(context) 5 » Let's go through this from top to bottom. First off, i's derived from partialviewResult. Why PartialviewResult and not ViewResult or Actionkesult? Viewesult has a more robust implementation of Eindview() that looks in several places for the view and includes the convention-based view search logic we're used to using with normal views. It also includes built-in support for managing the Viewata for a view. So why use PartialviewResult? The reason is that PartialViewResult never attempts to render layouts as part of the view. This is important if you're using a global layout via a_ViewStart.cshtm file or something similar. Since our PDF file obviously shouldn't have the same layout logic as one of our actual web pages, we need to make sure that doesn't get included in the rendered PDF syntax. The easiest way to do that is to derive our Pd¢kesuit class from PantialViewResult, which ensures a layout is not used by returning a slightly different Viewengineresult (and thus 1vies) in it’s own Eindview(), implementation Looking at the body, the only method is an override of ExecuteResult().. This method is called when the PdfResult (or any ActionResult) is processed by MVC and is intended to manipulate the result sent to the client (by adding content, setting headers, etc.) The first thing we do is check to make sure we have a context. This block, and most of the rest of the first part of the method, is copied straight from the implementation in MVC. Next we set the model (if there is one) and the other data that will be passed to the view. This is necessary to make sure that when we interpret our view code we have access to all of the same kinds of data we would have if this were just a normal web view. Then we get the name of the view from the action name if a view name wasnt already provided. We set this in the ViewName member which Findview() uses to locate the view. This is where things get a little bit interesting. Next we call Eindview(). which locates the actual view cshtm! file using MVC conventions and instantiates an 1view for us that can be used for rendering the view. We then create a ViewContext to hold all of the data our view might need and call the Render(), method of the Iview we were previously provided. This triggers the Razor view engine and is where the view magically gets transformed into content we can pass to our PDF generation library. Once we have the content to pass to the PDF generator library, we create the PDF file. The code above is written for Aspose.Paf, but could be adapted to work with iTextSharp like this (from MvcRazorToPdf // Create a POF from the rendered view content var workStrean = new MemoryStream(); var document = new Document ()5 Pdfwriter writer = PdfWriter.GetInstance(document, workStream) ; weiter.CloseStrean = false; document .open(); Stream stream = new MenoryStrean( Encoding .UTFS.Getaytes (sb. ToString()))5 XLWorkerHelper.GetInstance().Parsexitml(writer, document, strean, null); docunent.Close() 5 // Save the POF to the response stream FilecontentResult result = new FileContentResult(workStream.ToArray(), "application/pd#") K FileDownloadNare = FileDownloacNane » ntResult. If null is One final note about the Fi1ebownloadvane property and it's use in the Ei1ec supplied for FiledownioadNane, the PDF file will be delivered to the browser and rendered inline. However, if a value is supplied for FiledonnloadNane, the browser will initiate a file download of a PDF file with that name. This lets you control the way in which the client views and downloads the PDF file. The Controller Now that we have the Pafresuit class complete, how do we use it to actually generate a PDF file? This step is optional, but I prefer to add a method to my Controller base class to support alternate view results from an action, The base Controller in MVC already does this - you typically write return View(); MOL return new Viewesult() { ... }; Ifyou don't already have a custom base controller in your MVC application, I suggest adding one. Even if it's just to hold the next bit of code, it's worthwhile. And Ive found over time that it's nice having a base Controller class into which I can add all sorts of other helper methods and additional logic. To that end, the following are overloads for a Paf() method that can be used as the return value for an action: protected ActionResult PdF() « return Pdf(null, null, null); > protected ActionResult Pdf(string fileDownloadNane) « return Pdf(FileDownloadName, null, null); y protected ActionResult Pdf(string fileDownloadNane, string ViewName) K return Pdf(fileDownloadName, ViewName, null); y protected ActionResult PdF(object model) K return Pdf(null, null, model); > protected ActionResult PdF(string fileDownloadNane, object model) K return Pdf(#ileDownloadNane, null, model); > protected ActionResult Pdf(string #ileDownloadNane, string viewWane, object model) Kk 11 wased on View() code in Controller base class from MVC sf (model != null) { VienData.Model = model; y PafResult pdf = new PdfResult() t FileDownloadNane = fileDownloadNane, ViewName = viewNane, Viewbata = Viewbata, Tempbata = Tenpbata, ViewEngineCollection = Viewénginecollection h return pdf; 2 The Action ‘The result of all this is that you can write you PDF generating actions in a very similar way to how you write your normal web actions: public virtual ActionResult PdfTest() K return Pdf(new int{] { 1, 2, 3 }) The code about will cause a PdfResuit class to be instantiated which will attempt to find a view named “pdfTest.cshtml” in the conventional location. It will be given an int{] array as it’s model and then rendered by the Razor view engine. The View The final step is the view, where the actual PDF content is specified. Recall that I said I'm using Aspose.Pdf, so the XML in my view corresponds to the XML. that Aspose.Pdf expects. If'you're using iLextSharp or any other PDF generation library then the XML (or other type of) content contained in your view may look drastically different. But for the sake of example, here's what a sample view might look like using the Aspose.Pdf XML format: lénodel Tenunerablecint> ‘
@foreach (int ¢ in Model) ‘ @: }
‘The Razor syntax checker in Visual Studio will probably complain that all these XML elements are not valid HTMLS (or whatever other validation type you have configured), but that's fine - the actual view engine will deal with them without issuc, One small complication youll see above is that the Aspose.Paf XML specification uses an element called Text. Unfortunately, this element also has a very special meaning in Razor syntax. We need to escape it when used directly inside a code block by using @ Conclusion That about covers it. This was a pretty long article, mainly because I wanted to explain how everything fit together. Hopefully you'll see that when you get right down to it the approach is actually pretty simple. Now go forth and populate your web apps with lots of useful PDF documents ALSO ON DAVEAGLICK ‘Thepersonal blog ofDave The personal blogofDave___Theppersonalblogof Dave The personal Bog of Dave The personal bo, hick lice ii lice lick 30 Comments: Login @ scin the discussion = SortbyBet= Oa james donophve Tanks, ths gave me the foundation I needed to build my ov solution use this lass with EvoPDF" PafConver Copyright © 2022 by Dave Glick All ams ane jelies preserved. The opinions expressed herein are my own and do not represent those of my ‘employer or any other third-party views in any way. This work is licensed under a Creative Commons Attribution 40 international License, RSS Feed R.Atom Fee ‘©-This Site on GitHiub Generated by Statiq Life saver... Thanks aot, Twas able ree evopedcom/) ust replaced the same

You might also like