Skip to footer content
MIGRATION GUIDES

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:

  1. No HTML Support: MigraDoc doesn't support HTML directly. You must manually construct documents element-by-element using Document, Section, Paragraph, and Table objects—you cannot leverage existing HTML/CSS designs.

  2. Proprietary Document Model: MigraDoc requires learning a unique document model with concepts like AddSection(), AddParagraph(), AddTable(), AddRow(), and AddCell(). This steep learning curve is particularly challenging for developers with web development backgrounds.

  3. 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, and Format.Alignment are limited compared to full CSS3.

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

  5. No JavaScript Support: MigraDoc cannot render dynamic content or execute JavaScript, limiting options for modern charting and interactive elements.

  6. Charts Are Basic: MigraDoc's chart functionality is limited compared to modern JavaScript charting libraries like Chart.js or D3.

MigraDoc vs IronPDF Comparison

FeatureMigraDocIronPDF
Content DefinitionProgrammatic (Document/Section/Paragraph)HTML/CSS
Learning CurveSteep (proprietary DOM)Easy (web skills)
StylingLimited propertiesFull CSS3
JavaScriptNoneFull Chromium execution
TablesManual column/row definitionHTML <table> with CSS
ChartsBasic MigraDoc chartsAny JavaScript charting library
ImagesManual sizing/positioningStandard HTML <img>
Responsive LayoutsNot supportedFlexbox, Grid
LicenseOpen 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

FeatureMigration ComplexityNotes
Simple TextVery LowParagraph → HTML elements
TablesLowTable/Row/Cell → HTML <table>
Headers/FootersLowSection.Headers → RenderingOptions
StylesMediumFormat properties → CSS classes
ImagesLowAddImage → HTML <img>
ChartsMediumRequires 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

  1. .NET Environment: .NET Framework 4.6.2+ or .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. NuGet Access: Ability to install NuGet packages
  3. 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 IronPdf
SHELL

License 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";
$vbLabelText   $csharpLabel

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" .
SHELL

Complete API Reference

Class Mappings

MigraDoc ClassIronPDF EquivalentNotes
DocumentChromePdfRendererUse renderer, not document
SectionHTML <body> or <div>Structural container
ParagraphHTML <p>, <h1>, etc.Text elements
FormattedTextHTML <span>, <strong>, etc.Inline formatting
TableHTML <table>With CSS styling
RowHTML <tr>Table row
ColumnHTML <col> or CSSColumn styling
CellHTML <td>, <th>Table cell
PdfDocumentRendererChromePdfRendererMain renderer

Method Mappings

MigraDoc MethodIronPDF EquivalentNotes
document.AddSection()HTML structureUse <div> or <section>
section.AddParagraph(text)<p>text</p>HTML paragraph
section.AddTable()<table>HTML table
table.AddColumn(width)CSS width propertyStyle 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 MethodIronPDF PlaceholderNotes
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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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");
    }
}
$vbLabelText   $csharpLabel

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}"
$vbLabelText   $csharpLabel

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;">
$vbLabelText   $csharpLabel

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;">
$vbLabelText   $csharpLabel

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");
$vbLabelText   $csharpLabel

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);
$vbLabelText   $csharpLabel

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>"
$vbLabelText   $csharpLabel

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();
$vbLabelText   $csharpLabel

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}");
$vbLabelText   $csharpLabel

Migration Checklist

Pre-Migration

  • Identify all MigraDoc using statements
  • 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-MigraDoc package
  • Remove PdfSharp-MigraDoc-GDI package
  • Install IronPdf NuGet package: dotnet add package IronPdf
  • Update namespace imports

Code Changes

  • Add license key configuration at startup
  • Replace Document/Section with HTML structure
  • Convert AddParagraph() to HTML <p> elements
  • Convert Table/Row/Cell to HTML <table> structure
  • Replace AddPageField() with {page} placeholder
  • Replace AddNumPagesField() with {total-pages} placeholder
  • Convert Format properties to CSS styles
  • Replace PdfDocumentRenderer with ChromePdfRenderer

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

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More