How to Migrate from wkhtmltopdf to IronPDF in C#
wkhtmltopdf has been a widely-used tool for converting HTML documents to PDF using Qt 4.8 + QtWebKit. Despite its popularity among developers for its command-line capabilities and free licensing, the project now presents critical security risks that can no longer be ignored. The GitHub repository was archived on January 2, 2023; the last upstream release is 0.12.6 from June 11, 2020; and CVE-2022-35583 (CVSS 9.8, SSRF) remains unpatched.
This guide provides a complete migration path from wkhtmltopdf to IronPDF, with step-by-step instructions, code comparisons, and practical examples for professional .NET developers who need to eliminate this security risk from their applications.
Critical Security Warning: CVE-2022-35583
wkhtmltopdf contains a critical security vulnerability that will never be fixed:
| Issue | Detail | Status |
|---|---|---|
| CVE-2022-35583 (SSRF, CWE-918) | CRITICAL (CVSS 9.8) | UNPATCHED — disputed by maintainers |
| GitHub repo archived | Read-only | Jan 2, 2023 |
| Last upstream release | 0.12.6 | June 11, 2020 |
| Underlying engine | Qt 4.8 + QtWebKit (Qt 4.8 EOL 2015) | OBSOLETE |
| CSS Grid Support | None | Broken |
| Flexbox Support | Partial | Broken |
| ES6+ JavaScript | Limited | Broken |
How the SSRF Attack Works
The Server-Side Request Forgery vulnerability allows attackers to access internal services, steal credentials, scan your internal network, and exfiltrate sensitive data through crafted HTML:
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
When wkhtmltopdf renders this HTML, it fetches these URLs from your server's network context, bypassing firewalls and security controls.
Affected Wrapper Libraries
Every .NET wrapper bundles or shells out to the same wkhtmltopdf native binary, so they all inherit its CVE exposure regardless of how active the wrapper itself is:
| Wrapper Library | Latest NuGet | Security Risk |
|---|---|---|
| DinkToPdf | 1.0.8 (April 2017) — abandoned | Inherits CVE-2022-35583 |
| Rotativa.AspNetCore (webgio fork) | 1.4.0 (Nov 2023) — wrapper updated, binary frozen | Inherits CVE-2022-35583 |
| TuesPechkin | 2.1.1 (Jan 2015) — abandoned | Inherits CVE-2022-35583 |
Haukcode.WkHtmlToPdfDotNet (formerly WkHtmlToPdf-DotNet) |
1.5.95 (Oct 2024) — wrapper updated, binary frozen | Inherits CVE-2022-35583 |
| NReco.PdfGenerator | wrapper updated, bundles wkhtmltopdf | Inherits CVE-2022-35583 |
If you use any of these libraries, your application is exposed to CVE-2022-35583 unless you sanitize all HTML input.
IronPDF vs wkhtmltopdf: Feature Comparison
Understanding the architectural differences helps technical decision-makers evaluate the migration investment:
| Feature | wkhtmltopdf | IronPDF |
|---|---|---|
| Licensing | LGPLv3 (Free) | Commercial |
| Rendering Engine | Qt 4.8 + QtWebKit (Qt 4.8 EOL 2015) | Current Chromium engine |
| Security Vulnerabilities | CVE-2022-35583 (CVSS 9.8) unpatched, disputed | No critical CVEs reported |
| Active Maintenance | GitHub repo archived Jan 2, 2023; last release June 2020 | Actively maintained with regular releases |
| Support for Modern Web Standards | Limited (Broken flexbox, no CSS Grid) | Supported |
| Integration and Support | Limited to community forums | Extensive documentation and dedicated support |
| CSS Grid | ❌ Not supported | ✅ Supported |
| Flexbox | ⚠ Broken | ✅ Supported |
| ES6+ JavaScript | ❌ Not supported | ✅ Supported |
| Async/Await | ❌ Not supported | ✅ Supported |
| PDF Manipulation | ❌ Not supported | ✅ Supported |
| Digital Signatures | ❌ Not supported | ✅ Supported |
| PDF/A Compliance | ❌ Not supported | ✅ Supported |
Quick Start: wkhtmltopdf to IronPDF Migration
The migration can begin immediately with these foundational steps.
Step 1: Remove wkhtmltopdf Packages and Binaries
Remove all wkhtmltopdf wrapper packages:
# Remove wkhtmltopdf wrapper (whichever you're using)
dotnet remove package Haukcode.WkHtmlToPdfDotNet
dotnet remove package DinkToPdf
dotnet remove package TuesPechkin
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
dotnet remove package NReco.PdfGenerator
# Remove wkhtmltopdf binary from your deployment
# Delete wkhtmltopdf.exe, wkhtmltox.dll, etc.
# Remove wkhtmltopdf wrapper (whichever you're using)
dotnet remove package Haukcode.WkHtmlToPdfDotNet
dotnet remove package DinkToPdf
dotnet remove package TuesPechkin
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
dotnet remove package NReco.PdfGenerator
# Remove wkhtmltopdf binary from your deployment
# Delete wkhtmltopdf.exe, wkhtmltox.dll, etc.
Step 2: Install IronPDF
# Add IronPDF (secure, modern alternative)
dotnet add package IronPdf
# Add IronPDF (secure, modern alternative)
dotnet add package IronPdf
Step 3: Update Namespaces
Replace wkhtmltopdf namespaces with the IronPDF namespace:
// Before (wkhtmltopdf)
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
// After (IronPDF)
using IronPdf;
// Before (wkhtmltopdf)
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
// After (IronPDF)
using IronPdf;
Imports IronPdf
Step 4: Initialize License
Add license initialization at application startup:
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Code Migration Examples
Converting HTML to PDF
The most fundamental operation reveals the complexity difference between these .NET PDF approaches.
wkhtmltopdf Approach:
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("output.pdf", pdf);
}
}
Imports Haukcode.WkHtmlToPdfDotNet
Imports Haukcode.WkHtmlToPdfDotNet.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter As New SynchronizedConverter(New PdfTools())
Dim doc As New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("output.pdf", pdf)
End Sub
End Module
IronPDF Approach:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>")
pdf.SaveAs("output.pdf")
End Sub
End Class
wkhtmltopdf requires creating a SynchronizedConverter with PdfTools, constructing an HtmlToPdfDocument with GlobalSettings and Objects, setting properties like ColorMode, Orientation, and PaperSize, calling converter.Convert() to get raw bytes, and manually writing to a file with File.WriteAllBytes().
IronPDF eliminates this ceremony entirely—create a ChromePdfRenderer, call RenderHtmlAsPdf(), and use the built-in SaveAs() method.
For advanced HTML-to-PDF scenarios, see the HTML to PDF conversion guide.
Converting URLs to PDF
URL-to-PDF conversion shows similar complexity patterns.
wkhtmltopdf Approach:
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
Page = "https://www.example.com"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("webpage.pdf", pdf);
}
}
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4
},
Objects = {
new ObjectSettings()
{
Page = "https://www.example.com"
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("webpage.pdf", pdf);
}
}
Imports Haukcode.WkHtmlToPdfDotNet
Imports Haukcode.WkHtmlToPdfDotNet.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter As New SynchronizedConverter(New PdfTools())
Dim doc As New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Portrait,
.PaperSize = PaperKind.A4
},
.Objects = New List(Of ObjectSettings) From {
New ObjectSettings() With {
.Page = "https://www.example.com"
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("webpage.pdf", pdf)
End Sub
End Module
IronPDF Approach:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
wkhtmltopdf uses the Page property in ObjectSettings to specify a URL, requiring the same document construction pattern. IronPDF provides a dedicated RenderUrlAsPdf() method that clearly expresses intent.
Explore the URL to PDF documentation for authentication and custom header options.
Custom Settings: HTML Files with Page Configuration
Configuring orientation, margins, and paper size requires different approaches.
wkhtmltopdf Approach:
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings()
{
Page = "input.html",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("custom-output.pdf", pdf);
}
}
// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;
class Program
{
static void Main()
{
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4,
Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
},
Objects = {
new ObjectSettings()
{
Page = "input.html",
WebSettings = { DefaultEncoding = "utf-8" }
}
}
};
byte[] pdf = converter.Convert(doc);
File.WriteAllBytes("custom-output.pdf", pdf);
}
}
Imports Haukcode.WkHtmlToPdfDotNet
Imports Haukcode.WkHtmlToPdfDotNet.Contracts
Imports System.IO
Module Program
Sub Main()
Dim converter = New SynchronizedConverter(New PdfTools())
Dim doc = New HtmlToPdfDocument() With {
.GlobalSettings = New GlobalSettings() With {
.ColorMode = ColorMode.Color,
.Orientation = Orientation.Landscape,
.PaperSize = PaperKind.A4,
.Margins = New MarginSettings() With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
},
.Objects = {
New ObjectSettings() With {
.Page = "input.html",
.WebSettings = New WebSettings() With {.DefaultEncoding = "utf-8"}
}
}
}
Dim pdf As Byte() = converter.Convert(doc)
File.WriteAllBytes("custom-output.pdf", pdf)
End Sub
End Module
IronPDF Approach:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
var pdf = renderer.RenderHtmlFileAsPdf("input.html");
pdf.SaveAs("custom-output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
var pdf = renderer.RenderHtmlFileAsPdf("input.html");
pdf.SaveAs("custom-output.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Imports System
Class Program
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
Dim pdf = renderer.RenderHtmlFileAsPdf("input.html")
pdf.SaveAs("custom-output.pdf")
End Sub
End Class
wkhtmltopdf nests settings inside GlobalSettings and Objects, with MarginSettings as a separate object. IronPDF provides direct RenderingOptions properties with clear names like PaperOrientation, MarginTop, and PaperSize.
wkhtmltopdf API to IronPDF Mapping Reference
This mapping accelerates migration by showing direct API equivalents:
CLI to IronPDF Mapping
| wkhtmltopdf CLI Option | IronPDF Equivalent |
|---|---|
wkhtmltopdf input.html output.pdf |
renderer.RenderHtmlFileAsPdf() |
wkhtmltopdf URL output.pdf |
renderer.RenderUrlAsPdf() |
--page-size A4 |
RenderingOptions.PaperSize = PdfPaperSize.A4 |
--page-size Letter |
RenderingOptions.PaperSize = PdfPaperSize.Letter |
--orientation Landscape |
RenderingOptions.PaperOrientation = Landscape |
--margin-top 10mm |
RenderingOptions.MarginTop = 10 |
--margin-bottom 10mm |
RenderingOptions.MarginBottom = 10 |
--margin-left 10mm |
RenderingOptions.MarginLeft = 10 |
--margin-right 10mm |
RenderingOptions.MarginRight = 10 |
--header-html header.html |
RenderingOptions.HtmlHeader |
--footer-center "[page]" |
{page} placeholder |
--footer-center "[toPage]" |
{total-pages} placeholder |
--enable-javascript |
Enabled by default |
--javascript-delay 500 |
RenderingOptions.WaitFor.RenderDelay = 500 |
--dpi 300 |
RenderingOptions.Dpi = 300 |
--grayscale |
RenderingOptions.GrayScale = true |
C# Wrapper API Mapping
| wkhtmltopdf Wrapper | IronPDF |
|---|---|
SynchronizedConverter |
ChromePdfRenderer |
HtmlToPdfDocument |
RenderingOptions |
GlobalSettings.Out |
pdf.SaveAs() |
GlobalSettings.PaperSize |
RenderingOptions.PaperSize |
GlobalSettings.Orientation |
RenderingOptions.PaperOrientation |
GlobalSettings.Margins |
RenderingOptions.Margin* |
ObjectSettings.Page |
RenderHtmlFileAsPdf() |
ObjectSettings.HtmlContent |
RenderHtmlAsPdf() |
converter.Convert(doc) |
renderer.RenderHtmlAsPdf() |
Placeholder Syntax Migration
| wkhtmltopdf Placeholder | IronPDF Placeholder |
|---|---|
[page] |
{page} |
[toPage] |
{total-pages} |
[date] |
{date} |
[time] |
{time} |
[title] |
{html-title} |
[url] |
{url} |
Common Migration Issues and Solutions
Issue 1: Header/Footer Placeholder Syntax
wkhtmltopdf: Uses square bracket syntax like [page] and [toPage].
Solution: Update to IronPDF's curly brace placeholders:
// Before (wkhtmltopdf)
FooterSettings = { Left = "Page [page] of [toPage]" }
// After (IronPDF)
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
MaxHeight = 25
};
// Before (wkhtmltopdf)
FooterSettings = { Left = "Page [page] of [toPage]" }
// After (IronPDF)
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
MaxHeight = 25
};
' Before (wkhtmltopdf)
FooterSettings = New With {.Left = "Page [page] of [toPage]"}
' After (IronPDF)
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
.MaxHeight = 25
}
Issue 2: JavaScript Delay Configuration
wkhtmltopdf: Uses JavascriptDelay property with limited reliability.
Solution: IronPDF provides multiple options:
renderer.RenderingOptions.EnableJavaScript = true;
// Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500);
// Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded");
// Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true");
renderer.RenderingOptions.EnableJavaScript = true;
// Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500);
// Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded");
// Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true");
renderer.RenderingOptions.EnableJavaScript = True
' Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500)
' Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded")
' Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true")
Issue 3: Modern CSS Not Rendering
Symptom: CSS Grid and Flexbox layouts render incorrectly in wkhtmltopdf.
Solution: IronPDF's Chromium engine handles modern CSS correctly:
// This CSS now works with IronPDF
var html = @"
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
// This CSS now works with IronPDF
var html = @"
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html);
Dim html As String = "
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
Issue 4: Synchronous vs Asynchronous Rendering
wkhtmltopdf: Wrappers are synchronous and block threads.
Solution: IronPDF supports async rendering:
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
Imports System.Threading.Tasks
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Dim renderer As New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Function
wkhtmltopdf Migration Checklist
Pre-Migration Tasks
Audit your codebase to identify all wkhtmltopdf usage:
# Find all wkhtmltopdf references
grep -r "Haukcode.WkHtmlToPdfDotNet\|WkHtmlToPdfDotNet\|DinkToPdf\|TuesPechkin\|Rotativa\|NReco.PdfGenerator" --include="*.cs" .
grep -r "wkhtmltopdf" --include="*.yml" --include="*.yaml" --include="Dockerfile" .
# Find all wkhtmltopdf references
grep -r "Haukcode.WkHtmlToPdfDotNet\|WkHtmlToPdfDotNet\|DinkToPdf\|TuesPechkin\|Rotativa\|NReco.PdfGenerator" --include="*.cs" .
grep -r "wkhtmltopdf" --include="*.yml" --include="*.yaml" --include="Dockerfile" .
Locate and document wkhtmltopdf binary files for removal. Document current settings (paper size, margins, headers/footers).
Code Update Tasks
- Remove all wkhtmltopdf wrapper NuGet packages
- Remove wkhtmltopdf binaries (wkhtmltopdf.exe, wkhtmltox.dll)
- Install IronPDF NuGet package
- Update namespace imports from
Haukcode.WkHtmlToPdfDotNet(or the wrapper you used) toIronPdf - Replace
SynchronizedConverterwithChromePdfRenderer - Convert
HtmlToPdfDocumentpatterns to direct rendering methods - Update
GlobalSettingsconfigurations toRenderingOptions - Convert margin configurations from
MarginSettingsto individual properties - Update placeholder syntax (
[page]→{page},[toPage]→{total-pages}) - Add IronPDF license initialization at startup
Post-Migration Testing
After migration, verify these aspects:
- Visual comparison of PDF output (should improve with modern CSS support)
- Verify modern CSS rendering (CSS Grid and Flexbox now work)
- Test JavaScript-heavy pages
- Security scan to confirm no wkhtmltopdf binaries remain
- Load test for performance comparison
Security Verification
# Scan for any remaining wkhtmltopdf artifacts
find /var/www/ -name "*wkhtmlto*" 2>/dev/null
find /usr/local/bin/ -name "*wkhtmlto*" 2>/dev/null
docker images | grep wkhtmltopdf
# Check if any process is still using it
ps aux | grep wkhtmltopdf
# Scan for any remaining wkhtmltopdf artifacts
find /var/www/ -name "*wkhtmlto*" 2>/dev/null
find /usr/local/bin/ -name "*wkhtmlto*" 2>/dev/null
docker images | grep wkhtmltopdf
# Check if any process is still using it
ps aux | grep wkhtmltopdf
Key Benefits of Migrating to IronPDF
Moving from wkhtmltopdf to IronPDF provides several critical advantages:
Security: CVE-2022-35583 and all wkhtmltopdf vulnerabilities are eliminated. IronPDF has no known CVEs and receives regular security updates.
Modern Rendering Engine: IronPDF uses the current Chromium engine, ensuring full CSS3, CSS Grid, Flexbox, and ES6+ JavaScript support. Modern frameworks render correctly.
Simplified API: Direct rendering methods replace document construction patterns. Built-in SaveAs() methods eliminate manual byte handling.
Extended Capabilities: PDF manipulation, digital signatures, PDF/A compliance, watermarks, and merge/split operations are built-in features that wkhtmltopdf couldn't provide.
Active Development: IronPDF's regular updates track current .NET releases, so modern .NET and C# language versions are supported as they ship.
Async Support: Prevent thread blocking in high-load web applications with native async/await support.

