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:

https://damienbod.com/2018/10/03/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

Advertisements

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

    https://espressocoder.com/2018/09/28/building-a-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 […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

%d bloggers like this: