How to Migrate from MigraDoc to IronPDF in C#
Migrating from MigraDoc to IronPDF transforms your .NET PDF workflow from a verbose programmatic document model requiring manual element-by-element construction to a modern HTML/CSS-based approach that leverages existing web development skills. This guide provides a comprehensive, step-by-step migration path that eliminates the steep learning curve of MigraDoc's proprietary document object model for professional .NET developers.
Why Migrate from MigraDoc to IronPDF
The MigraDoc Challenges
MigraDoc, while powerful for programmatic PDF generation, has fundamental limitations that affect modern development workflows:
No HTML Support: MigraDoc doesn't support HTML directly. You must manually construct documents element-by-element using
Document,Section,Paragraph, andTableobjects—you cannot leverage existing HTML/CSS designs.Proprietary Document Model: MigraDoc requires learning a unique document model with concepts like
AddSection(),AddParagraph(),AddTable(),AddRow(), andAddCell(). This steep learning curve is particularly challenging for developers with web development backgrounds.Limited Styling Options: While MigraDoc offers robust document structure management, its styling capabilities are modest compared to modern web tools. Properties like
Format.Font.Size,Format.Font.Bold, andFormat.Alignmentare limited compared to full CSS3.Verbose Code: Creating even simple layouts requires dozens of lines of code. A basic table with headers can require 15-20 lines of MigraDoc code.
No JavaScript Support: MigraDoc cannot render dynamic content or execute JavaScript, limiting options for modern charting and interactive elements.
- Charts Are Basic: MigraDoc's chart functionality is limited compared to modern JavaScript charting libraries like Chart.js or D3.
MigraDoc vs IronPDF Comparison
| Feature | MigraDoc | IronPDF |
|---|---|---|
| Content Definition | Programmatic (Document/Section/Paragraph) | HTML/CSS |
| Learning Curve | Steep (proprietary DOM) | Easy (web skills) |
| Styling | Limited properties | Full CSS3 |
| JavaScript | None | Full Chromium execution |
| Tables | Manual column/row definition | HTML <table> with CSS |
| Charts | Basic MigraDoc charts | Any JavaScript charting library |
| Images | Manual sizing/positioning | Standard HTML <img> |
| Responsive Layouts | Not supported | Flexbox, Grid |
| License | Open Source (MIT) | Commercial |
For teams planning .NET 10 and C# 14 adoption through 2025 and 2026, IronPDF provides a future-proof foundation that allows developers to use familiar HTML/CSS skills rather than learning a proprietary document model.
Migration Complexity Assessment
Estimated Effort by Feature
| Feature | Migration Complexity | Notes |
|---|---|---|
| Simple Text | Very Low | Paragraph → HTML elements |
| Tables | Low | Table/Row/Cell → HTML <table> |
| Headers/Footers | Low | Section.Headers → RenderingOptions |
| Styles | Medium | Format properties → CSS classes |
| Images | Low | AddImage → HTML <img> |
| Charts | Medium | Requires JavaScript library |
Paradigm Shift
The fundamental shift in this MigraDoc migration is from programmatic document construction to HTML-first rendering:
MigraDoc: Document → AddSection() → AddParagraph() → PdfDocumentRenderer → Save()
IronPDF: ChromePdfRenderer → RenderHtmlAsPdf(html) → SaveAs()This paradigm shift dramatically reduces code complexity while providing unlimited styling capabilities through CSS.
Before You Start
Prerequisites
- .NET Environment: .NET Framework 4.6.2+ or .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet Access: Ability to install NuGet packages
- IronPDF License: Obtain your license key from ironpdf.com
NuGet Package Changes
# Remove MigraDoc packages
dotnet remove package PdfSharp-MigraDoc
dotnet remove package PdfSharp-MigraDoc-GDI
dotnet remove package PDFsharp.MigraDoc.Standard
# Install IronPDF
dotnet add package IronPdf# Remove MigraDoc packages
dotnet remove package PdfSharp-MigraDoc
dotnet remove package PdfSharp-MigraDoc-GDI
dotnet remove package PDFsharp.MigraDoc.Standard
# Install IronPDF
dotnet add package IronPdfLicense Configuration
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";Identify MigraDoc Usage
# Find all MigraDoc references
grep -r "using MigraDoc\|PdfDocumentRenderer\|AddSection\|AddParagraph" --include="*.cs" .
grep -r "AddTable\|AddRow\|AddColumn\|AddCell\|AddImage" --include="*.cs" .# Find all MigraDoc references
grep -r "using MigraDoc\|PdfDocumentRenderer\|AddSection\|AddParagraph" --include="*.cs" .
grep -r "AddTable\|AddRow\|AddColumn\|AddCell\|AddImage" --include="*.cs" .Complete API Reference
Class Mappings
| MigraDoc Class | IronPDF Equivalent | Notes |
|---|---|---|
Document | ChromePdfRenderer | Use renderer, not document |
Section | HTML <body> or <div> | Structural container |
Paragraph | HTML <p>, <h1>, etc. | Text elements |
FormattedText | HTML <span>, <strong>, etc. | Inline formatting |
Table | HTML <table> | With CSS styling |
Row | HTML <tr> | Table row |
Column | HTML <col> or CSS | Column styling |
Cell | HTML <td>, <th> | Table cell |
PdfDocumentRenderer | ChromePdfRenderer | Main renderer |
Method Mappings
| MigraDoc Method | IronPDF Equivalent | Notes |
|---|---|---|
document.AddSection() | HTML structure | Use <div> or <section> |
section.AddParagraph(text) | <p>text</p> | HTML paragraph |
section.AddTable() | <table> | HTML table |
table.AddColumn(width) | CSS width property | Style on <th> or <td> |
table.AddRow() | <tr> | HTML row |
row.Cells[n].AddParagraph() | <td>content</td> | HTML cell |
renderer.RenderDocument() | RenderHtmlAsPdf(html) | Render to PDF |
pdfDocument.Save(path) | pdf.SaveAs(path) | Save file |
Placeholder Mappings (Headers/Footers)
| MigraDoc Method | IronPDF Placeholder | Notes |
|---|---|---|
AddPageField() | {page} | Current page number |
AddNumPagesField() | {total-pages} | Total page count |
AddDateField() | {date} | Current date |
Code Migration Examples
Example 1: Basic HTML to PDF (The Fundamental Difference)
Before (MigraDoc):
// NuGet: Install-Package PdfSharp-MigraDoc-GDI
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
using System.Diagnostics;
class Program
{
static void Main()
{
// MigraDoc doesn't support HTML directly
// Must manually create document structure
Document document = new Document();
Section section = document.AddSection();
Paragraph paragraph = section.AddParagraph();
paragraph.AddFormattedText("Hello World", TextFormat.Bold);
paragraph.Format.Font.Size = 16;
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("output.pdf");
}
}// NuGet: Install-Package PdfSharp-MigraDoc-GDI
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
using System.Diagnostics;
class Program
{
static void Main()
{
// MigraDoc doesn't support HTML directly
// Must manually create document structure
Document document = new Document();
Section section = document.AddSection();
Paragraph paragraph = section.AddParagraph();
paragraph.AddFormattedText("Hello World", TextFormat.Bold);
paragraph.Format.Font.Size = 16;
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("output.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
}
}This example illustrates the fundamental difference between MigraDoc and IronPDF. MigraDoc requires creating a Document, adding a Section, adding a Paragraph, using AddFormattedText() with TextFormat.Bold, setting Format.Font.Size, creating a PdfDocumentRenderer, assigning the document, calling RenderDocument(), and finally saving. That's 10+ lines of code with multiple objects.
IronPDF accomplishes the same result in 3 lines: create a renderer, render HTML, and save. The HTML <h1> tag naturally provides the bold, large heading style. See the HTML to PDF documentation for additional rendering options.
Example 2: Creating Tables
Before (MigraDoc):
// NuGet: Install-Package PdfSharp-MigraDoc-GDI
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Tables;
using MigraDoc.Rendering;
class Program
{
static void Main()
{
Document document = new Document();
Section section = document.AddSection();
Table table = section.AddTable();
table.Borders.Width = 0.75;
Column column1 = table.AddColumn("3cm");
Column column2 = table.AddColumn("3cm");
Row row1 = table.AddRow();
row1.Cells[0].AddParagraph("Name");
row1.Cells[1].AddParagraph("Age");
Row row2 = table.AddRow();
row2.Cells[0].AddParagraph("John");
row2.Cells[1].AddParagraph("30");
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("table.pdf");
}
}// NuGet: Install-Package PdfSharp-MigraDoc-GDI
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Tables;
using MigraDoc.Rendering;
class Program
{
static void Main()
{
Document document = new Document();
Section section = document.AddSection();
Table table = section.AddTable();
table.Borders.Width = 0.75;
Column column1 = table.AddColumn("3cm");
Column column2 = table.AddColumn("3cm");
Row row1 = table.AddRow();
row1.Cells[0].AddParagraph("Name");
row1.Cells[1].AddParagraph("Age");
Row row2 = table.AddRow();
row2.Cells[0].AddParagraph("John");
row2.Cells[1].AddParagraph("30");
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("table.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string htmlTable = @"
<table border='1'>
<tr><th>Name</th><th>Age</th></tr>
<tr><td>John</td><td>30</td></tr>
</table>";
var pdf = renderer.RenderHtmlAsPdf(htmlTable);
pdf.SaveAs("table.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string htmlTable = @"
<table border='1'>
<tr><th>Name</th><th>Age</th></tr>
<tr><td>John</td><td>30</td></tr>
</table>";
var pdf = renderer.RenderHtmlAsPdf(htmlTable);
pdf.SaveAs("table.pdf");
}
}The MigraDoc table creation requires understanding the Table, Column, Row, and Cell hierarchy. You must explicitly add columns with AddColumn(), create rows with AddRow(), access cells by index with Cells[n], and add content with AddParagraph(). The border is set via table.Borders.Width.
IronPDF uses standard HTML table syntax that any web developer knows. The border='1' attribute provides the border, <th> elements create header cells, and <td> elements create data cells. CSS can be added for advanced styling like zebra striping, hover effects, or responsive layouts. Learn more about creating tables in PDFs.
Example 3: Headers and Footers with Page Numbers
Before (MigraDoc):
// NuGet: Install-Package PdfSharp-MigraDoc-GDI
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
class Program
{
static void Main()
{
Document document = new Document();
Section section = document.AddSection();
// Add header
Paragraph headerPara = section.Headers.Primary.AddParagraph();
headerPara.AddText("Document Header");
headerPara.Format.Font.Size = 12;
headerPara.Format.Alignment = ParagraphAlignment.Center;
// Add footer
Paragraph footerPara = section.Footers.Primary.AddParagraph();
footerPara.AddText("Page ");
footerPara.AddPageField();
footerPara.Format.Alignment = ParagraphAlignment.Center;
// Add content
section.AddParagraph("Main content of the document");
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("header-footer.pdf");
}
}// NuGet: Install-Package PdfSharp-MigraDoc-GDI
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
class Program
{
static void Main()
{
Document document = new Document();
Section section = document.AddSection();
// Add header
Paragraph headerPara = section.Headers.Primary.AddParagraph();
headerPara.AddText("Document Header");
headerPara.Format.Font.Size = 12;
headerPara.Format.Alignment = ParagraphAlignment.Center;
// Add footer
Paragraph footerPara = section.Footers.Primary.AddParagraph();
footerPara.AddText("Page ");
footerPara.AddPageField();
footerPara.Format.Alignment = ParagraphAlignment.Center;
// Add content
section.AddParagraph("Main content of the document");
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("header-footer.pdf");
}
}After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Main content of the document</h1>");
pdf.AddTextHeader("Document Header");
pdf.AddTextFooter("Page {page}");
pdf.SaveAs("header-footer.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Main content of the document</h1>");
pdf.AddTextHeader("Document Header");
pdf.AddTextFooter("Page {page}");
pdf.SaveAs("header-footer.pdf");
}
}MigraDoc headers and footers require accessing section.Headers.Primary and section.Footers.Primary, creating paragraphs within them, adding text with AddText(), and using special methods like AddPageField() for dynamic content. Alignment requires setting Format.Alignment.
IronPDF provides simple AddTextHeader() and AddTextFooter() methods on the PdfDocument object. The {page} placeholder automatically inserts the current page number. For more complex headers, you can use HtmlHeaderFooter with full HTML/CSS support. See the headers and footers documentation for advanced options.
Critical Migration Notes
Page Number Placeholder Syntax
The most important change for headers and footers is the placeholder syntax:
// MigraDoc field methods:
footerPara.AddPageField(); // Current page
footerPara.AddNumPagesField(); // Total pages
// IronPDF placeholders:
"Page {page} of {total-pages}"// MigraDoc field methods:
footerPara.AddPageField(); // Current page
footerPara.AddNumPagesField(); // Total pages
// IronPDF placeholders:
"Page {page} of {total-pages}"Format Properties to CSS
MigraDoc's Format properties map to CSS:
// MigraDoc:
paragraph.Format.Font.Size = 16;
paragraph.Format.Font.Bold = true;
paragraph.Format.Alignment = ParagraphAlignment.Center;
// IronPDF (CSS):
<p style="font-size: 16pt; font-weight: bold; text-align: center;">// MigraDoc:
paragraph.Format.Font.Size = 16;
paragraph.Format.Font.Bold = true;
paragraph.Format.Alignment = ParagraphAlignment.Center;
// IronPDF (CSS):
<p style="font-size: 16pt; font-weight: bold; text-align: center;">Unit Conversion
MigraDoc uses various units; IronPDF margins use millimeters:
- "1cm" = 10mm
- "1in" = 25.4mm
- "72pt" = 25.4mm
// MigraDoc:
table.AddColumn("3cm");
// IronPDF (CSS):
<th style="width: 3cm;">// MigraDoc:
table.AddColumn("3cm");
// IronPDF (CSS):
<th style="width: 3cm;">Rendering Pattern Change
The entire rendering pattern changes:
// MigraDoc pattern (DELETE):
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("output.pdf");
// IronPDF pattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");// MigraDoc pattern (DELETE):
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
pdfRenderer.PdfDocument.Save("output.pdf");
// IronPDF pattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");Troubleshooting
Issue 1: Document/Section Not Found
Problem: Document and Section classes don't exist in IronPDF.
Solution: Replace with HTML structure:
// MigraDoc
Document document = new Document();
Section section = document.AddSection();
// IronPDF
string html = "<html><body>...</body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);// MigraDoc
Document document = new Document();
Section section = document.AddSection();
// IronPDF
string html = "<html><body>...</body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);Issue 2: AddParagraph Not Found
Problem: AddParagraph() method doesn't exist.
Solution: Use HTML elements:
// MigraDoc
section.AddParagraph("Hello World");
// IronPDF
"<p>Hello World</p>"// MigraDoc
section.AddParagraph("Hello World");
// IronPDF
"<p>Hello World</p>"Issue 3: PdfDocumentRenderer Not Found
Problem: PdfDocumentRenderer class doesn't exist.
Solution: Use ChromePdfRenderer:
// MigraDoc
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
// IronPDF
var renderer = new ChromePdfRenderer();// MigraDoc
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
// IronPDF
var renderer = new ChromePdfRenderer();Issue 4: AddPageField Not Working
Problem: AddPageField() method doesn't exist.
Solution: Use IronPDF placeholder syntax:
// MigraDoc
footerPara.AddPageField();
// IronPDF
pdf.AddTextFooter("Page {page}");// MigraDoc
footerPara.AddPageField();
// IronPDF
pdf.AddTextFooter("Page {page}");Migration Checklist
Pre-Migration
- Identify all MigraDoc
usingstatements - Document table structures (columns, rows, styling)
- Note header/footer content and page field usage
- List custom styles defined with
document.Styles - Obtain IronPDF license key
Package Changes
- Remove
PdfSharp-MigraDocpackage - Remove
PdfSharp-MigraDoc-GDIpackage - Install
IronPdfNuGet package:dotnet add package IronPdf - Update namespace imports
Code Changes
- Add license key configuration at startup
- Replace
Document/Sectionwith HTML structure - Convert
AddParagraph()to HTML<p>elements - Convert
Table/Row/Cellto HTML<table>structure - Replace
AddPageField()with{page}placeholder - Replace
AddNumPagesField()with{total-pages}placeholder - Convert
Formatproperties to CSS styles - Replace
PdfDocumentRendererwithChromePdfRenderer
Testing
- Compare visual output between old and new PDFs
- Verify page breaks work correctly
- Check header/footer rendering and page numbers
- Validate table formatting and borders
- Test with complex multi-page documents
Post-Migration
- Remove MigraDoc-related documentation
- Update team training materials
- Document new HTML template locations






