Let’s imagine that we have a .NET Core Web API project in which we need to generate a PDF report. Even though it shouldn’t suppose to be too hard to do something like that, we could end up in losing too much time if we don’t know how to do it properly.
In this article, we are going to show how to use the DinkToPDF
library to easily generate PDF documents while working on the .NET Core Web API project.
- Murach's ASP. 6 Web Programming with C# 2015 Computers & Technology; Programming. And how ASP.NET MVC programming differs from Web Forms programming To make it easier for you to master ASP.NET, you get complete web applications¦¦including the web forms, the aspx code, and the C# code¦¦that show you how each feature works in.
- Visual Studio 2017 updates for this book are now available. Follow the Download Source Code link for this book on the Apress website. Now in its 6th edition, the best selling book on MVC is now updated for ASP.NET Core MVC.
- ASP.NET Database Programming Weekend Crash Course. Open the book Friday evening and on Sunday afternoon, after completing 30 fast, focused sessions, you’ll be able to jump right in and start to create dynamic, data-driven Web applications. It’s as simple as that. The Curriculum Get Up to Speed on ASP.NET Database Programming — in a Weekend!
So, without further ado, let’s dive right into the fun part.
You can download the PDF of this wonderful tutorial by paying a nominal price of $9.99. Your contribution will go a long way in helping us serve more readers. ASP.NET is a web development platform, which provides a programming model, a comprehensive software infrastructure and various services required to build up.
You can download the source code for this article at Creating PDF Document Source Code.
In this post, we are going to cover:
Basic Project Preparations
Let’s start from the very beginning, by creating a new .NET Core Web API project named PDF_Generator
:
After the project creation, let’s modify the launchSettings.json
file to disable our browser to start automatically and to change the applicationUrl
property to [::]:5000
:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 | '$schema':'http://json.schemastore.org/launchsettings.json', 'windowsAuthentication':false, 'iisExpress':{ 'sslPort':44320 }, 'IIS Express':{ 'launchBrowser':false, 'ASPNETCORE_ENVIRONMENT':'Development' }, 'commandName':'Project', 'applicationUrl':'http://[::]:5000', 'ASPNETCORE_ENVIRONMENT':'Development' } } |
DinkToPdf Library Configuration
DinkToPdf
is a cross-platform oriented library which is the wrapper for the Webkit HTML to PDF library. It uses the WebKit engine to convert HTML to PDF.
It will allow us to create a PDF document from our HTML string that we generate in the .NET Core project, or to create a PDF document from an existing HTML page. Furthermore, we can download the created PDF document or save it on a certain location or return a new HTML page with the PDF content.
We are going to cover all these features in this article.
So, let’s install the DinkToPdf
library first:
Or search for DinkToPdf
inside the Nuget Package window:
After the installation completes, we need to import native library files to our root project. We can find those files in our source project in the NativeLibrary folder. Inside we will find two folders 32bit
and 64bit
, so we need to choose the appropriate library for our OS. We are going to choose the files from the 64bit folder:
Finally, we need to register this library with our IoC container in the StartUp
class:
2 4 6 | publicvoidConfigureServices(IServiceCollection services) services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddSingleton(typeof(IConverter),newSynchronizedConverter(newPdfTools())); |
To learn in more detail about service registration in .NET Core and how to keep Startup methods cleaner, you can read the .NET Core Service Configuration.
Excellent.
We have everything in place and we are ready to proceed.
Preparing Data for the PDF Document
In a real-world project, we can collect data from the database or receive it from other API. But for the sake of simplicity, we are going to collect data for our PDF document from the local storage. Then we are going to create an HTML template and store it in the PDF document.
So let’s first create a new folder Models
and inside it the Employee.cs
file:
2 4 6 8 10 | { { publicstringLastName{get;set;} publicstringGender{get;set;} } |
To continue, we are going to create a new folder Utility
and two class files inside it DataStoage.cs
and TemplateGenerator.cs
. A complete structure should look like this:
Now, let’s modify the DataStorage.cs
file:
2 4 6 8 10 12 14 16 18 20 | usingSystem.Collections.Generic; namespacePDF_Generator.Utility publicstaticclassDataStorage publicstaticList<Employee>GetAllEmployess() returnnewList<Employee> newEmployee{Name='Mike',LastName='Turner',Age=35,Gender='Male'}, newEmployee{Name='Sonja',LastName='Markus',Age=22,Gender='Female'}, newEmployee{Name='Luck',LastName='Martins',Age=40,Gender='Male'}, newEmployee{Name='Sofia',LastName='Packner',Age=30,Gender='Female'}, newEmployee{Name='John',LastName='Doe',Age=45,Gender='Male'} } } |
In the code above we just return a list of employees which will be displayed inside the HTML template.
HTML Template Generation
We want to generate an HTML template, so we need to modify the TemplateGenerator.cs
file:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 | { { { sb.Append(@' <head> <body> <div><h1>This is the generated PDF report!!!</h1></div> <tr> <th>LastName</th> <th>Gender</th> { <td>{0}</td> <td>{2}</td> </tr>',emp.Name,emp.LastName,emp.Age,emp.Gender); </table> </html>'); returnsb.ToString(); } |
In the code above we are fetching data from our static DataStorage
class and fill our template with it. The HTML template is nothing more than a pure HTML code.
But we want to style our table and h1 tag as well, so let’s create the new folder assets
and inside it the new styles.css
file and modify it:
2 4 6 8 10 12 14 16 18 20 22 | text-align:center; padding-bottom:35px; width:80%; } td, th { padding:15px; text-align:center; background-color:green; } |
This CSS file is going to be loaded later in the Controller class.
That is it, we have our HTML template to use in PDF creation and we can continue to the Controller logic.
Saving the PDF Document on the Local Storage
In the Controllers
folder, we are going to create a new empty API controller PdfCreatorController
:
Pdf Free Download Windows 10
2 4 6 8 | { [ApiController] { } |
Now, let’s modify the PdfCreatorController
class to support the creation and saving of a PDF document to a local drive:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 | usingDinkToPdf.Contracts; usingPDF_Generator.Utility; { [ApiController] { { } [HttpGet] { { Orientation=Orientation.Portrait, Margins=newMarginSettings{Top=10}, Out=@'D:PDFCreatorEmployee_Report.pdf' { HtmlContent=TemplateGenerator.GetHTMLString(), WebSettings={DefaultEncoding='utf-8',UserStyleSheet=Path.Combine(Directory.GetCurrentDirectory(),'assets','styles.css')}, HeaderSettings={FontName='Arial',FontSize=9,Right='Page [page] of [toPage]',Line=true}, FooterSettings={FontName='Arial',FontSize=9,Line=true,Center='Report Footer'} { Objects={objectSettings} } } |
Code Explanation
In the code above we first inject our registered Converter with the Dependency Injection inside our constructor by using IConverter
interface. Then we create two objects globalSettings
and objectSettings
and use them as a configuration in the HtmlToPdfDcoument
property. Finally, we convert our pdf configuration into a real PDF Document on our local machine.
Now let’s talk about the GlobalSettings
and ObjectSettings
classes.
About the GlobalSettings Class
The GlobalSettings
class consists of the overall configuration properties for the PDF document. We use just a couple of those properties to set up the color mode, orientation, paper size, document title etc… but if we go to the implementation of the GlobalSettings
class we can find more of those properties.
The Out property is very important if we want to save our file on a local machine. So we need to set it to the path where we want our document to. If we set the Out
property then we can use _converter.Convert(pdf);
to convert our document. We will see how this will change once we try to show our PDF document inside a browser.
One more important note is that all the folders from the Out
path should be previously created or the conversion won’t work. So in our example where we create a PDF document in the D:
drive in the PDFCreator
folder, we had to create the PDFCreator
folder prior to PDF document creation.
About the ObjectSettings Class
The ObjectSettings
class consists of the properties related to the contents of the PDF document. So, we can configure the visibility of the page counter, formatting of headers and footers, the body content of our document (HtmlContent
property) or the web settings for our document.
Of course, these are not all of the configuration properties but that’s all we need for this article.
The HtmlContent
property is the very important property of this class. It contains our generated HTML template and shows the main body of a PDF document.
WebSettings
is pretty important as well, especially if we have external CSS file for the styling as we do. In this property, we can configure the encoding of our document and provide the path to our CSS file. If we inspect this property, we are going to find out more settings that we can configure like the background of a PDF document or if we should load images or what the minimum font size is etc…
Inspecting Results
Let’s start our app, open our browser and send a simple request towards our PDF creator endpoint:
As a result, we have our document created in the PDFCreator folder:
And let’s inspect the content of the document:
That is awesome.
We can now continue on.
Showing a PDF Document in a Browser
If we want to show our document in a browser instead, we can configure that quite easily.
First, we need to remove the Out
property from the globalSettings
object.
Then instead of this type of conversion:
We are going to use this type:
Why is that?
Well as we said if we use the Out
property than the file is sent to stdout and saved to our local machine. But without the Out
property, our output will be stored in a buffer. While converting we need to create a byte array and to store it inside the file
variable.
Finally, we are using that file
variable and return it to the requester with a content type.
This is our CreatePDF()
method after modification:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 | publicIActionResult CreatePDF() varglobalSettings=newGlobalSettings ColorMode=ColorMode.Color, PaperSize=PaperKind.A4, DocumentTitle='PDF Report' { HtmlContent=TemplateGenerator.GetHTMLString(), WebSettings={DefaultEncoding='utf-8',UserStyleSheet=Path.Combine(Directory.GetCurrentDirectory(),'assets','styles.css')}, HeaderSettings={FontName='Arial',FontSize=9,Right='Page [page] of [toPage]',Line=true}, FooterSettings={FontName='Arial',FontSize=9,Line=true,Center='Report Footer'} { Objects={objectSettings} returnFile(file,'application/pdf'); |
And this is the result:
Using Existing HTML Page to Generate PDF Content
We don’t have to use our custom HTML template to generate a PDF content, we can use an existing HTML page. The effort is minimal. All we have to do is to remove the HtmlContent
property and add the Page
property of the ObjectSettings
class.
So instead of this code:
let’s add this code:
And let’s inspect the result:
Enabling Download Mode
If we want to enable download feature for the PDF document we need to modify our return
statement in our action method. All we have to do is to simply add the name of the file with its extension to the return
statement:
returnFile(file,'application/pdf','EmployeeReport.pdf'); |
As a result, we are going to have our file downloaded:
And there it is.
Everything is working as it supposed to.
Update Project For Deployment
Pdf Free Download
If we want to deploy this application, we have to make some changes. Let’s do that step by step.
First, in the Utility
folder we are going to add a new class CustomAssemblyLoadContext
and modify it:
2 4 6 8 10 12 14 16 | internalclassCustomAssemblyLoadContext:AssemblyLoadContext publicIntPtr LoadUnmanagedLibrary(stringabsolutePath) returnLoadUnmanagedDll(absolutePath); protectedoverrideIntPtr LoadUnmanagedDll(StringunmanagedDllName) returnLoadUnmanagedDllFromPath(unmanagedDllName); protectedoverrideAssembly Load(AssemblyName assemblyName) thrownewNotImplementedException(); } |
After that, let’s modify the ConfigureServices
method in the StartUp
class:
2 4 6 8 | publicvoidConfigureServices(IServiceCollection services) services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); varcontext=newCustomAssemblyLoadContext(); context.LoadUnmanagedLibrary(Path.Combine(Directory.GetCurrentDirectory(),'libwkhtmltox.dll')); services.AddSingleton(typeof(IConverter),newSynchronizedConverter(newPdfTools())); |
In here, we are creating an instance of the CustomAssemblyLoadContext
class and just call the LoadUnmanagedLibrary
method with the path of the libwkhtmltox.dll
file.
We need to do one more thing. When we publish our application, we need to have the libwkhtmltox.dll
file and the styles.css
file in the published directory. To ensure that, right click on the dll
file in Solution Explorer
and choose properties
. For the Build Action
we are going to choose Content
and for the Copy to Output Directory
, we are going to choose Copy always
. We need to repeat this steps for the CSS file as well:
Now, all we have to do is to publish our application by following one of these tutorials or both of them:
This is the result of the IIS deployment:
Conclusion
In this article, we have used the DinkToPdf library to create PDF documents while working with the .NET Core Web API project. We have created our PDF’s in different ways to show many different features of this library.
Create Pdf From Asp Net
If you have enjoyed reading this article and if you would like to receive the notifications about the freshly published .NET Core content we encourage you to subscribe to our blog.