Creating PDF files in ASP.NET Core

This article shows how to create PDF files in ASP.NET Core. I decided I wanted to use PDFSharp, because I like this library, but no NuGet packages exist for .NET Standard 2.0. YetaWF created a port for this, which was used 1:1 in this example, without changes. It would be great to see PDFSharp as a .NET Standard 2.0 NuGet package.

Code: https://github.com/damienbod/AspNetCorePdf

Part 2: Creating a PDF in ASP.NET Core using MigraDoc PDFSharp

Setting up the projects

To get the PDFSharp code working in ASP.NET Core, the best way is to clone the PDFsharp-.netcoreapp2.0 repository from YetaWF, and add this to your solution as a project. Then create an ASP.NET Core application, MVC or Razor Pages as preferred, and add a reference to the project.

Using the PDFSharp project

The example adds a HTTP Get request, creates a PdfData model which is used as an input for the PDF document. The PdfService was added as a scoped service to the IoC, and it creates the PDF document. This PDF document is then saved to the file system. The document is also returned in the HTTP response.

[HttpGet]
public FileStreamResult CreatePdf()
{
	var data = new PdfData
	{
		DocumentTitle = "This is my demo document Title",
		DocumentName = "myFirst",
		CreatedBy = "Damien",
		Description = "some data description which I have, and want to display in the PDF file..., This is another text, what is happening here, why is this text display...",
		DisplayListItems = new List<ItemsToDisplay>
		{
			new ItemsToDisplay{ Id = "Print Servers", Data1= "some data", Data2 = "more data to display"},
			new ItemsToDisplay{ Id = "Network Stuff", Data1= "IP4", Data2 = "any left"},
			new ItemsToDisplay{ Id = "Job details", Data1= "too many", Data2 = "say no"},
			new ItemsToDisplay{ Id = "Firewall", Data1= "what", Data2 = "Let's burn it"}

		}
	};
	var path = _pdfService.CreatePdf(data);

	var stream = new FileStream(path, FileMode.Open);
	return File(stream, "application/pdf");
}

The PdfService implements one public method, CreatePdf which takes the model as a parameter. The path configurations are defined as private fields in the class. In a real application, these settings would be read from the app.settings. The method sets up the PDF document and pages using the PDFSharp project. Each part of the document is then created in different private methods.

using AspNetCorePdf.PdfProvider.DataModel;
using PdfSharp.Drawing;
using PdfSharp.Drawing.Layout;
using PdfSharp.Fonts;
using PdfSharp.Pdf;
using System;
using System.IO;

namespace AspNetCorePdf.PdfProvider
{
    public class PdfService : IPdfService
    {
        private string _createdDocsPath = ".\\PdfProvider\\Created";
        private string _imagesPath = ".\\PdfProvider\\Images";
        private string _resourcesPath = ".\\PdfProvider\\Resources";

        public string CreatePdf(PdfData pdfData)
        {
            if (GlobalFontSettings.FontResolver == null)
            {
                GlobalFontSettings.FontResolver = new FontResolver(_resourcesPath);
            }

            var document = new PdfDocument();
            var page = document.AddPage();
            var gfx = XGraphics.FromPdfPage(page);
    
            AddTitleLogo(gfx, page, $"{_imagesPath}\\logo.jpg", 0, 0);
            AddTitleAndFooter(page, gfx, pdfData.DocumentTitle, document, pdfData);

            AddDescription(gfx, pdfData);

            AddList(gfx, pdfData);

            string docName = $"{_createdDocsPath}/{pdfData.DocumentName}-{DateTime.UtcNow.ToOADate()}.pdf";
            document.Save(docName);
            return docName;
        }

XGraphics is then used to create the document as required. Refer to the samples for reference:

http://www.pdfsharp.net/wiki/PDFsharpSamples.ashx

void AddTitleLogo(XGraphics gfx, PdfPage page, string imagePath, int xPosition, int yPosition)
{
	if (!File.Exists(imagePath))
	{
		throw new FileNotFoundException(String.Format("Could not find image {0}.", imagePath));
	}

	XImage xImage = XImage.FromFile(imagePath);
	gfx.DrawImage(xImage, xPosition, yPosition, xImage.PixelWidth / 8, xImage.PixelWidth / 8);
}

void AddTitleAndFooter(PdfPage page, XGraphics gfx, string title, PdfDocument document, PdfData pdfData)
{
	XRect rect = new XRect(new XPoint(), gfx.PageSize);
	rect.Inflate(-10, -15);
	XFont font = new XFont("OpenSans", 14, XFontStyle.Bold);
	gfx.DrawString(title, font, XBrushes.MidnightBlue, rect, XStringFormats.TopCenter);

	rect.Offset(0, 5);
	font = new XFont("OpenSans", 8, XFontStyle.Italic);
	XStringFormat format = new XStringFormat();
	format.Alignment = XStringAlignment.Near;
	format.LineAlignment = XLineAlignment.Far;
	gfx.DrawString("Created by " + pdfData.CreatedBy, font, XBrushes.DarkOrchid, rect, format);

	font = new XFont("OpenSans", 8);
	format.Alignment = XStringAlignment.Center;
	gfx.DrawString(document.PageCount.ToString(), font, XBrushes.DarkOrchid, rect, format);

	document.Outlines.Add(title, page, true);
}

void AddDescription(XGraphics gfx, PdfData pdfData)
{
	var font = new XFont("OpenSans", 14, XFontStyle.Regular);
	XTextFormatter tf = new XTextFormatter(gfx);
	XRect rect = new XRect(40, 100, 520, 100);
	gfx.DrawRectangle(XBrushes.White, rect);
	tf.DrawString(pdfData.Description, font, XBrushes.Black, rect, XStringFormats.TopLeft);
}

void AddList(XGraphics gfx, PdfData pdfData)
{
	int startingHeight = 200;
	int listItemHeight = 30;

	for (int i = 0; i < pdfData.DisplayListItems.Count; i++)
	{
		var font = new XFont("OpenSans", 14, XFontStyle.Regular);
		XTextFormatter tf = new XTextFormatter(gfx);
		XRect rect = new XRect(60, startingHeight, 500, listItemHeight);
		gfx.DrawRectangle(XBrushes.White, rect);
		var data = $"{i}. {pdfData.DisplayListItems[i].Id} | {pdfData.DisplayListItems[i].Data1} | {pdfData.DisplayListItems[i].Data2}";
		tf.DrawString(data, font, XBrushes.Black, rect, XStringFormats.TopLeft);

		startingHeight = startingHeight + listItemHeight;
	}
}

When the application is run, the create PDF link can be clicked, and it creates the PDF.

The PDF is returned in the browser. Each PDF can also be viewed in the Created directory.

This works really good, with little effort to setup. The used PDFSharp code is included in the repository. The MigraDoc is not part of this, it would be nice to use this as well, but no solution exists, which works for ASP.NET Core.

I really hope the the PDFSharp NuGet package as well as MigraDoc gets ported to .NET Core.

Links:

Creating a PDF in ASP.NET Core using MigraDoc PDFSharp

https://github.com/YetaWF/PDFsharp-.netcoreapp2.0

http://www.pdfsharp.net/wiki/Graphics-sample.ashx

http://www.pdfsharp.net/wiki/PDFsharpSamples.ashx

http://www.pdfsharp.net/

https://odetocode.com/blogs/scott/archive/2018/02/14/pdf-generation-in-azure-functions-v2.aspx

http://fizzylogic.nl/2017/08/03/how-to-generate-pdf-documents-in-asp-net-core/

https://github.com/rdvojmoc/DinkToPdf

https://photosauce.net/blog/post/5-reasons-you-should-stop-using-systemdrawing-from-aspnet

9 comments

  1. Nice post Damien. I recently implemented something similar but didn’t know about the .net standard library you found. Using a compatibility shim would also be an option.

    Building a Compatibility Shim with .NET Standard 2.0

  2. […] Creating PDF files in ASP.NET Core – Damien Bowden […]

  3. […] Creating PDF files in ASP.NET Core (Damien Bowden) […]

  4. […] article shows how to use MigraDoc in ASP.NET Core to create PDF documents. In the last blog post, Creating a PDF in ASP.NET Core, PDFSharp was used to create the PDF. MigraDoc is used on top on this, which makes it easy to […]

  5. GarryWang · · Reply

    I have some experience with Zetpdf.com as well. It’s really convenient and easy to use

  6. The best library I have used for creating PDF (based on Custom Desings) it is HtmlToPdf which it is free. There are some remarks related to it such as the library is native (meaning, you need pack the correct native binary (exe or dll) and use DLL imports or execute process to get it working.
    The library itself is based on WebKit thus HTML used tends to be very accurate representation. There are some extensible points for headers and footers.

    Long time ago I create a sample using it at https://hmadrigal.wordpress.com/2015/10/16/creating-pdf-reports-from-html-using-dotliquid-markup-for-templates-and-wkhtmltoxsharp-for-printing-pdf/

    1. thanks for the link, will give it a try.

  7. Roger Ospina · · Reply

    Hi, thanks for the post. I have a question. How could I change the development to set a Html as content of the Pdf file?

    Thanks man

  8. Zeshan Riaz · · Reply

    Thank you for sharing this wonderful info.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.