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:
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.
Complex Learning Curve: XSL-FO requires learning intricate XML-based markup with specialized formatting objects (
fo:block,fo:table,fo:page-sequence, etc.).No HTML/CSS Support: fo.net cannot render HTML or CSS—it requires manual conversion from HTML to XSL-FO markup.
Unmaintained: The original CodePlex repository is defunct; GitHub forks are no longer actively maintained.
Windows-Only: fo.net has internal dependencies on
System.Drawingthat prevent it from working on Linux/macOS.Limited Modern Features: No JavaScript support, no CSS3, no flexbox/grid, no modern web fonts.
- No URL Rendering: fo.net cannot directly render web pages—requires manual HTML-to-XSL-FO conversion.
fo.net vs IronPDF Comparison
| Aspect | fo.net (FO.NET) | IronPDF |
|---|---|---|
| Input Format | XSL-FO (outdated XML) | HTML/CSS (modern web standards) |
| Learning Curve | Steep (XSL-FO expertise) | Gentle (HTML/CSS knowledge) |
| Maintenance | Unmaintained | Actively maintained monthly |
| Platform Support | Windows only | True cross-platform (.NET 6/7/8/9/10+) |
| CSS Support | None | Full CSS3 (Flexbox, Grid) |
| JavaScript | None | Full JavaScript support |
| URL Rendering | Not supported | Built-in |
| Modern Features | Limited | Headers, footers, watermarks, security |
| Documentation | Outdated | Thorough 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
- .NET Environment: IronPDF supports .NET Framework 4.6.2+, .NET Core 3.1+, .NET 5/6/7/8/9+
- NuGet Access: Ensure you can install packages from NuGet
- 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"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*"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 IronPdfStep 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;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";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");Complete API Reference
Namespace Mapping
| fo.net Namespace | IronPDF Equivalent | Notes |
|---|---|---|
Fonet | IronPdf | Main namespace |
Fonet.Render.Pdf | IronPdf | PDF rendering |
Fonet.Layout | N/A | Layout handled by CSS |
Fonet.Fo | N/A | Formatting Objects → HTML |
Fonet.Image | IronPdf | Image handling built-in |
FonetDriver to ChromePdfRenderer
| FonetDriver Method | IronPDF Equivalent | Notes |
|---|---|---|
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.BaseDirectory | RenderingOptions.BaseUrl | Base path for resources |
driver.OnError += handler | Try/catch around render | Error handling |
RenderingOptions (PDF Configuration)
| fo.net (XSL-FO Attributes) | IronPDF RenderingOptions | Notes |
|---|---|---|
page-height | PaperSize or SetCustomPaperSize() | Page dimensions |
page-width | PaperSize | Standard or custom |
margin-top | MarginTop | In millimeters |
margin-bottom | MarginBottom | In millimeters |
margin-left | MarginLeft | In millimeters |
margin-right | MarginRight | In millimeters |
reference-orientation | PaperOrientation | Portrait/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 Element | HTML/CSS Equivalent | Notes |
|---|---|---|
<fo:root> | <html> | Root element |
<fo:layout-master-set> | CSS @page rule | Page setup |
<fo:simple-page-master> | CSS @page | Page definition |
<fo:page-sequence> | <body> or <div> | Page content |
<fo:flow> | <main> or <div> | Main content area |
<fo:static-content> | HtmlHeaderFooter | Headers/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} placeholder | Page numbers |
<fo:page-number-citation> | {total-pages} | Total pages |
<fo:basic-link> | <a href> | Hyperlinks |
XSL-FO Properties to CSS
| XSL-FO Property | CSS Equivalent | Example |
|---|---|---|
font-family | font-family | Same syntax |
font-size | font-size | Same syntax |
font-weight | font-weight | bold, normal, 700 |
text-align | text-align | left, center, right, justify |
color | color | Hex, RGB, names |
background-color | background-color | Same syntax |
space-before | margin-top | Before element |
space-after | margin-bottom | After element |
start-indent | margin-left | Left indent |
keep-together | page-break-inside: avoid | Prevent breaks |
break-before="page" | page-break-before: always | Force 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));
}
}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");
}
}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));
}
}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");
}
}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();
}
}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");
}
}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>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
};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 libraryAfter (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;
}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;
}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 inchpublic 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 inchTroubleshooting
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);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>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
};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
FonetorFO.NETpackage:dotnet remove package Fonet - Install
IronPdfpackage:dotnet add package IronPdf - Update namespace imports from
FonettoIronPdf - Set IronPDF license key at startup
Code Migration
- Replace
FonetDriver.Make()withnew ChromePdfRenderer() - Replace
driver.Render()withrenderer.RenderHtmlAsPdf() - Update file output from streams to
pdf.SaveAs() - Replace error event handlers with try/catch
- Convert
fo:static-contenttoHtmlHeaderFooter - 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
.foand.xslfotemplate files - Remove fo.net-related code and utilities
- Update documentation
reference](https://ironpdf.com/object-reference/api/).






