How to Migrate from TextControl to IronPDF in C#
TX Text Control has established itself as a comprehensive document editor component in the .NET ecosystem, offering robust DOCX editing capabilities with embedded UI controls. However, for development teams whose primary requirement is PDF generation rather than full document editing, TextControl's architecture presents significant overhead in licensing costs, complexity, and runtime dependencies.
This guide provides a complete migration path from TextControl to IronPDF, with step-by-step instructions, code comparisons, and practical examples for professional .NET developers evaluating this transition.
Why Migrate from TextControl
The decision to migrate from TextControl typically centers on matching your tooling to your actual requirements. TX Text Control is fundamentally a document editor that treats PDF generation as a secondary feature. Key reasons development teams consider migration include:
Expensive Licensing: TextControl operates on a commercial license at a minimum of $3,398 per year per developer. A team of four can expect to invest around $6,749 per year, with additional costs for server deployment runtime licenses. Renewal costs stand at 40% annually, which is mandatory for maintaining access to updates.
PDF as Afterthought: The core architecture is word processing, not PDF. While PDF generation is available, it's more of an added feature rather than the core focus, resulting in less than optimal output quality.
Hardware Bugs: The Intel Iris Xe Graphics bug affects document rendering in newer Intel processors (11th generation), requiring a registry workaround to resolve.
Bloated Dependencies: TextControl includes document editing UI components that you may not need if your focus is purely PDF generation.
Word-Processor Architecture: Not optimized for HTML-to-PDF workflows that modern web applications demand.
Complex API: The ServerTextControl context management and selection model add unnecessary complexity for straightforward PDF generation tasks.
Cost Comparison
| Aspect | TX Text Control | IronPDF |
|---|---|---|
| Base License | $3,398+ | Significantly lower |
| Annual Renewal | 40% mandatory | Optional support |
| Per Developer | Yes | Yes |
| UI Components | Bundled (bloat) | PDF-focused |
| Total 3-Year Cost | $5,750+ | Much lower |
IronPDF vs TextControl: Feature Comparison
Understanding the architectural differences helps technical decision-makers evaluate the migration investment:
| Feature | TX Text Control | IronPDF |
|---|---|---|
| Primary Focus | DOCX editing | PDF generation |
| License Cost | $3,398/year per developer | $749 one-time per developer |
| PDF Quality | Basic, add-on feature | High, core functionality |
| Hardware Compatibility | Known issues with Intel Iris | Stable across all devices |
| Integration with UI | Requires UI components | No UI component bloat |
| HTML/CSS Rendering | Buggy with HTML | Modern HTML5/CSS3 |
| HTML to PDF | Yes (secondary) | Yes (primary) |
| CSS Support | Limited | Full CSS3 |
| JavaScript | Limited | Full ES2024 |
| URL to PDF | Complex setup | Native |
| Headers/Footers | Complex API | Simple HTML |
| Mail Merge | Proprietary | HTML templates |
| PDF/A | Yes | Yes |
| Password Protection | Yes | Yes |
| Digital Signatures | Yes | Yes |
| Merge PDFs | Limited | Yes |
| Split PDFs | Limited | Yes |
| Context Management | Required | Not needed |
| Cross-Platform | Windows-focused | Yes |
Quick Start: TextControl to IronPDF Migration
The migration can begin immediately with these foundational steps.
Step 1: Replace NuGet Packages
Remove all TextControl packages:
# Remove TX Text Control
dotnet remove package TXTextControl.TextControl
dotnet remove package TXTextControl.DocumentServer# Remove TX Text Control
dotnet remove package TXTextControl.TextControl
dotnet remove package TXTextControl.DocumentServerInstall IronPDF:
# Install IronPDF
dotnet add package IronPdf# Install IronPDF
dotnet add package IronPdfStep 2: Update Namespaces
Replace TextControl namespaces with the IronPdf namespace:
// Before (TextControl)
using TXTextControl;
using TXTextControl.DocumentServer;
// After (IronPDF)
using IronPdf;// Before (TextControl)
using TXTextControl;
using TXTextControl.DocumentServer;
// After (IronPDF)
using IronPdf;Imports TXTextControl
Imports TXTextControl.DocumentServer
' After (IronPDF)
Imports IronPdfStep 3: 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 common use case demonstrates the architectural difference between these .NET PDF libraries.
TextControl Approach:
// NuGet: Install-Package TXTextControl.Server
using TXTextControl;
using System.IO;
namespace TextControlExample
{
class Program
{
static void Main(string[] args)
{
using (ServerTextControl textControl = new ServerTextControl())
{
textControl.Create();
string html = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
textControl.Load(html, StreamType.HTMLFormat);
textControl.Save("output.pdf", StreamType.AdobePDF);
}
}
}
}// NuGet: Install-Package TXTextControl.Server
using TXTextControl;
using System.IO;
namespace TextControlExample
{
class Program
{
static void Main(string[] args)
{
using (ServerTextControl textControl = new ServerTextControl())
{
textControl.Create();
string html = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
textControl.Load(html, StreamType.HTMLFormat);
textControl.Save("output.pdf", StreamType.AdobePDF);
}
}
}
}Imports TXTextControl
Imports System.IO
Namespace TextControlExample
Class Program
Shared Sub Main(ByVal args As String())
Using textControl As New ServerTextControl()
textControl.Create()
Dim html As String = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
textControl.Load(html, StreamType.HTMLFormat)
textControl.Save("output.pdf", StreamType.AdobePDF)
End Using
End Sub
End Class
End NamespaceIronPDF Approach:
// NuGet: Install-Package IronPdf
using IronPdf;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
}// NuGet: Install-Package IronPdf
using IronPdf;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
}Imports IronPdf
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class
End NamespaceThe TextControl version requires creating a ServerTextControl instance, calling Create() to initialize the context, loading HTML with StreamType.HTMLFormat, and saving with StreamType.AdobePDF. The using block is mandatory for proper resource disposal.
IronPDF eliminates context management entirely. The ChromePdfRenderer requires no initialization ceremony—create it, render HTML, and save. This architectural simplification reduces cognitive load and potential resource management bugs.
For advanced HTML-to-PDF scenarios, see the HTML to PDF conversion guide.
Merging Multiple PDFs
PDF merging reveals another significant complexity difference between these libraries.
TextControl Approach:
// NuGet: Install-Package TXTextControl.Server
using TXTextControl;
using System.IO;
namespace TextControlExample
{
class Program
{
static void Main(string[] args)
{
using (ServerTextControl textControl = new ServerTextControl())
{
textControl.Create();
byte[] pdf1 = File.ReadAllBytes("document1.pdf");
textControl.Load(pdf1, StreamType.AdobePDF);
byte[] pdf2 = File.ReadAllBytes("document2.pdf");
textControl.Load(pdf2, StreamType.AdobePDF, LoadAppendMode.Append);
textControl.Save("merged.pdf", StreamType.AdobePDF);
}
}
}
}// NuGet: Install-Package TXTextControl.Server
using TXTextControl;
using System.IO;
namespace TextControlExample
{
class Program
{
static void Main(string[] args)
{
using (ServerTextControl textControl = new ServerTextControl())
{
textControl.Create();
byte[] pdf1 = File.ReadAllBytes("document1.pdf");
textControl.Load(pdf1, StreamType.AdobePDF);
byte[] pdf2 = File.ReadAllBytes("document2.pdf");
textControl.Load(pdf2, StreamType.AdobePDF, LoadAppendMode.Append);
textControl.Save("merged.pdf", StreamType.AdobePDF);
}
}
}
}Imports TXTextControl
Imports System.IO
Namespace TextControlExample
Class Program
Shared Sub Main(ByVal args As String())
Using textControl As New ServerTextControl()
textControl.Create()
Dim pdf1 As Byte() = File.ReadAllBytes("document1.pdf")
textControl.Load(pdf1, StreamType.AdobePDF)
Dim pdf2 As Byte() = File.ReadAllBytes("document2.pdf")
textControl.Load(pdf2, StreamType.AdobePDF, LoadAppendMode.Append)
textControl.Save("merged.pdf", StreamType.AdobePDF)
End Using
End Sub
End Class
End NamespaceIronPDF Approach:
// NuGet: Install-Package IronPdf
using IronPdf;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
}
}
}// NuGet: Install-Package IronPdf
using IronPdf;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
}
}
}Imports IronPdf
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim pdf1 = PdfDocument.FromFile("document1.pdf")
Dim pdf2 = PdfDocument.FromFile("document2.pdf")
Dim merged = PdfDocument.Merge(pdf1, pdf2)
merged.SaveAs("merged.pdf")
End Sub
End Class
End NamespaceTextControl requires reading files into byte arrays, managing the ServerTextControl context, and using LoadAppendMode.Append to merge documents. IronPDF's PdfDocument.Merge() method handles everything with a single, explicit call.
For advanced merging scenarios including selective page extraction, see the merge and split PDFs guide.
Adding Headers and Footers
Headers and footers with dynamic page numbers demonstrate the API complexity difference.
TextControl Approach:
// NuGet: Install-Package TXTextControl.Server
using TXTextControl;
using System.IO;
namespace TextControlExample
{
class Program
{
static void Main(string[] args)
{
using (ServerTextControl textControl = new ServerTextControl())
{
textControl.Create();
string html = "<html><body><h1>Document Content</h1><p>Main body text.</p></body></html>";
textControl.Load(html, StreamType.HTMLFormat);
HeaderFooter header = new HeaderFooter(HeaderFooterType.Header);
header.Text = "Document Header";
textControl.Sections[0].HeadersAndFooters.Add(header);
HeaderFooter footer = new HeaderFooter(HeaderFooterType.Footer);
footer.Text = "Page {page} of {numpages}";
textControl.Sections[0].HeadersAndFooters.Add(footer);
textControl.Save("output.pdf", StreamType.AdobePDF);
}
}
}
}// NuGet: Install-Package TXTextControl.Server
using TXTextControl;
using System.IO;
namespace TextControlExample
{
class Program
{
static void Main(string[] args)
{
using (ServerTextControl textControl = new ServerTextControl())
{
textControl.Create();
string html = "<html><body><h1>Document Content</h1><p>Main body text.</p></body></html>";
textControl.Load(html, StreamType.HTMLFormat);
HeaderFooter header = new HeaderFooter(HeaderFooterType.Header);
header.Text = "Document Header";
textControl.Sections[0].HeadersAndFooters.Add(header);
HeaderFooter footer = new HeaderFooter(HeaderFooterType.Footer);
footer.Text = "Page {page} of {numpages}";
textControl.Sections[0].HeadersAndFooters.Add(footer);
textControl.Save("output.pdf", StreamType.AdobePDF);
}
}
}
}Imports TXTextControl
Imports System.IO
Namespace TextControlExample
Class Program
Shared Sub Main(ByVal args As String())
Using textControl As New ServerTextControl()
textControl.Create()
Dim html As String = "<html><body><h1>Document Content</h1><p>Main body text.</p></body></html>"
textControl.Load(html, StreamType.HTMLFormat)
Dim header As New HeaderFooter(HeaderFooterType.Header)
header.Text = "Document Header"
textControl.Sections(0).HeadersAndFooters.Add(header)
Dim footer As New HeaderFooter(HeaderFooterType.Footer)
footer.Text = "Page {page} of {numpages}"
textControl.Sections(0).HeadersAndFooters.Add(footer)
textControl.Save("output.pdf", StreamType.AdobePDF)
End Using
End Sub
End Class
End NamespaceIronPDF Approach:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Document Content</h1><p>Main body text.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.AddTextHeader("Document Header");
pdf.AddTextFooter("Page {page} of {total-pages}");
pdf.SaveAs("output.pdf");
}
}
}// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Document Content</h1><p>Main body text.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.AddTextHeader("Document Header");
pdf.AddTextFooter("Page {page} of {total-pages}");
pdf.SaveAs("output.pdf");
}
}
}Imports IronPdf
Imports IronPdf.Rendering
Namespace IronPdfExample
Class Program
Shared Sub Main(args As String())
Dim renderer As New ChromePdfRenderer()
Dim html As String = "<html><body><h1>Document Content</h1><p>Main body text.</p></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.AddTextHeader("Document Header")
pdf.AddTextFooter("Page {page} of {total-pages}")
pdf.SaveAs("output.pdf")
End Sub
End Class
End NamespaceTextControl requires creating HeaderFooter objects with specific HeaderFooterType enums, accessing document sections through textControl.Sections[0], and adding to the HeadersAndFooters collection. IronPDF provides direct AddTextHeader and AddTextFooter methods with simple placeholder syntax.
For HTML-based headers with full styling control, IronPDF also supports HtmlHeaderFooter:
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: center; font-size: 12pt;'>
Company Report
</div>",
MaxHeight = 30
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: right; font-size: 10pt;'>
Page {page} of {total-pages}
</div>",
MaxHeight = 25
};renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: center; font-size: 12pt;'>
Company Report
</div>",
MaxHeight = 30
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: right; font-size: 10pt;'>
Page {page} of {total-pages}
</div>",
MaxHeight = 25
};renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.HtmlFragment = "
<div style='width: 100%; text-align: center; font-size: 12pt;'>
Company Report
</div>",
.MaxHeight = 30
}
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "
<div style='width: 100%; text-align: right; font-size: 10pt;'>
Page {page} of {total-pages}
</div>",
.MaxHeight = 25
}Learn more about header and footer options in the headers and footers documentation.
TextControl API to IronPDF Mapping Reference
This mapping accelerates migration by showing direct API equivalents:
| TX Text Control | IronPDF |
|---|---|
ServerTextControl.Create() | new ChromePdfRenderer() |
tx.Load(html, StreamType.HTMLFormat) | renderer.RenderHtmlAsPdf(html) |
tx.Load(url, StreamType.HTMLFormat) | renderer.RenderUrlAsPdf(url) |
tx.Save(path, StreamType.AdobePDF) | pdf.SaveAs(path) |
SaveSettings.PDFAConformance | RenderingOptions.PdfAFormat |
DocumentServer.MailMerge | HTML templates + Razor |
DocumentTarget.HeadersAndFooters | HtmlHeaderFooter |
LoadSettings | RenderingOptions |
StreamType.AdobePDF | Default output |
Common Migration Issues and Solutions
Issue 1: ServerTextControl Context
TextControl requires Create() and using block for every operation.
Solution: IronPDF has no context management:
// Just create and use
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);// Just create and use
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);' Just create and use
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)Issue 2: StreamType Conversions
TextControl loads different formats and converts to PDF through StreamType enums.
Solution: IronPDF renders HTML directly without intermediate format conversion:
// No format conversion needed
var pdf = renderer.RenderHtmlAsPdf(html);// No format conversion needed
var pdf = renderer.RenderHtmlAsPdf(html);Dim pdf = renderer.RenderHtmlAsPdf(html)Issue 3: DOCX Templates
TextControl uses DOCX files for templates with mail merge.
Solution: Convert to HTML templates with C# string interpolation or Razor:
var data = new { CustomerName = "John Doe", InvoiceNumber = "12345", Total = "$1,500.00" };
var html = $@"
<html>
<head>
<style>
body {{ font-family: Arial; padding: 40px; }}
h1 {{ color: #333; }}
.total {{ font-size: 24px; color: green; }}
</style>
</head>
<body>
<h1>Invoice #{data.InvoiceNumber}</h1>
<p>Customer: {data.CustomerName}</p>
<p class='total'>Total: {data.Total}</p>
</body>
</html>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("invoice.pdf");var data = new { CustomerName = "John Doe", InvoiceNumber = "12345", Total = "$1,500.00" };
var html = $@"
<html>
<head>
<style>
body {{ font-family: Arial; padding: 40px; }}
h1 {{ color: #333; }}
.total {{ font-size: 24px; color: green; }}
</style>
</head>
<body>
<h1>Invoice #{data.InvoiceNumber}</h1>
<p>Customer: {data.CustomerName}</p>
<p class='total'>Total: {data.Total}</p>
</body>
</html>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("invoice.pdf");Option Strict On
Option Infer On
Dim data = New With {Key .CustomerName = "John Doe", Key .InvoiceNumber = "12345", Key .Total = "$1,500.00"}
Dim html = $"
<html>
<head>
<style>
body {{ font-family: Arial; padding: 40px; }}
h1 {{ color: #333; }}
.total {{ font-size: 24px; color: green; }}
</style>
</head>
<body>
<h1>Invoice #{data.InvoiceNumber}</h1>
<p>Customer: {data.CustomerName}</p>
<p class='total'>Total: {data.Total}</p>
</body>
</html>"
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("invoice.pdf")Issue 4: Intel Iris Xe Graphics Bug
TextControl has documented rendering issues with 11th generation Intel processors, requiring registry workarounds.
Solution: IronPDF uses Chromium rendering—no hardware acceleration bugs or registry modifications required.
TextControl Migration Checklist
Pre-Migration Tasks
Audit your codebase to identify all TextControl usage:
grep -r "using TXTextControl" --include="*.cs" .
grep -r "ServerTextControl\|Load\|Save" --include="*.cs" .grep -r "using TXTextControl" --include="*.cs" .
grep -r "ServerTextControl\|Load\|Save" --include="*.cs" .Document mail merge templates for conversion to HTML. Note header/footer requirements for implementation with HtmlHeaderFooter. Identify any DOCX editing functionality that may require alternative solutions.
Code Update Tasks
- Remove TX Text Control NuGet packages
- Install IronPdf NuGet package
- Remove
ServerTextControlcontext management (no moreCreate()calls) - Convert
StreamType.HTMLFormatloads toRenderHtmlAsPdf - Convert mail merge to HTML templates with string interpolation or Razor
- Update headers/footers to use
HtmlHeaderFooterorAddTextHeader/AddTextFooter - Simplify page settings using
RenderingOptions - Add license initialization at startup
Post-Migration Testing
After migration, verify these aspects:
- Test all document templates render correctly
- Verify PDF/A compliance if required
- Test password protection functionality
- Verify headers/footers appear on all pages
- Check on Intel 11th gen hardware—no more registry workarounds needed with IronPDF
Key Benefits of Migrating to IronPDF
Moving from TextControl to IronPDF provides several advantages for teams focused on PDF generation:
PDF-First Architecture: IronPDF is tailored specifically for PDF generation, offering robust document creation and rendering capabilities by leveraging modern HTML5 and CSS3 standards.
Cost Efficiency: IronPDF's one-time pricing makes it significantly cheaper over time, especially compared to TextControl's subscription-based service with mandatory 40% annual renewals.
Proven Stability: Documented reliability across various hardware, avoiding issues such as those faced by TextControl with Intel graphics.
No Context Management: Eliminate the ServerTextControl creation ceremony and resource disposal patterns. IronPDF's stateless rendering simplifies code and reduces potential memory leaks.
Modern Rendering Engine: As .NET 10 and C# 14 adoption increases through 2026, IronPDF's Chromium-based rendering ensures compatibility with current and future web standards.






