Skip to footer content
MIGRATION GUIDES

How to Migrate from fo.net to IronPDF

Migrating from fo.net (FO.NET) to IronPDF is a major update for your .NET PDF generation process. This guide offers a straightforward, step-by-step path to transition your codebase from outdated XSL-FO markup to modern HTML/CSS-based PDF generation, using skills your development team already has.

Why Migrate from fo.net to IronPDF

The fo.net Challenges

fo.net is an XSL-FO to PDF renderer with several limitations for current development:

  1. Outdated Technology: XSL-FO (Extensible Stylesheet Language Formatting Objects) is a W3C specification from 2001, with no updates since 2006, and is largely considered outdated.

  2. Complex Learning Curve: XSL-FO requires learning intricate XML-based markup with specialized formatting objects (fo:block, fo:table, fo:page-sequence, etc.).

  3. No HTML/CSS Support: fo.net cannot render HTML or CSS—it requires manual conversion from HTML to XSL-FO markup.

  4. Unmaintained: The original CodePlex repository is defunct; GitHub forks are no longer actively maintained.

  5. Windows-Only: fo.net has internal dependencies on System.Drawing that prevent it from working on Linux/macOS.

  6. Limited Modern Features: No JavaScript support, no CSS3, no flexbox/grid, no modern web fonts.

  7. No URL Rendering: fo.net cannot directly render web pages—requires manual HTML-to-XSL-FO conversion.

fo.net vs IronPDF Comparison

Aspectfo.net (FO.NET)IronPDF
Input FormatXSL-FO (outdated XML)HTML/CSS (modern web standards)
Learning CurveSteep (XSL-FO expertise)Gentle (HTML/CSS knowledge)
MaintenanceUnmaintainedActively maintained monthly
Platform SupportWindows onlyTrue cross-platform (.NET 6/7/8/9/10+)
CSS SupportNoneFull CSS3 (Flexbox, Grid)
JavaScriptNoneFull JavaScript support
URL RenderingNot supportedBuilt-in
Modern FeaturesLimitedHeaders, footers, watermarks, security
DocumentationOutdatedThorough tutorials

Why the Switch Makes Sense

fo.net was designed when XSL-FO was expected to become a standard for document formatting. That expectation never materialized. HTML/CSS became the universal document format, with over 98% of developers knowing HTML/CSS compared to less than 1% knowing XSL-FO. Most XSL-FO resources date from 2005-2010, making maintenance increasingly difficult.

IronPDF lets you use the skills you already have to create professional PDFs, with full support for modern .NET versions including .NET 10 and C# 14 as they become available through 2025 and into 2026.


Before You Start

Prerequisites

  1. .NET Environment: IronPDF supports .NET Framework 4.6.2+, .NET Core 3.1+, .NET 5/6/7/8/9+
  2. NuGet Access: Ensure you can install packages from NuGet
  3. License Key: Obtain your IronPDF license key for production use from ironpdf.com

Backup Your Project

# Create a backup branch
git checkout -b pre-ironpdf-migration
git add .
git commit -m "Backup before fo.net to IronPDF migration"
# Create a backup branch
git checkout -b pre-ironpdf-migration
git add .
git commit -m "Backup before fo.net to IronPDF migration"
SHELL

Identify All fo.net Usage

# Find all fo.net references
grep -r "FonetDriver\|Fonet\|\.fo\"\|xsl-region" --include="*.cs" --include="*.csproj" .

# Find all XSL-FO template files
find . -name "*.fo" -o -name "*.xslfo" -o -name "*xsl-fo*"
# Find all fo.net references
grep -r "FonetDriver\|Fonet\|\.fo\"\|xsl-region" --include="*.cs" --include="*.csproj" .

# Find all XSL-FO template files
find . -name "*.fo" -o -name "*.xslfo" -o -name "*xsl-fo*"
SHELL

Document Your XSL-FO Templates

Before migration, catalog all XSL-FO files and note:

  • Page dimensions and margins
  • Fonts used
  • Tables and their structures
  • Headers and footers (fo:static-content)
  • Page numbering patterns
  • Image references

Quick Start Migration

Step 1: Update NuGet Packages

# Remove fo.net package
dotnet remove package Fonet
dotnet remove package FO.NET

# Install IronPDF
dotnet add package IronPdf
# Remove fo.net package
dotnet remove package Fonet
dotnet remove package FO.NET

# Install IronPDF
dotnet add package IronPdf
SHELL

Step 2: Update Namespaces

// Before (fo.net)
using Fonet;
using Fonet.Render.Pdf;
using System.Xml;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
// Before (fo.net)
using Fonet;
using Fonet.Render.Pdf;
using System.Xml;

// After (IronPDF)
using IronPdf;
using IronPdf.Rendering;
$vbLabelText   $csharpLabel

Step 3: Initialize IronPDF

// Set license key at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Set license key at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

Step 4: Basic Conversion Pattern

// Before (fo.net with XSL-FO)
FonetDriver driver = FonetDriver.Make();
using (FileStream output = new FileStream("output.pdf", FileMode.Create))
{
    driver.Render(new StringReader(xslFoContent), output);
}

// After (IronPDF with HTML)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
// Before (fo.net with XSL-FO)
FonetDriver driver = FonetDriver.Make();
using (FileStream output = new FileStream("output.pdf", FileMode.Create))
{
    driver.Render(new StringReader(xslFoContent), output);
}

// After (IronPDF with HTML)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
$vbLabelText   $csharpLabel

Complete API Reference

Namespace Mapping

fo.net NamespaceIronPDF EquivalentNotes
FonetIronPdfMain namespace
Fonet.Render.PdfIronPdfPDF rendering
Fonet.LayoutN/ALayout handled by CSS
Fonet.FoN/AFormatting Objects → HTML
Fonet.ImageIronPdfImage handling built-in

FonetDriver to ChromePdfRenderer

FonetDriver MethodIronPDF EquivalentNotes
FonetDriver.Make()new ChromePdfRenderer()Create renderer
driver.Render(inputStream, outputStream)renderer.RenderHtmlAsPdf(html)Stream-based
driver.Render(inputFile, outputStream)renderer.RenderHtmlFileAsPdf(path)File-based
driver.BaseDirectoryRenderingOptions.BaseUrlBase path for resources
driver.OnError += handlerTry/catch around renderError handling

RenderingOptions (PDF Configuration)

fo.net (XSL-FO Attributes)IronPDF RenderingOptionsNotes
page-heightPaperSize or SetCustomPaperSize()Page dimensions
page-widthPaperSizeStandard or custom
margin-topMarginTopIn millimeters
margin-bottomMarginBottomIn millimeters
margin-leftMarginLeftIn millimeters
margin-rightMarginRightIn millimeters
reference-orientationPaperOrientationPortrait/Landscape

XSL-FO to HTML Conversion Guide

XSL-FO Elements to HTML/CSS

The fundamental shift in this fo.net migration is converting XSL-FO elements to their HTML equivalents:

XSL-FO ElementHTML/CSS EquivalentNotes
<fo:root><html>Root element
<fo:layout-master-set>CSS @page rulePage setup
<fo:simple-page-master>CSS @pagePage definition
<fo:page-sequence><body> or <div>Page content
<fo:flow><main> or <div>Main content area
<fo:static-content>HtmlHeaderFooterHeaders/footers
<fo:block><p>, <div>, <h1>-<h6>Block content
<fo:inline><span>Inline content
<fo:table><table>Tables
<fo:table-row><tr>Table rows
<fo:table-cell><td>, <th>Table cells
<fo:list-block><ul>, <ol>Lists
<fo:list-item><li>List items
<fo:external-graphic><img>Images
<fo:page-number>{page} placeholderPage numbers
<fo:page-number-citation>{total-pages}Total pages
<fo:basic-link><a href>Hyperlinks

XSL-FO Properties to CSS

XSL-FO PropertyCSS EquivalentExample
font-familyfont-familySame syntax
font-sizefont-sizeSame syntax
font-weightfont-weightbold, normal, 700
text-aligntext-alignleft, center, right, justify
colorcolorHex, RGB, names
background-colorbackground-colorSame syntax
space-beforemargin-topBefore element
space-aftermargin-bottomAfter element
start-indentmargin-leftLeft indent
keep-togetherpage-break-inside: avoidPrevent breaks
break-before="page"page-break-before: alwaysForce page break

Code Examples

Example 1: Basic HTML to PDF

Before (fo.net with XSL-FO):

// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
using System.Xml;

class Program
{
    static void Main()
    {
        // fo.net requires XSL-FO format, not HTML
        // First convert HTML to XSL-FO (manual process)
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='page'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='page'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block>Hello World</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("output.pdf", FileMode.Create));
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
using System.Xml;

class Program
{
    static void Main()
    {
        // fo.net requires XSL-FO format, not HTML
        // First convert HTML to XSL-FO (manual process)
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='page'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='page'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block>Hello World</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("output.pdf", FileMode.Create));
    }
}
$vbLabelText   $csharpLabel

After (IronPDF with HTML):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        string html = "<h1>Hello World</h1><p>This is HTML content.</p>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        string html = "<h1>Hello World</h1><p>This is HTML content.</p>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("output.pdf");
    }
}
$vbLabelText   $csharpLabel

The IronPDF approach reduces 25+ lines of XSL-FO markup to just 4 lines of clean C# code. For more HTML to PDF options, see the IronPDF HTML to PDF documentation.

Example 2: PDF with Custom Settings

Before (fo.net with XSL-FO):

// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;

class Program
{
    static void Main()
    {
        // fo.net settings are configured in XSL-FO markup
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='A4' 
                        page-height='297mm' page-width='210mm'
                        margin-top='20mm' margin-bottom='20mm'
                        margin-left='25mm' margin-right='25mm'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='A4'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block font-size='14pt'>Custom PDF</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("custom.pdf", FileMode.Create));
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;

class Program
{
    static void Main()
    {
        // fo.net settings are configured in XSL-FO markup
        string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
            <fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
                <fo:layout-master-set>
                    <fo:simple-page-master master-name='A4' 
                        page-height='297mm' page-width='210mm'
                        margin-top='20mm' margin-bottom='20mm'
                        margin-left='25mm' margin-right='25mm'>
                        <fo:region-body/>
                    </fo:simple-page-master>
                </fo:layout-master-set>
                <fo:page-sequence master-reference='A4'>
                    <fo:flow flow-name='xsl-region-body'>
                        <fo:block font-size='14pt'>Custom PDF</fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </fo:root>";

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("custom.pdf", FileMode.Create));
    }
}
$vbLabelText   $csharpLabel

After (IronPDF with HTML):

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.MarginLeft = 25;
        renderer.RenderingOptions.MarginRight = 25;

        string html = "<h1 style='font-size:14pt'>Custom PDF</h1>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("custom.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.MarginLeft = 25;
        renderer.RenderingOptions.MarginRight = 25;

        string html = "<h1 style='font-size:14pt'>Custom PDF</h1>";
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("custom.pdf");
    }
}
$vbLabelText   $csharpLabel

IronPDF provides programmatic rendering options instead of embedding configuration in XML markup.

Example 3: URL to PDF

Before (fo.net - not supported):

// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;

class Program
{
    static void Main()
    {
        // fo.net does not support URL rendering directly
        // Must manually download, convert HTML to XSL-FO, then render
        string url = "https://example.com";
        string html = new WebClient().DownloadString(url);

        // Manual conversion from HTML to XSL-FO required (complex)
        string xslFo = ConvertHtmlToXslFo(html); // Not built-in

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("webpage.pdf", FileMode.Create));
    }

    static string ConvertHtmlToXslFo(string html)
    {
        // Custom implementation required - extremely complex
        throw new System.NotImplementedException();
    }
}
// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;

class Program
{
    static void Main()
    {
        // fo.net does not support URL rendering directly
        // Must manually download, convert HTML to XSL-FO, then render
        string url = "https://example.com";
        string html = new WebClient().DownloadString(url);

        // Manual conversion from HTML to XSL-FO required (complex)
        string xslFo = ConvertHtmlToXslFo(html); // Not built-in

        FonetDriver driver = FonetDriver.Make();
        driver.Render(new StringReader(xslFo), 
            new FileStream("webpage.pdf", FileMode.Create));
    }

    static string ConvertHtmlToXslFo(string html)
    {
        // Custom implementation required - extremely complex
        throw new System.NotImplementedException();
    }
}
$vbLabelText   $csharpLabel

After (IronPDF - built-in support):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
$vbLabelText   $csharpLabel

URL to PDF rendering is one of the most significant advantages in this fo.net migration. IronPDF handles this natively with full JavaScript execution. Learn more about URL to PDF conversion.

Example 4: Headers and Footers

Before (fo.net with XSL-FO):

<fo:static-content flow-name="xsl-region-before">
    <fo:block text-align="center" font-size="10pt">
        Company Name - Confidential
    </fo:block>
</fo:static-content>

<fo:static-content flow-name="xsl-region-after">
    <fo:block text-align="right" font-size="10pt">
        Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
    </fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-before">
    <fo:block text-align="center" font-size="10pt">
        Company Name - Confidential
    </fo:block>
</fo:static-content>

<fo:static-content flow-name="xsl-region-after">
    <fo:block text-align="right" font-size="10pt">
        Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
    </fo:block>
</fo:static-content>
XML

After (IronPDF):

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center; font-size:10pt;'>Company Name - Confidential</div>",
    DrawDividerLine = true
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Page {page} of {total-pages}</div>",
    DrawDividerLine = true
};
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center; font-size:10pt;'>Company Name - Confidential</div>",
    DrawDividerLine = true
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Page {page} of {total-pages}</div>",
    DrawDividerLine = true
};
$vbLabelText   $csharpLabel

IronPDF replaces complex XSL-FO region definitions with simple HTML headers and footers.

Example 5: PDF Security

Before (fo.net):

// fo.net has very limited PDF security options
// Must use post-processing with another library
// fo.net has very limited PDF security options
// Must use post-processing with another library
$vbLabelText   $csharpLabel

After (IronPDF):

using IronPdf;

public byte[] GenerateSecurePdf(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(html);

    // Set metadata
    pdf.MetaData.Title = "Confidential Report";
    pdf.MetaData.Author = "Company Name";

    // Password protection
    pdf.SecuritySettings.OwnerPassword = "owner123";
    pdf.SecuritySettings.UserPassword = "user456";

    // Restrict permissions
    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
    pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.NoEdit;

    return pdf.BinaryData;
}
using IronPdf;

public byte[] GenerateSecurePdf(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(html);

    // Set metadata
    pdf.MetaData.Title = "Confidential Report";
    pdf.MetaData.Author = "Company Name";

    // Password protection
    pdf.SecuritySettings.OwnerPassword = "owner123";
    pdf.SecuritySettings.UserPassword = "user456";

    // Restrict permissions
    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
    pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.NoEdit;

    return pdf.BinaryData;
}
$vbLabelText   $csharpLabel

Performance Considerations

Reuse ChromePdfRenderer

For optimal performance during your fo.net migration, reuse the ChromePdfRenderer instance:

// GOOD - Reuse the renderer
public class PdfService
{
    private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

    public byte[] Generate(string html) => _renderer.RenderHtmlAsPdf(html).BinaryData;
}

// BAD - Creating new instance each time
public byte[] GenerateBad(string html)
{
    var renderer = new ChromePdfRenderer();  // Wasteful
    return renderer.RenderHtmlAsPdf(html).BinaryData;
}
// GOOD - Reuse the renderer
public class PdfService
{
    private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

    public byte[] Generate(string html) => _renderer.RenderHtmlAsPdf(html).BinaryData;
}

// BAD - Creating new instance each time
public byte[] GenerateBad(string html)
{
    var renderer = new ChromePdfRenderer();  // Wasteful
    return renderer.RenderHtmlAsPdf(html).BinaryData;
}
$vbLabelText   $csharpLabel

Unit Conversion Helper

fo.net XSL-FO uses various units. IronPDF uses millimeters for margins. Here's a helper class:

public static class UnitConverter
{
    public static double InchesToMm(double inches) => inches * 25.4;
    public static double PointsToMm(double points) => points * 0.352778;
    public static double PicasToMm(double picas) => picas * 4.233;
    public static double CmToMm(double cm) => cm * 10;
}

// Usage
renderer.RenderingOptions.MarginTop = UnitConverter.InchesToMm(1);  // 1 inch
public static class UnitConverter
{
    public static double InchesToMm(double inches) => inches * 25.4;
    public static double PointsToMm(double points) => points * 0.352778;
    public static double PicasToMm(double picas) => picas * 4.233;
    public static double CmToMm(double cm) => cm * 10;
}

// Usage
renderer.RenderingOptions.MarginTop = UnitConverter.InchesToMm(1);  // 1 inch
$vbLabelText   $csharpLabel

Troubleshooting

Issue 1: Page Size Differences

Problem: PDF page size looks different after fo.net migration.

Solution: Map XSL-FO page dimensions correctly:

// XSL-FO: page-height='11in' page-width='8.5in' (Letter)
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;

// XSL-FO: page-height='297mm' page-width='210mm' (A4)
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;

// Custom size (in mm)
renderer.RenderingOptions.SetCustomPaperSize(210, 297);
// XSL-FO: page-height='11in' page-width='8.5in' (Letter)
renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter;

// XSL-FO: page-height='297mm' page-width='210mm' (A4)
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;

// Custom size (in mm)
renderer.RenderingOptions.SetCustomPaperSize(210, 297);
$vbLabelText   $csharpLabel

Issue 2: fo:block to HTML Mapping

Problem: Not sure what <fo:block> should become.

Solution: Use appropriate semantic HTML:

  • Headings: <h1> through <h6>
  • Paragraphs: <p>
  • Generic containers: <div>
  • Inline text: <span>

Issue 3: Fonts Not Matching

Problem: Fonts look different from fo.net output.

Solution: Use web fonts or specify system fonts in CSS:

<style>
    @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
    body { font-family: 'Roboto', Arial, sans-serif; }
</style>
<style>
    @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
    body { font-family: 'Roboto', Arial, sans-serif; }
</style>
HTML

Issue 4: Page Numbers Not Working

Problem: <fo:page-number/> doesn't work.

Solution: Use IronPDF placeholders in headers/footers:

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
    MaxHeight = 15  // mm
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
    HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
    MaxHeight = 15  // mm
};
$vbLabelText   $csharpLabel

Migration Checklist

Pre-Migration

  • Catalog all XSL-FO template files (.fo, .xslfo)
  • Document page dimensions and margins used
  • Note header/footer configurations (fo:static-content)
  • Identify table structures and styling
  • Backup project to version control
  • Obtain IronPDF license key

Package Migration

  • Remove Fonet or FO.NET package: dotnet remove package Fonet
  • Install IronPdf package: dotnet add package IronPdf
  • Update namespace imports from Fonet to IronPdf
  • Set IronPDF license key at startup

Code Migration

  • Replace FonetDriver.Make() with new ChromePdfRenderer()
  • Replace driver.Render() with renderer.RenderHtmlAsPdf()
  • Update file output from streams to pdf.SaveAs()
  • Replace error event handlers with try/catch
  • Convert fo:static-content to HtmlHeaderFooter
  • Replace <fo:page-number/> with {page} placeholder

Testing

  • Compare output appearance to original fo.net PDFs
  • Verify page dimensions and margins
  • Check headers and footers
  • Validate page numbers
  • Test table rendering
  • Verify image loading

Post-Migration

  • Delete .fo and .xslfo template files
  • Remove fo.net-related code and utilities
  • Update documentation

reference](https://ironpdf.com/object-reference/api/).

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