How to Migrate from Api2pdf to IronPDF in C#
Api2pdf offers a cloud-based service for generating PDFs, but sending sensitive documents to external servers can lead to security risks, compliance issues, and ongoing costs that can add up over time. This guide provides a detailed migration path from Api2pdf to IronPDF—a native .NET PDF library that processes documents entirely on your own infrastructure, removing data transmission concerns and converting per-conversion costs into a one-time investment.
Why Consider Moving from Api2pdf?
While Api2pdf provides convenient cloud-based PDF generation, several factors lead development teams to look for on-premises alternatives for their PDF generation needs.
Security and Compliance Concerns
Api2pdf operates as a cloud-based service where your sensitive HTML and documents are sent to third-party servers for processing. This creates significant concerns for organizations handling regulated data.
| Risk | Api2pdf | IronPDF |
|---|---|---|
| Data Transmission | All content sent to external servers | Processes locally on your infrastructure |
| GDPR Compliance | Data crosses jurisdictions | Data never leaves your environment |
| HIPAA Compliance | PHI transmitted externally | PHI stays within your systems |
| SOC 2 | Third-party dependency | Full control over data handling |
| PCI DSS | Card data potentially exposed | No external transmission |
Cost Accumulation Over Time
Api2pdf charges a $1/month base plus metered usage (bandwidth and compute seconds) indefinitely, while IronPDF offers a one-time perpetual license. Verify current numbers at api2pdf.com/pricing:
| Component | Api2pdf | IronPDF |
|---|---|---|
| Base | $1/month | One-time license |
| Bandwidth | $0.001 per MB | n/a (local) |
| Compute | $0.00019551 per second | n/a (local) |
| Volume scaling | Linear with usage and file size | Flat (Lite ~$749, Plus ~$1,499, Professional ~$2,999) |
Heavier workloads (large files, JS-heavy pages, long render times) shift the api2pdf bill upward; IronPDF cost is fixed once licensed.
Performance and Availability
Api2pdf requires network round-trips that add 2-5 seconds of latency to every PDF generation request. IronPDF processes locally in 100-500 milliseconds. Additionally, IronPDF works fully offline and in air-gapped environments—critical for applications that can't depend on external service availability.
Api2pdf vs. IronPDF: Key Differences
| Aspect | Api2pdf | IronPDF |
|---|---|---|
| Data Handling | Sent to third-party cloud servers | Processed locally on your infrastructure |
| Pricing | $1/month base + metered ($0.001/MB bandwidth, $0.00019551/sec compute) | One-time perpetual license |
| Latency | 2-5 seconds (network round-trip) | 100-500ms (local processing) |
| Offline | Not available | Works fully offline |
| Installation | API key + HTTP client | Simple NuGet package |
| Compliance | GDPR/HIPAA concerns (data leaves network) | Full compliance control |
Step-by-Step Migration Process
Step 1: Update NuGet Packages
Remove the Api2pdf package and install IronPDF:
# Remove Api2pdf
dotnet remove package Api2Pdf
# Install IronPDF
dotnet add package IronPdf
# Remove Api2pdf
dotnet remove package Api2Pdf
# Install IronPDF
dotnet add package IronPdf
Or via Package Manager Console:
Uninstall-Package Api2Pdf
Install-Package IronPdf
Step 2: Update Namespace References
Replace Api2pdf namespaces with IronPDF:
// Remove these
using Api2Pdf;
// Add these
using IronPdf;
using IronPdf.Rendering;
// Remove these
using Api2Pdf;
// Add these
using IronPdf;
using IronPdf.Rendering;
Imports IronPdf
Imports IronPdf.Rendering
Step 3: Configure the License Key
Set the IronPDF license key at application startup:
// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
// Or configure via appsettings.json:
// { "IronPdf.LicenseKey": "YOUR-IRONPDF-LICENSE-KEY" }
// Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
// Or configure via appsettings.json:
// { "IronPdf.LicenseKey": "YOUR-IRONPDF-LICENSE-KEY" }
' Set once at application startup
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY"
' Or configure via appsettings.json:
' { "IronPdf.LicenseKey": "YOUR-IRONPDF-LICENSE-KEY" }
Step 4: Remove API Key Configuration
IronPDF runs locally and doesn't require API keys:
// Remove this Api2pdf pattern
var client = new Api2Pdf("API_KEY");
// Just create the renderer directly
var renderer = new ChromePdfRenderer();
// Remove this Api2pdf pattern
var client = new Api2Pdf("API_KEY");
// Just create the renderer directly
var renderer = new ChromePdfRenderer();
' Remove this Api2pdf pattern
Dim client = New Api2Pdf("API_KEY")
' Just create the renderer directly
Dim renderer = New ChromePdfRenderer()
Complete API Migration Reference
Core Class Mapping
| Api2pdf Class | IronPDF Equivalent |
|---|---|
Api2Pdf (client) |
ChromePdfRenderer |
Api2PdfResult |
PdfDocument |
ChromeHtmlToPdfOptions |
ChromePdfRenderOptions |
Method Mapping
| Api2pdf Method | IronPDF Method |
|---|---|
client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest { Html = html }) |
renderer.RenderHtmlAsPdf(html) |
client.Chrome.UrlToPdfAsync(new ChromeUrlToPdfRequest { Url = url }) |
renderer.RenderUrlAsPdf(url) |
result.FileUrl (URL to download) |
pdf.SaveAs(path) |
result.GetFileBytes() |
pdf.BinaryData |
client.PdfSharp.MergePdfs(new PdfMergeRequest { Urls = urls }) |
PdfDocument.Merge(pdfs) |
client.PdfSharp.SetPassword(new PdfPasswordRequest { Url, OwnerPassword }) |
pdf.SecuritySettings.OwnerPassword |
Rendering Options Mapping
| Api2pdf Option | IronPDF Option |
|---|---|
Landscape = true |
RenderingOptions.PaperOrientation = Landscape |
PreferCSSPageSize = true / Format |
RenderingOptions.PaperSize = PdfPaperSize.A4 |
PrintBackground = true |
RenderingOptions.PrintHtmlBackgrounds = true |
MarginTop, etc. |
RenderingOptions.MarginTop, etc. |
Delay = 5000 |
RenderingOptions.WaitFor.RenderDelay(5000) |
Code Migration Examples
HTML to PDF Conversion
The most common Api2pdf operation demonstrates the fundamental shift—from cloud API calls to local processing.
Api2pdf Implementation:
// NuGet: Install-Package Api2Pdf
using System;
using System.Threading.Tasks;
using Api2Pdf;
class Program
{
static async Task Main(string[] args)
{
var client = new Api2Pdf("your-api-key");
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = "<h1>Hello World</h1>"
});
Console.WriteLine(result.FileUrl);
}
}
// NuGet: Install-Package Api2Pdf
using System;
using System.Threading.Tasks;
using Api2Pdf;
class Program
{
static async Task Main(string[] args)
{
var client = new Api2Pdf("your-api-key");
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = "<h1>Hello World</h1>"
});
Console.WriteLine(result.FileUrl);
}
}
Imports System
Imports System.Threading.Tasks
Imports Api2Pdf
Module Program
Async Function Main(args As String()) As Task
Dim client = New Api2Pdf("your-api-key")
Dim result = Await client.Chrome.HtmlToPdfAsync(New ChromeHtmlToPdfRequest With {
.Html = "<h1>Hello World</h1>"
})
Console.WriteLine(result.FileUrl)
End Function
End Module
IronPDF Implementation:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created successfully");
}
}
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created successfully");
}
}
Imports System
Imports IronPdf
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>")
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF created successfully")
End Sub
End Class
IronPDF eliminates the network round-trip, API key management, and the separate download step required by Api2pdf's URL-based response pattern.
URL to PDF Conversion
Api2pdf Implementation:
// NuGet: Install-Package Api2Pdf
using System;
using System.Threading.Tasks;
using Api2Pdf;
class Program
{
static async Task Main(string[] args)
{
var client = new Api2Pdf("your-api-key");
var result = await client.Chrome.UrlToPdfAsync(new ChromeUrlToPdfRequest
{
Url = "https://www.example.com"
});
Console.WriteLine(result.FileUrl);
}
}
// NuGet: Install-Package Api2Pdf
using System;
using System.Threading.Tasks;
using Api2Pdf;
class Program
{
static async Task Main(string[] args)
{
var client = new Api2Pdf("your-api-key");
var result = await client.Chrome.UrlToPdfAsync(new ChromeUrlToPdfRequest
{
Url = "https://www.example.com"
});
Console.WriteLine(result.FileUrl);
}
}
Imports System
Imports System.Threading.Tasks
Imports Api2Pdf
Module Program
Async Function Main(args As String()) As Task
Dim client = New Api2Pdf("your-api-key")
Dim result = Await client.Chrome.UrlToPdfAsync(New ChromeUrlToPdfRequest With {
.Url = "https://www.example.com"
})
Console.WriteLine(result.FileUrl)
End Function
End Module
IronPDF Implementation:
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF created from URL successfully");
}
}
// NuGet: Install-Package IronPdf
using System;
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("PDF created from URL successfully");
}
}
Imports System
Imports IronPdf
Module Program
Sub Main(args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("PDF created from URL successfully")
End Sub
End Module
HTML File to PDF with Options
Api2pdf Implementation:
// NuGet: Install-Package Api2Pdf
using System;
using System.IO;
using System.Threading.Tasks;
using Api2Pdf;
class Program
{
static async Task Main(string[] args)
{
var client = new Api2Pdf("your-api-key");
string html = File.ReadAllText("input.html");
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = html,
Options = new ChromeHtmlToPdfOptions
{
Landscape = true,
PrintBackground = true
}
});
Console.WriteLine(result.FileUrl);
}
}
// NuGet: Install-Package Api2Pdf
using System;
using System.IO;
using System.Threading.Tasks;
using Api2Pdf;
class Program
{
static async Task Main(string[] args)
{
var client = new Api2Pdf("your-api-key");
string html = File.ReadAllText("input.html");
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = html,
Options = new ChromeHtmlToPdfOptions
{
Landscape = true,
PrintBackground = true
}
});
Console.WriteLine(result.FileUrl);
}
}
Imports System
Imports System.IO
Imports System.Threading.Tasks
Imports Api2Pdf
Module Program
Async Function Main(args As String()) As Task
Dim client = New Api2Pdf("your-api-key")
Dim html As String = File.ReadAllText("input.html")
Dim result = Await client.Chrome.HtmlToPdfAsync(New ChromeHtmlToPdfRequest With {
.Html = html,
.Options = New ChromeHtmlToPdfOptions With {
.Landscape = True,
.PrintBackground = True
}
})
Console.WriteLine(result.FileUrl)
End Function
End Module
IronPDF Implementation:
// NuGet: Install-Package IronPdf
using System;
using System.IO;
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Landscape;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
string html = File.ReadAllText("input.html");
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created with options successfully");
}
}
// NuGet: Install-Package IronPdf
using System;
using System.IO;
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Landscape;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
string html = File.ReadAllText("input.html");
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created with options successfully");
}
}
Imports System
Imports System.IO
Imports IronPdf
Module Program
Sub Main(args As String())
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Landscape
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
Dim html As String = File.ReadAllText("input.html")
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF created with options successfully")
End Sub
End Module
IronPDF configures rendering options directly on the renderer object rather than passing them as a separate options parameter to each API call.
Merging Multiple PDFs
Api2pdf Implementation:
using Api2Pdf;
var client = new Api2Pdf("YOUR_API_KEY");
var pdfUrls = new List<string>
{
"https://example.com/pdf1.pdf",
"https://example.com/pdf2.pdf",
"https://example.com/pdf3.pdf"
};
var request = new PdfMergeRequest { Urls = pdfUrls };
var result = await client.PdfSharp.MergePdfsAsync(request);
if (result.Success)
{
// Download merged PDF from result.FileUrl
}
using Api2Pdf;
var client = new Api2Pdf("YOUR_API_KEY");
var pdfUrls = new List<string>
{
"https://example.com/pdf1.pdf",
"https://example.com/pdf2.pdf",
"https://example.com/pdf3.pdf"
};
var request = new PdfMergeRequest { Urls = pdfUrls };
var result = await client.PdfSharp.MergePdfsAsync(request);
if (result.Success)
{
// Download merged PDF from result.FileUrl
}
Imports Api2Pdf
Dim client As New Api2Pdf("YOUR_API_KEY")
Dim pdfUrls As New List(Of String) From {
"https://example.com/pdf1.pdf",
"https://example.com/pdf2.pdf",
"https://example.com/pdf3.pdf"
}
Dim request As New PdfMergeRequest With {.Urls = pdfUrls}
Dim result = Await client.PdfSharp.MergePdfsAsync(request)
If result.Success Then
' Download merged PDF from result.FileUrl
End If
IronPDF Implementation:
using IronPdf;
// Load PDFs from files
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var pdf3 = PdfDocument.FromFile("document3.pdf");
// Merge all PDFs
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("merged.pdf");
using IronPdf;
// Load PDFs from files
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var pdf3 = PdfDocument.FromFile("document3.pdf");
// Merge all PDFs
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("merged.pdf");
Imports IronPdf
' Load PDFs from files
Dim pdf1 = PdfDocument.FromFile("document1.pdf")
Dim pdf2 = PdfDocument.FromFile("document2.pdf")
Dim pdf3 = PdfDocument.FromFile("document3.pdf")
' Merge all PDFs
Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
merged.SaveAs("merged.pdf")
IronPDF's static Merge method accepts multiple documents directly, eliminating the URL-based workflow.
Password-Protected PDFs
Api2pdf Implementation:
using Api2Pdf;
var client = new Api2Pdf("YOUR_API_KEY");
// Generate PDF first
var pdfResult = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = "<h1>Confidential</h1>"
});
// Then add password protection in a second round-trip
var protectedResult = await client.PdfSharp.SetPasswordAsync(new PdfPasswordRequest
{
Url = pdfResult.FileUrl,
OwnerPassword = "secretpassword"
});
using Api2Pdf;
var client = new Api2Pdf("YOUR_API_KEY");
// Generate PDF first
var pdfResult = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = "<h1>Confidential</h1>"
});
// Then add password protection in a second round-trip
var protectedResult = await client.PdfSharp.SetPasswordAsync(new PdfPasswordRequest
{
Url = pdfResult.FileUrl,
OwnerPassword = "secretpassword"
});
Imports Api2Pdf
Dim client = New Api2Pdf("YOUR_API_KEY")
' Generate PDF first
Dim pdfResult = Await client.Chrome.HtmlToPdfAsync(New ChromeHtmlToPdfRequest With {
.Html = "<h1>Confidential</h1>"
})
' Then add password protection in a second round-trip
Dim protectedResult = Await client.PdfSharp.SetPasswordAsync(New PdfPasswordRequest With {
.Url = pdfResult.FileUrl,
.OwnerPassword = "secretpassword"
})
IronPDF Implementation:
using IronPdf;
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Confidential</h1>");
// Set security in one step
pdf.SecuritySettings.OwnerPassword = "owner123";
pdf.SecuritySettings.UserPassword = "user123";
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint;
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.AllowUserEdits = PdfEditSecurity.NoEdit;
pdf.SaveAs("protected.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Confidential</h1>");
// Set security in one step
pdf.SecuritySettings.OwnerPassword = "owner123";
pdf.SecuritySettings.UserPassword = "user123";
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint;
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.AllowUserEdits = PdfEditSecurity.NoEdit;
pdf.SaveAs("protected.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Confidential</h1>")
' Set security in one step
pdf.SecuritySettings.OwnerPassword = "owner123"
pdf.SecuritySettings.UserPassword = "user123"
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint
pdf.SecuritySettings.AllowUserCopyPasteContent = False
pdf.SecuritySettings.AllowUserEdits = PdfEditSecurity.NoEdit
pdf.SaveAs("protected.pdf")
IronPDF provides granular control over PDF permissions through the SecuritySettings property.
Headers and Footers
Api2pdf Implementation:
using Api2Pdf;
var client = new Api2Pdf("YOUR_API_KEY");
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = html,
Options = new ChromeHtmlToPdfOptions
{
DisplayHeaderFooter = true,
HeaderTemplate = "<div style='font-size:10px'>Company Header</div>",
FooterTemplate = "<div style='font-size:10px'>Page <span class='pageNumber'></span></div>"
}
});
using Api2Pdf;
var client = new Api2Pdf("YOUR_API_KEY");
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = html,
Options = new ChromeHtmlToPdfOptions
{
DisplayHeaderFooter = true,
HeaderTemplate = "<div style='font-size:10px'>Company Header</div>",
FooterTemplate = "<div style='font-size:10px'>Page <span class='pageNumber'></span></div>"
}
});
Imports Api2Pdf
Dim client = New Api2Pdf("YOUR_API_KEY")
Dim result = Await client.Chrome.HtmlToPdfAsync(New ChromeHtmlToPdfRequest With {
.Html = html,
.Options = New ChromeHtmlToPdfOptions With {
.DisplayHeaderFooter = True,
.HeaderTemplate = "<div style='font-size:10px'>Company Header</div>",
.FooterTemplate = "<div style='font-size:10px'>Page <span class='pageNumber'></span></div>"
}
})
IronPDF Implementation:
using IronPdf;
var renderer = new ChromePdfRenderer();
// HTML headers and footers with full styling
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:10px; text-align:center;'>Company Header</div>",
DrawDividerLine = true
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:10px; text-align:center;'>Page {page} of {total-pages}</div>",
DrawDividerLine = true
};
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("with-headers.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
// HTML headers and footers with full styling
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:10px; text-align:center;'>Company Header</div>",
DrawDividerLine = true
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:10px; text-align:center;'>Page {page} of {total-pages}</div>",
DrawDividerLine = true
};
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("with-headers.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
' HTML headers and footers with full styling
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='font-size:10px; text-align:center;'>Company Header</div>",
.DrawDividerLine = True
}
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='font-size:10px; text-align:center;'>Page {page} of {total-pages}</div>",
.DrawDividerLine = True
}
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("with-headers.pdf")
IronPDF supports placeholder tokens like {page} and {total-pages} for dynamic page numbering. For more options, see the headers and footers documentation.
ASP.NET Core Integration
Api2pdf's async HTTP pattern differs significantly from IronPDF's direct PDF generation.
Api2pdf Pattern:
[ApiController]
public class PdfController : ControllerBase
{
private readonly Api2Pdf _client;
public PdfController()
{
_client = new Api2Pdf("YOUR_API_KEY");
}
[HttpGet("generate")]
public async Task<IActionResult> GeneratePdf()
{
var result = await _client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = "<h1>Report</h1>"
});
if (!result.Success)
return BadRequest(result.Error);
// Redirect to download URL
return Redirect(result.FileUrl);
}
}
[ApiController]
public class PdfController : ControllerBase
{
private readonly Api2Pdf _client;
public PdfController()
{
_client = new Api2Pdf("YOUR_API_KEY");
}
[HttpGet("generate")]
public async Task<IActionResult> GeneratePdf()
{
var result = await _client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest
{
Html = "<h1>Report</h1>"
});
if (!result.Success)
return BadRequest(result.Error);
// Redirect to download URL
return Redirect(result.FileUrl);
}
}
Imports Microsoft.AspNetCore.Mvc
<ApiController>
Public Class PdfController
Inherits ControllerBase
Private ReadOnly _client As Api2Pdf
Public Sub New()
_client = New Api2Pdf("YOUR_API_KEY")
End Sub
<HttpGet("generate")>
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim result = Await _client.Chrome.HtmlToPdfAsync(New ChromeHtmlToPdfRequest With {
.Html = "<h1>Report</h1>"
})
If Not result.Success Then
Return BadRequest(result.Error)
End If
' Redirect to download URL
Return Redirect(result.FileUrl)
End Function
End Class
IronPDF Pattern:
[ApiController]
public class PdfController : ControllerBase
{
[HttpGet("generate")]
public IActionResult GeneratePdf()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Report</h1>");
// Return PDF directly - no download step needed
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
[HttpGet("generate-async")]
public async Task<IActionResult> GeneratePdfAsync()
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync("<h1>Report</h1>");
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
}
[ApiController]
public class PdfController : ControllerBase
{
[HttpGet("generate")]
public IActionResult GeneratePdf()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Report</h1>");
// Return PDF directly - no download step needed
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
[HttpGet("generate-async")]
public async Task<IActionResult> GeneratePdfAsync()
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync("<h1>Report</h1>");
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
}
Imports Microsoft.AspNetCore.Mvc
<ApiController>
Public Class PdfController
Inherits ControllerBase
<HttpGet("generate")>
Public Function GeneratePdf() As IActionResult
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Report</h1>")
' Return PDF directly - no download step needed
Return File(pdf.BinaryData, "application/pdf", "report.pdf")
End Function
<HttpGet("generate-async")>
Public Async Function GeneratePdfAsync() As Task(Of IActionResult)
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync("<h1>Report</h1>")
Return File(pdf.BinaryData, "application/pdf", "report.pdf")
End Function
End Class
IronPDF returns the PDF directly via BinaryData or Stream, eliminating the redirect-to-download pattern.
Dependency Injection Configuration
// Program.cs or Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IPdfService, IronPdfService>();
}
// IPdfService.cs
public interface IPdfService
{
PdfDocument GenerateFromHtml(string html);
Task<PdfDocument> GenerateFromHtmlAsync(string html);
}
// IronPdfService.cs
public class IronPdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public IronPdfService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
_renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
}
public PdfDocument GenerateFromHtml(string html) =>
_renderer.RenderHtmlAsPdf(html);
public Task<PdfDocument> GenerateFromHtmlAsync(string html) =>
_renderer.RenderHtmlAsPdfAsync(html);
}
// Program.cs or Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IPdfService, IronPdfService>();
}
// IPdfService.cs
public interface IPdfService
{
PdfDocument GenerateFromHtml(string html);
Task<PdfDocument> GenerateFromHtmlAsync(string html);
}
// IronPdfService.cs
public class IronPdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public IronPdfService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
_renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
}
public PdfDocument GenerateFromHtml(string html) =>
_renderer.RenderHtmlAsPdf(html);
public Task<PdfDocument> GenerateFromHtmlAsync(string html) =>
_renderer.RenderHtmlAsPdfAsync(html);
}
' Program.vb or Startup.vb
Public Sub ConfigureServices(services As IServiceCollection)
services.AddScoped(Of IPdfService, IronPdfService)()
End Sub
' IPdfService.vb
Public Interface IPdfService
Function GenerateFromHtml(html As String) As PdfDocument
Function GenerateFromHtmlAsync(html As String) As Task(Of PdfDocument)
End Interface
' IronPdfService.vb
Public Class IronPdfService
Implements IPdfService
Private ReadOnly _renderer As ChromePdfRenderer
Public Sub New()
_renderer = New ChromePdfRenderer()
_renderer.RenderingOptions.PrintHtmlBackgrounds = True
_renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
End Sub
Public Function GenerateFromHtml(html As String) As PdfDocument Implements IPdfService.GenerateFromHtml
Return _renderer.RenderHtmlAsPdf(html)
End Function
Public Function GenerateFromHtmlAsync(html As String) As Task(Of PdfDocument) Implements IPdfService.GenerateFromHtmlAsync
Return _renderer.RenderHtmlAsPdfAsync(html)
End Function
End Class
Error Handling Migration
Api2pdf uses response object checks. IronPDF uses standard .NET exceptions.
Api2pdf Pattern:
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest { Html = html });
if (!result.Success)
{
Console.WriteLine($"Error: {result.Error}");
return;
}
var result = await client.Chrome.HtmlToPdfAsync(new ChromeHtmlToPdfRequest { Html = html });
if (!result.Success)
{
Console.WriteLine($"Error: {result.Error}");
return;
}
Imports System
Dim result = Await client.Chrome.HtmlToPdfAsync(New ChromeHtmlToPdfRequest With {.Html = html})
If Not result.Success Then
Console.WriteLine($"Error: {result.Error}")
Return
End If
IronPDF Pattern:
try
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
catch (IronPdf.Exceptions.IronPdfLicenseException ex)
{
Console.WriteLine($"License error: {ex.Message}");
}
catch (IronPdf.Exceptions.IronPdfRenderingException ex)
{
Console.WriteLine($"Rendering error: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
try
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
catch (IronPdf.Exceptions.IronPdfLicenseException ex)
{
Console.WriteLine($"License error: {ex.Message}");
}
catch (IronPdf.Exceptions.IronPdfRenderingException ex)
{
Console.WriteLine($"Rendering error: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
Imports IronPdf.Exceptions
Try
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
Catch ex As IronPdfLicenseException
Console.WriteLine($"License error: {ex.Message}")
Catch ex As IronPdfRenderingException
Console.WriteLine($"Rendering error: {ex.Message}")
Catch ex As Exception
Console.WriteLine($"Error: {ex.Message}")
End Try
Performance Comparison
| Metric | Api2pdf | IronPDF |
|---|---|---|
| Simple HTML | 2-5 seconds (network) | 100-500ms (local) |
| Complex page | 5-10 seconds | 500ms-2s |
| Batch of 100 | Minutes (rate limits) | Seconds (parallel) |
| Offline | Not available | Works fully |
| Cold start | None | ~2s (first render) |
Performance Optimization Tips
// 1. Reuse renderer instance
private static readonly ChromePdfRenderer SharedRenderer = new ChromePdfRenderer();
public PdfDocument GeneratePdf(string html)
{
return SharedRenderer.RenderHtmlAsPdf(html);
}
// 2. Parallel generation
var tasks = htmlDocs.Select(html =>
Task.Run(() => SharedRenderer.RenderHtmlAsPdf(html)));
var results = await Task.WhenAll(tasks);
// 3. Disable unnecessary features for speed
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = false; // If not needed
renderer.RenderingOptions.WaitFor.RenderDelay(0); // No delay
// 1. Reuse renderer instance
private static readonly ChromePdfRenderer SharedRenderer = new ChromePdfRenderer();
public PdfDocument GeneratePdf(string html)
{
return SharedRenderer.RenderHtmlAsPdf(html);
}
// 2. Parallel generation
var tasks = htmlDocs.Select(html =>
Task.Run(() => SharedRenderer.RenderHtmlAsPdf(html)));
var results = await Task.WhenAll(tasks);
// 3. Disable unnecessary features for speed
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = false; // If not needed
renderer.RenderingOptions.WaitFor.RenderDelay(0); // No delay
Imports System.Threading.Tasks
' 1. Reuse renderer instance
Private Shared ReadOnly SharedRenderer As New ChromePdfRenderer()
Public Function GeneratePdf(html As String) As PdfDocument
Return SharedRenderer.RenderHtmlAsPdf(html)
End Function
' 2. Parallel generation
Dim tasks = htmlDocs.Select(Function(html) Task.Run(Function() SharedRenderer.RenderHtmlAsPdf(html)))
Dim results = Await Task.WhenAll(tasks)
' 3. Disable unnecessary features for speed
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = False ' If not needed
renderer.RenderingOptions.WaitFor.RenderDelay(0) ' No delay
Troubleshooting Common Migration Issues
Issue: PDF Looks Different from Api2pdf Output
Match Api2pdf's Headless Chrome settings:
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
renderer.RenderingOptions.PrintHtmlBackgrounds = true;
renderer.RenderingOptions.ViewPortWidth = 1280;
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.RenderDelay(1000);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
renderer.RenderingOptions.PrintHtmlBackgrounds = true;
renderer.RenderingOptions.ViewPortWidth = 1280;
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.RenderDelay(1000);
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print
renderer.RenderingOptions.PrintHtmlBackgrounds = True
renderer.RenderingOptions.ViewPortWidth = 1280
renderer.RenderingOptions.EnableJavaScript = True
renderer.RenderingOptions.WaitFor.RenderDelay(1000)
Issue: External Resources Not Loading
Configure resource loading timeouts:
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.WaitFor.AllFontsLoaded(timeout: 10000);
renderer.RenderingOptions.WaitFor.NetworkIdle(timeout: 10000);
// Or use base URL for relative paths
var pdf = renderer.RenderHtmlAsPdf(html, baseUrl: "https://example.com/");
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.WaitFor.AllFontsLoaded(timeout: 10000);
renderer.RenderingOptions.WaitFor.NetworkIdle(timeout: 10000);
// Or use base URL for relative paths
var pdf = renderer.RenderHtmlAsPdf(html, baseUrl: "https://example.com/");
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.WaitFor.AllFontsLoaded(timeout:=10000)
renderer.RenderingOptions.WaitFor.NetworkIdle(timeout:=10000)
' Or use base URL for relative paths
Dim pdf = renderer.RenderHtmlAsPdf(html, baseUrl:="https://example.com/")
Issue: Large PDF File Sizes
Compress images after generation:
renderer.RenderingOptions.ImageQuality = 80;
// Or compress after generation
pdf.CompressImages(quality: 75);
pdf.SaveAs("compressed.pdf");
renderer.RenderingOptions.ImageQuality = 80;
// Or compress after generation
pdf.CompressImages(quality: 75);
pdf.SaveAs("compressed.pdf");
renderer.RenderingOptions.ImageQuality = 80
' Or compress after generation
pdf.CompressImages(quality:=75)
pdf.SaveAs("compressed.pdf")
Post-Migration Checklist
After completing the code migration, verify the following:
- Verify PDF output quality matches expectations
- Test all edge cases (large documents, special characters)
- Validate performance metrics (should see significant improvement)
- Update Docker configurations if applicable
- Remove Api2pdf portal account and API keys
- Update monitoring (no more API latency tracking needed)
- Document new patterns for your team
- Update CI/CD pipelines
Additional Resources
Migrating from Api2pdf to IronPDF transforms your PDF generation from a cloud-dependent, per-conversion cost model to a local, one-time investment. Your sensitive documents stay on your infrastructure, latency drops from seconds to milliseconds, and you eliminate vendor dependency for this critical application capability.

