Generating PDF Documents in .NET
Introduction
If I had a dollar for every time I was asked how to generate PDF documents in a .NET web application, I’d be rich. This question seems to come up every few months internally at Marathon Consulting and I kept saying we need to write a blog post to share the answer. Finally, here it is!
Approaches
This is not intended to be a comprehensive list of every approach you can take, but it does cover approaches we have used internally that have been successful. Each has its advantages and disadvantages, so let’s take a quick look at the overall list before we dive into each one in detail.
Approach | Cost |
---|---|
SelectPdf | Varies |
PDFSharp | Free (Open Source) |
iTextSharp | Open source but requires a license for commercial |
IRONPDF | Starts at $499 |
Aspose Total for .NET | $3,999 |
SQL Server Reporting Services (SSRS) | Licensing costs vary but are expensive |
SelectPdf
SelectPdf offers a variety of ways to create PDF documents, including a free option: the HtmlToPdf Converter for .NET, the HTML to PDF API, and the PDF Library for .NET. Each option has its own use case and for two of them, there are license costs. I could write a blog post just on SelectPdf, but since this is an overview, let’s concentrate on a free and easy option – the HtmlToPdf Converter for .NET.
A subset of the full Select.Pdf Library for .NET, the HtmlToPdf Converter for .NET comes in a community edition that is free for personal and commercial use. The main thing to note is the limitation that it will only generate up to a 5 page PDF document. However, there are some great use cases for this (think single page forms) that make this a viable option. Ease of use and flexibility are the strengths of this option as it can convert a URL, HTML file, or HTML string to a PDF document.
Start off by instantiating the HtmlToPdf library.
var pdfConverter = new HtmlToPdf();
Then create a new PDF document.
var doc = pdfConverter.ConvertUrl(“This is my document text.”);
Then save as a new PDF document.
doc.Save(HttpContext.Current.Response, true, "App_Data\\MyDocument.pdf");
PDFSharp
PDFSharp is an open source .NET library that has been around a long time. It provides an incredible amount of power and flexibility for manipulating PDF documents using .NET, including the ability to use drawing routines from GDI+. The library is published under the MIT License and is free to use in commercial products. Note that one big limitation of PDFSharp is that only basic text layout is supported and page breaks are not created automatically. This can be a dealbreaker if you are using this approach to generate reports. The same foundation that maintains PDFsharp also maintains MigraDoc, which lets you create rich documents, so that could be an alternative approach. Another big dealbreaker is that PDFSharp does not support .NET Core although there is a partial port called PdfSharpCore. I can’t recommend PDFSharp unless you need to create PDF documents with a lot of images or need really low-level manipulation of the PDF document.
To get started, create a new PDF document.
var pdfDocument = new PdfDocument();
Then you can add a title to the page.
pdfDocument.Info.Title = "My Page Title";
Add a new page to the PDF document.
var page = pdfDocument.AddPage();
Add some text to the page.
var gfx = XGraphics.FromPdfPage(page);
gfx.DrawString("This is my document text.", font, XBrushes.Black, new XRect(0, 0, page.Width, page.Height), XStringFormats.Center);
Finally, save the document.
pdfDocument.Save("App_Data\\MyPdfDoc.pdf");
iTextSharp
iTextSharp is a Java-based toolkit for PDF generation and manipulation. Note that one big drawback that most developers miss is that while iTextSharp is open source under the AGLP license agreement, it is not free to use in commercial applications and you must negotiate license costs. That, combined with the fact that it is Java based, makes this an approach I would stay away from as a .NET developer.
IRONPDF
IRONPDF is a library that can be used to generate, format, and manipulate PDFs in .NET. It is available with a free 30-day trial; then you’ll have to purchase a license. The library is available as a DLL or a NuGet package and was designed to work easily in .NET. It provides the ability to render an HTML string, an HTML file, a URL, an MVC View, or a .NET Web Form to PDF. You can merge and split PDF files, encrypt them, extract images, etc. I was not aware of this library when I was researching PDF generation options for this blog post, but this library is now definitely on my radar.
To create a PDF document from an HTML file, you first instantiate the IronPdf library.
var renderer = new IronPdf.HtmlToPdf();
Then, open the HTML page.
var pdfDocument = Renderer.RenderHTMLFileAsPdf("MyPage.html");
Finally save the PDF document.
pdfDocument.SaveAs("App_Data\\MyPage.pdf");
Aspose Total for .NET
Aspose Total is a complete package for creating and manipulating file formats in .NET, including Word, Excel, CSV, PDF, etc. While it is a bit pricey, I can’t say enough about how easy to use and full featured this package is. We are going to leverage it to create a PDF document by using Aspose.Words for .NET and Aspose.PDF for .NET. The use case that comes to mind where Aspose was a big win for us was a client that had contracts they maintained in Word format. They wanted to continue to maintain them in Word as they changed yearly, but have the application we were building fill in data in the Word document from the application database and present that as a PDF document to the user that could be printed and signed or sent to DocuSign.
The first thing we’ll need to do is set a reference to the license file for Aspose.Words.
var lic = new Aspose.Words.License();
lic.SetLicense($"App_Data\\Aspose.Words.NET.lic");
Now we can open a Word document.
var appData = Path.Combine(_hostingEnvironment.ContentRootPath, "App_Data");
var contractDoc = new Aspose.Words.Document($"{appData}\\Contract.docx");
With the Word document open, we can fill in database data where needed in the contract document. We can leverage the Replace method to search for an occurrence in the document of the string we want to replace. In this case, we used the percentage character around the variable names we placed in the Word document, so every occurrence of the string "%<Year>%" will get replaced with the string “2021” in the document.
contractDoc.Range.Replace("%<Year>%", “2021”, new Aspose.Words.Replacing.FindReplaceOptions(FindReplaceDirection.Forward));
With the Word document contents updated, we will save it in PDF format.
contractDoc.Save(“App_Data\\MyContract.pdf”, Aspose.Words.SaveFormat.Pdf);
At this point, the PDF document could be ready for the end user, but we needed to do a few more things to the document that could not be achieved in Word, including adding a signature section for a variable number of customers. Creating that section is beyond the scope of this article, but I will show a few other ways we manipulated this document, including setting the page size to legal and adding a footer.
The first thing we’ll need to do is set a reference to the license file for Aspose.PDF.
var licPDF = new Aspose.Pdf.License();
licPDF.SetLicense($"App_Data\\Aspose.Pdf.lic");
Then we can open the PDF document.
var contractPdf = new Aspose.Pdf.Document(“App_Data\\MyContract.pdf”);
Now we can set the page size to legal.
foreach (var p in contractPdf.Pages)
{
p.PageInfo.Width = PageSize.PageLegal.Width;
p.PageInfo.Height = PageSize.PageLegal.Height;
}
Then we can add a text stamp to the document.
foreach (var page in contractPdf.Pages)
{
pg.Value = $"Page {page.Number} of {doc.Pages.Count}";
page.AddStamp(pg);
page.AddStamp(con);
}
Finally, save the changes to the PDF document.
contractPdf.Save(“App_Data\\MyContract.pdf”);
SQL Server Reporting Services (SSRS)
Using SSRS to generate PDFs was an option recommended by a colleague that left me scratching my head. It seemed like overkill and a nonoptimal solution, but once we talked a little about it, I realized what a great option this one is, the caveat here being that your client is already using SQL Server and SSRS and the solution is on premise. I would not recommend this approach for a cloud-based solution or if your client has not already made the investment of standing up a SQL Server.
We won’t go into the details of creating an SSRS report since that is out of scope for this article, but just keep in mind that with SSRS, you have a large amount of flexibility to create everything from simple column-based reports to complex reports with subreports and grouping. Let’s dive into how we can call a SSRS report and return a PDF document.
The first thing I would recommend is grabbing the RestSharp NuGet package. This package brings a lot of simplicity and features to the table as opposed to HttpClient Class in .NET. We can instantiate a new RestClient using the base URL of our SSRS server and a new RestRequest with the full path to the report we created (MyReport).
var client = new RestClient(“http://www.myssrsserver.com/”);
var request = new RestRequest(“ReportServer?/MyReport”);
Now we can use the AddParameter method of the RestRequest object to pass parameters to the report. We are passing in year as a single report parameter for demonstration purposes, but you can pass in as many report parameters as you have.
request.AddParameter("Year", 2021, ParameterType.QueryStringWithoutEncode);
Now we pass in a couple additional parameters that make the PDF generation happen. The “rs:Command” parameter with a “Render” value forces SSRS to render the report in memory as opposed to on the screen. The “rs:Format” parameter with the “PDF” value tells SSRS to generate the report in PDF form.
request.AddParameter("rs:Command", "Render", ParameterType.QueryStringWithoutEncode);
request.AddParameter("rs:Format", "PDF", ParameterType.QueryStringWithoutEncode);
Now comes one of the main reasons we use RestSharp for this approach: authentication. It is way easier to handle authentication with RestSharp as opposed to the HttpClient in .NET, so we use the NtlmAuthenticator object to pass in a username and password to SSRS in order to execute the report.
client.Authenticator = new NtlmAuthenticator(“SSRS_UserName”,”SSRS_Password”);
With everything set up correctly, we are ready to execute our report and return the PDF file to the browser.
var response = await client.ExecuteGetAsync(request);
return File(response.RawBytes, "application/pdf", $"MyReport_{DateTime.Now:yyyyMMddHHmmss}.pdf");
Conclusion
As you can see, there is no one best answer to the question of how to generate PDF documents in .NET. It is really an “it depends” answer. If your company or client already has SQL Server and you are familiar with SSRS, I’d recommend taking advantage of it. If not, then it’s hard to beat the flexibility you get using Aspose Total for .NET.