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 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.

So, without further ado, let’s dive right into the fun part.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

VIDEO: How to Easily Create a PDF Document in ASP.NET Core Web API video.


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, by creating a brand new .NET Core 3.0 Web API project named PDF_Generator:

Creating project for .NET Core Web API PDF Document Creation

After the project creation, we are going to modify the launchSettings.json file to disable our browser to start automatically:

{
  "profiles": {
    "PDF_Generator": {
      "commandName": "Project",
      "launchBrowser": false,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "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:

PM> Install-Package DinkToPdf

Or search for DinkToPdf inside the Nuget Package window:

Nuget package .NET Core PDF Creation

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:

Native library files

Finally, we need to register this library with our IoC container in the StartUp class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));

    services.AddControllers();
}

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:

namespace PDF_Generator.Models
{
    public class Employee
    {
        public string Name { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
        public string Gender { 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:

Utility Folder Structure

Now, let’s modify the DataStorage.cs file:

using PDF_Generator.Models;
using System.Collections.Generic;

namespace PDF_Generator.Utility
{
    public static class DataStorage
    {
        public static List<Employee> GetAllEmployees() =>
            new List<Employee>
            {
                new Employee { Name="Mike", LastName="Turner", Age=35, Gender="Male"},
                new Employee { Name="Sonja", LastName="Markus", Age=22, Gender="Female"},
                new Employee { Name="Luck", LastName="Martins", Age=40, Gender="Male"},
                new Employee { Name="Sofia", LastName="Packner", Age=30, Gender="Female"},
                new Employee { Name="John", LastName="Doe", Age=45, Gender="Male"}
            };
    }
}

In this code, we just return a list of employees that 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:

using System.Text;

namespace PDF_Generator.Utility
{
    public static class TemplateGenerator
    {
        public static string GetHTMLString()
        {
            var employees = DataStorage.GetAllEmployess();

            var sb = new StringBuilder();
            sb.Append(@"
                        <html>
                            <head>
                            </head>
                            <body>
                                <div class='header'><h1>This is the generated PDF report!!!</h1></div>
                                <table align='center'>
                                    <tr>
                                        <th>Name</th>
                                        <th>LastName</th>
                                        <th>Age</th>
                                        <th>Gender</th>
                                    </tr>");

            foreach (var emp in employees)
            {
                sb.AppendFormat(@"<tr>
                                    <td>{0}</td>
                                    <td>{1}</td>
                                    <td>{2}</td>
                                    <td>{3}</td>
                                  </tr>", emp.Name, emp.LastName, emp.Age, emp.Gender);
            }

            sb.Append(@"
                                </table>
                            </body>
                        </html>");

            return sb.ToString();
        }
    }
}

So, 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:

.header {
    text-align: center;
    color: green;
    padding-bottom: 35px;
}

table {
    width: 80%;
    border-collapse: collapse;
}

td, th {
    border: 1px solid gray;
    padding: 15px;
    font-size: 22px;
    text-align: center;
}

table th {
    background-color: green;
    color: white;
}

This CSS file is going to be loaded later in the Controller class.

That is it, we have our HTML template to use for the PDF creation. Now, 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:

namespace PDF_Generator.Controllers
{
    [Route("api/pdfcreator")]
    [ApiController]
    public class PdfCreatorController : ControllerBase
    {
    }
}

Now, let’s modify the PdfCreatorController class to support the creation and saving a PDF document to a local drive:

using DinkToPdf;
using DinkToPdf.Contracts;
using Microsoft.AspNetCore.Mvc;
using PDF_Generator.Utility;
using System.IO;

namespace PDF_Generator.Controllers
{
    [Route("api/pdfcreator")]
    [ApiController]
    public class PdfCreatorController : ControllerBase
    {
        private IConverter _converter;

        public PdfCreatorController(IConverter converter)
        {
            _converter = converter;
        }

        [HttpGet]
        public IActionResult CreatePDF()
        {
            var globalSettings = new GlobalSettings
            {
                ColorMode = ColorMode.Color,
                Orientation = Orientation.Portrait,
                PaperSize = PaperKind.A4,
                Margins = new MarginSettings { Top = 10 },
                DocumentTitle = "PDF Report",
                Out = @"D:\PDFCreator\Employee_Report.pdf"
            };

            var objectSettings = new ObjectSettings
            {
                PagesCount = true,
                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" }
            };

            var pdf = new HtmlToPdfDocument()
            {
                GlobalSettings = globalSettings,
                Objects = { objectSettings }
            };

            _converter.Convert(pdf);

            return Ok("Successfully created PDF document.");
        }
    }
}

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 HtmlToPdfDcoumentproperty. 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 files 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 an 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:

Request for PDF creation

As a result, we have our document created in the PDFCreator folder:

Created document .NET Core PDF Creation

And let’s inspect the content of the document:

PDF Content .NET Core PDF Creation

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:

_converter.Convert(pdf);

We are going to use this type:

var file = _converter.Convert(pdf);

Why is that?

Well as we said if we use the Out property then 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 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:

[HttpGet]
public IActionResult CreatePDF()
{
    var globalSettings = new GlobalSettings
    {
        ColorMode = ColorMode.Color,
        Orientation = Orientation.Portrait,
        PaperSize = PaperKind.A4,
        Margins = new MarginSettings { Top = 10 },
        DocumentTitle = "PDF Report"
    };

    var objectSettings = new ObjectSettings
    {
        PagesCount = true,
        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" }
     };

     var pdf = new HtmlToPdfDocument()
     {
        GlobalSettings = globalSettings,
        Objects = { objectSettings }
     };

     var file = _converter.Convert(pdf);
     return File(file, "application/pdf");
}

And this is the result:

PDF browser content .NET Core PDF Creation

Using Existing HTML Page to Generate PDF Content

We don’t have to use our custom HTML template to generate 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:

HtmlContent = TemplateGenerator.GetHTMLString()

let’s add this code:

Page = "https://code-maze.com/"

And let’s inspect the result:

PDF browser HTML page .NET Core PDF Creation

Enabling Download Mode

If we want to enable the download feature for the PDF document we need to modify our return statement in our action method. All we have to do is simply add the name of the file with its extension to the return statement:

return File(file, "application/pdf", "EmployeeReport.pdf");

As a result, we are going to have our file downloaded:

PDF downloaded file

And there it is.

Everything is working as it supposed to.

Update Project For Deployment

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:

internal class CustomAssemblyLoadContext : AssemblyLoadContext
{
    public IntPtr LoadUnmanagedLibrary(string absolutePath)
    {
        return LoadUnmanagedDll(absolutePath);
    }
    protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
    {
        return LoadUnmanagedDllFromPath(unmanagedDllName);
    }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        throw new NotImplementedException();
    }
}

After that, let’s modify the ConfigureServices method in the StartUp class:

public void ConfigureServices(IServiceCollection services)
{
    var context = new CustomAssemblyLoadContext(); 
    context.LoadUnmanagedLibrary(Path.Combine(Directory.GetCurrentDirectory(), "libwkhtmltox.dll"));

    services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));

    services.AddControllers();
}

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 these 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:

.NET Core Application IIS Deployment

.NET Core Application Linux Deployment

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 PDFs in different ways to show many different features of this library.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!