17. Jun 2024
Lesedauer 5 Min.
Aus HTML mach PDF
PDF-Dateien im Web erstellen
So setzen Sie das NuGet-Package DinkToPdf ein.

Es existieren zahlreiche kommerzielle Bibliotheken für das Erstellen von PDF-Dateien in C#, wie zum Beispiel IronPDF [1] und Aspose.PDF [2]. Wer eine kostenfreie Bibliothek für die Erstellung von PDF-Dateien sucht, kann beispielsweise zwischen PDFsharp [3] und DinkToPdf [4] wählen.Mit PDFsharp werden die PDF-Dateien mit Zeichenroutinen, die aus GDI+ bekannt sind, erstellt. Fast alle Funktionen von GDI+ sind auch in PDFsharp verfügbar [5].Im Gegensatz dazu wandelt DinkToPdf HTML-Code in PDF-Dateien um, wobei auch CSS-Formatierungen möglich sind. Aufgrund der Vertrautheit vieler Webentwickler mit HTML wird die Entscheidung vermutlich zugunsten von DinkToPdf fallen.
Installation und Konfiguration von DinkToPdf
DinkToPdf, eine plattformübergreifende Bibliothek, fungiert als Wrapper für die wkhtmltopdf-Bibliothek. wkhtmltopdf ist ein Open-Source-Befehlszeilentool (LGPLv3), das HTML-Code unter Verwendung einer WebKit-Rendering-Engine in PDF umwandelt [6].DinkToPdf ist als NuGet-Package in der Version 1.08 verfügbar und kann über den NuGet-Paket-Manager oder mit dem Befehl Install-Package DinkToPdf über die Paket-Manager-Konsole installiert werden. Dabei werden die DLL-Dateien aus der wkhtmltopdf-Bibliothek nicht automatisch installiert; diese müssen manuell zum Projekt hinzugefügt werden.Wir installieren jedoch die benötigte DLL-Datei aus der wkhtmltopdf-Bibliothek zunächst nicht, damit wir die entsprechende Fehlermeldung generieren können, die auftritt, wenn die DLL-Datei fehlt.In unserem Beispiel verwenden wir eine MVC-Webseite, .NET 8 und C#. Zunächst installieren wir das NuGet-Package DinkToPdf. Anschließend wird der Service in der Datei Program.cs wie folgt registriert:
<span class="hljs-keyword">var</span> converter = <span class="hljs-keyword">new</span><span class="hljs-type"></span> SynchronizedConverter(
<span class="hljs-keyword">new</span><span class="hljs-type"></span> PdfTools());
builder.Services.AddSingleton<IConverter>(converter);
Hiermit haben wir den HTML-zu-PDF-Converter aus dem NuGet-Package DinkToPdf als Service registriert und können diesen mittels Dependency Injection überall in unserem Projekt verwenden.
Konfiguration der PDF-Seite
DinkToPdf bietet drei Hauptklassen für die Konfiguration:- Die Klasse GlobalSettings besteht aus den allgemeinen Konfigurationseigenschaften für das PDF-Dokument. Wir verwenden nur einige dieser Eigenschaften, um den Farbmodus, die Ausrichtung, das Papierformat, den Dokumententitel der Seite einzurichten.
- Die Klasse ObjectSettings besteht aus den Eigenschaften, die mit dem Inhalt des PDF-Dokuments zusammenhängen. Hier können wir zum einen die Paginierung und den Inhalt der Kopf- und Fußzeilen festlegen. Zum anderen gibt es noch die Web-Einstellungen und die HtmlContent-Eigenschaft. In den Web-Einstellungen der ObjectSettings lässt sich auch festlegen, ob JavaScript aktiviert sein soll oder nicht und ob eine – und welche – Style-Sheet-Datei für das Rendern des HTML-Codes verwendet werden soll. In unserem Beispiel ist das die Datei PDFstyles.css im Ordner wwwroot/css; diese formatiert die Tabelle mit einem blauen Header und einem blauen Rahmen (Listing 1). Die HtmlContent-Eigenschaft ist eine sehr wichtige Eigenschaft dieser Klasse; ihr wird später die von uns generierte HTML-Vorlage übergeben.
Listing 1: Inhalt der Datei PDFstyles.css
<span class="hljs-selector-tag">h1</span> {<br/> <span class="hljs-attribute">color</span>: blue;<br/> <span class="hljs-attribute">text-align</span>: center;<br/>}<br/><span class="hljs-selector-tag">table</span> {<br/> <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;<br/> <span class="hljs-attribute">border-collapse</span>: collapse;<br/>}<br/><span class="hljs-selector-tag">table</span>, <span class="hljs-selector-tag">th</span>, <span class="hljs-selector-tag">td</span> {<br/> <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid blue;<br/> <span class="hljs-attribute">font-size</span>: <span class="hljs-number">22px</span>;<br/>}<br/><span class="hljs-selector-tag">td</span>, <span class="hljs-selector-tag">th</span> {<br/> <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;<br/>}<br/><span class="hljs-selector-tag">th</span> {<br/> <span class="hljs-attribute">background-color</span>: blue;<br/> <span class="hljs-attribute">color</span>: white;<br/> <span class="hljs-attribute">text-align</span>: left;<br/>}
- Zuletzt gibt es noch die Klasse HtmlToPdfDocument, welche die GlobalSettings und ObjectSettings als Eigenschaften beinhaltet.
Listing 2: Die Eigenschaften unserer PDF-Datei werden in einer separaten Klasse gesetzt
public class PdfConfigSettings<br/>{<br/> public static HtmlToPdfDocument <br/> GetHtmlToPdfDocument()<br/> {<br/> var globalSettings = new GlobalSettings<br/> {<br/> ColorMode = ColorMode.Color,<br/> Orientation = Orientation.Portrait,<br/> PaperSize = PaperKind.A4,<br/> Margins = new MarginSettings {Top = 10},<br/> DocumentTitle = "",<br/> };<br/> var objectSettings = new ObjectSettings<br/> {<br/> PagesCount = true,<br/> HtmlContent = "", // hier wird später der <br/> HTML-Code eingefügt<br/> WebSettings = { <br/> DefaultEncoding = "utf-8", <br/> EnableJavascript = false, <br/> UserStyleSheet = Path.Combine(<br/> Directory.GetCurrentDirectory(),<br/> "wwwroot/css", "PDFstyles.css") <br/> },<br/> FooterSettings = { <br/> FontName = "Calibri, Arial", <br/> FontSize = 8, <br/> Right = "Seite [page] von [toPage]", <br/> Line = false }<br/> };<br/> var htmlToPdfDocument = new HtmlToPdfDocument()<br/> {<br/> GlobalSettings = globalSettings,<br/> Objects = { objectSettings }<br/> };<br/> return htmlToPdfDocument;<br/> }<br/>}
Erstellung von Beispieldaten für das PDF-Dokument
In unserem Beispiel möchten wir Informationen über die Mitglieder eines fiktiven Vereins als PDF-Datei ausgeben und auf der Webseite anzeigen und dort auch zum Download anbieten. Dazu wurde zunächst eine Klasse Members und danach eine Klasse Data mit einer Methode GetAllMembers() erstellt. Die Methode GetAllMembers() gibt eine Liste von 20 Mitgliedern zurück; diese Mitgliederdaten wurden mittels ChatGPT erstellt.Generierung des HTML-Codes
Jetzt brauchen wir noch eine Methode, die uns eine Tabelle mit den Mitgliederdaten in HTML zurückgibt. Mittels einer Klasse PdfReportGenerator sowie der Methode GetHTMLString() lassen wir uns den HTML-Code für unsere Mitgliederliste erstellen (Listing 3).Listing 3: Die Klasse PdfReportGenerator zum Erstellen des HTML-Codes
public static class PdfReportGenerator<br/>{<br/> public static string GetHTMLString()<br/> {<br/> var members = Data.GetAllMembers();<br/> var sb = new StringBuilder();<br/> sb.Append(@"<br/> &lt;html&gt;<br/> &lt;head&gt;<br/> &lt;/head&gt;<br/> &lt;body&gt;<br/> &lt;div class='header'&gt;<br/> &lt;h1&gt;Mitglieder-Liste&lt;/h1&gt;&lt;/div&gt;<br/> &lt;table align='center'&gt;<br/> &lt;tr&gt;<br/> &lt;th&gt;Name&lt;/th&gt;<br/> &lt;th&gt;Vorname&lt;/th&gt;<br/> &lt;th&gt;Strasse&lt;/th&gt;<br/> &lt;th&gt;PLZ&lt;/th&gt;<br/> &lt;th&gt;Ort&lt;/th&gt;<br/> &lt;/tr&gt;");<br/> foreach (var member in members)<br/> {<br/> sb.AppendFormat(@"&lt;tr&gt;<br/> &lt;td&gt;{0}&lt;/td&gt;<br/> &lt;td&gt;{1}&lt;/td&gt;<br/> &lt;td&gt;{2}&lt;/td&gt;<br/> &lt;td&gt;{3}&lt;/td&gt;<br/> &lt;td&gt;{4}&lt;/td&gt;<br/> &lt;/tr&gt;", <br/> member.Firstname, member.<br/> LastName, member.Street, <br/> member.PLZ, member.City);<br/> }<br/> sb.Append(@"<br/> &lt;/table&gt;<br/> &lt;/body&gt;<br/> &lt;/html&gt;");<br/> return sb.ToString();<br/> }<br/>}
In unserem Controller können wir in der Methode ShowPDF() nun mit vier Codezeilen die PDF-Datei ausgeben, siehe Listing 4. Zunächst lassen wir uns mit der Methode GetHtmlToPdfDocument() aus der Klasse PdfConfigSettings ein bereits konfiguriertes Objekt der Klasse HtmlToPdfDocument zurückgeben. Anschließend übergeben wir an die Eigenschaft HtmlContent den HTML-Code, den wir uns mit GetHTMLString() aus der Klasse PdfReportGenerator zurückgeben lassen.
Listing 4: Die PDF-Datei im Controller ausgeben
using CreatePDFOnWeb.PDFHelper;<br/>using DinkToPdf;<br/>using DinkToPdf.Contracts;<br/>using Microsoft.AspNetCore.Mvc;<br/>namespace CreatePDFOnWeb.Controllers<br/>{<br/> public class PdfController : Controller<br/> {<br/> private readonly IConverter _converter; <br/> public PdfController(IConverter converter)<br/> {<br/> _converter = converter;<br/> }<br/> public IActionResult ShowPDF()<br/> {<br/> HtmlToPdfDocument htmlToPdfDocument = <br/> PdfConfigSettings.GetHtmlToPdfDocument();<br/> htmlToPdfDocument.Objects[0].HtmlContent = <br/> PdfReportGenerator.GetHTMLString();<br/> byte[] file = _converter.Convert(<br/> htmlToPdfDocument);<br/> return File(file, "application/pdf");<br/> }<br/> }<br/>}
Ausgabe der PDF-Datei – schlägt fehl
Nun übergeben wir das HtmlToPdfDocument-Objekt an den Converter-Service, den wir per Dependency Injection in den Kontroller eingebunden haben. Als Ergebnis erhalten wir ein Byte-Array. Jetzt müssen wir nur noch das Byte-Array als File mit dem ContentType”application/pdf” zurückgeben, und die PDF-Datei sollte im Browser angezeigt werden.Externe DLL-Datei hinzufügen und registrieren
Mit dem bisherigen Code funktioniert das jedoch noch nicht. Die Anwendung lässt sich kompilieren und starten, doch erhalten wir beim Versuch, die PDF-Seite auszugeben, einen Laufzeitfehler (siehe Bild 1). Die Fehlermeldung „Unable to load DLL 'libwkhtmltox' or one of its dependencies:“ weist auf eine fehlende DLL-Datei namens libwkhtmltox hin.
Fehlermeldung wegen fehlender DLL-Datei (Bild 1)
Autor
Die benötigte DLL-Datei lässt sich aus dem DinkToPdf-Repository bei GitHub [4] herunterladen und im Projekt platzieren; libwkhtmltox.dll findet sich im Ordner \v0.12.4\64 bit. Wir kopieren sie in unserem Beispiel in den Ordner wwwroot\pdfCreatorDll. Damit unsere Anwendung diese DLL-Datei finden und verwenden kann, müssen wir sie zunächst registrieren.Dazu haben wir eine Klasse CustomAssemblyLoadContext
.cs angelegt (Listing 5). Diese erbt von der Klasse AssemblyLoadContext und überschreibt die Methoden LoadUnmanagedLibrary und LoadUnmanagedDll.
.cs angelegt (Listing 5). Diese erbt von der Klasse AssemblyLoadContext und überschreibt die Methoden LoadUnmanagedLibrary und LoadUnmanagedDll.
Listing 5: Inhalt der Klasse CustomAssemblyLoadContext
public class CustomAssemblyLoadContext : <br/> AssemblyLoadContext<br/>{<br/> public nint LoadUnmanagedLibrary(<br/> string absolutePath)<br/> {<br/> return LoadUnmanagedDll(absolutePath);<br/> }<br/> protected override nint LoadUnmanagedDll(<br/> string unmanagedDllName)<br/> {<br/> return LoadUnmanagedDllFromPath(unmanagedDllName);<br/> }<br/>}
Zuletzt müssen wir noch das Laden der DLL-Datei in der Datei Program.cs initiieren (Listing 6).
Listing 6: Die benötigten Einträge in der Datei Program.cs
// register libwkhtmltox.dll <br/>var contentRootPath = <br/> builder.Environment.ContentRootPath;<br/>var libwkhtmltoxPath = Path.Combine(contentRootPath, <br/> $"wwwroot\\pdfCreatorDll\\libwkhtmltox.dll");<br/>var assemblyLoadContext = <br/> new CustomAssemblyLoadContext();<br/>assemblyLoadContext.LoadUnmanagedLibrary(<br/> libwkhtmltoxPath);<br/>// register service DinkToPdf<br/>var converter = new SynchronizedConverter(<br/> new PdfTools());<br/>builder.Services.AddSingleton&lt;IConverter&gt;(converter);
PDF-Datei im Webbrowser erstellen
Nach Abschluss dieser Schritte ist die PDF-Erstellung in der Webanwendung realisierbar (siehe Bild 2).
Ansicht der PDF-Datei im Browser (Bild 2)
Autor
Das Codebeispiel dieses Artikels kann unter [7] heruntergeladen werden.
Fussnoten
- IronPDF, The C# PDF Library, http://www.dotnetpro.de/SL2407DinkToPdf1
- Aspose.PDF for .NET Documentation, http://www.dotnetpro.de/SL2407DinkToPdf2
- PDFsharp, http://www.dotnetpro.de/SL2407DinkToPdf3
- DinkToPdf auf GitHub, http://www.dotnetpro.de/SL2407DinkToPdf4
- PDFsharp & MigraDoc, Overview, http://www.dotnetpro.de/SL2407DinkToPdf5
- wkhtmltopdf, http://www.dotnetpro.de/SL2407DinkToPdf6
- ChristianKiefer / CreatePDFOnWebsites auf GitHub, http://www.dotnetpro.de/SL2407DinkToPdf7