COMPARACIóN

Elección de una biblioteca de generación de documentos for .NET 8

.NET 8 introdujo cambios en el tiempo de ejecución que rompen la compatibilidad con muchas bibliotecas PDF tradicionales. System.Drawing.Common está obsoleto en las plataformas que no son Windows, Native AOT impone nuevas restricciones a las bibliotecas que requieren mucha reflexión y el modelo de despliegue de contenedores expone problemas de dependencia que no surgieron en las máquinas de desarrollo Windows. Las bibliotecas que funcionaban en .NET Framework o incluso .NET 6 pueden fallar con errores NU1202, DllNotFoundException o PlatformNotSupportedException en .NET 8.

Este artículo documenta qué bibliotecas PDF funcionan con .NET 8, muestra los errores específicos que encontrará con bibliotecas incompatibles y proporciona configuraciones de implementación para Docker y Azure Functions.

Inicio rápido: Generar PDF a partir de HTML en .NET 8

using IronPdf;

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;

var pdf = renderer.RenderHtmlAsPdf(@"
    <html>
    <head><style>
        body { font-family: 'Segoe UI', sans-serif; padding: 40px; }
        h1 { color: #2563eb; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th { background: #2563eb; color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #e5e7eb; }
    </style></head>
    <body>
        <h1>Q4 Report</h1>
        <table>
            <tr><th>Metric</th><th>Value</th><th>Change</th></tr>
            <tr><td>Revenue</td><td>$1.2M</td><td>+12%</td></tr>
            <tr><td>Users</td><td>45,230</td><td>+23%</td></tr>
        </table>
    </body></html>");

pdf.SaveAs("report.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;

var pdf = renderer.RenderHtmlAsPdf(@"
    <html>
    <head><style>
        body { font-family: 'Segoe UI', sans-serif; padding: 40px; }
        h1 { color: #2563eb; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th { background: #2563eb; color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #e5e7eb; }
    </style></head>
    <body>
        <h1>Q4 Report</h1>
        <table>
            <tr><th>Metric</th><th>Value</th><th>Change</th></tr>
            <tr><td>Revenue</td><td>$1.2M</td><td>+12%</td></tr>
            <tr><td>Users</td><td>45,230</td><td>+23%</td></tr>
        </table>
    </body></html>");

pdf.SaveAs("report.pdf");
$vbLabelText   $csharpLabel

Instalar mediante NuGet: Install-Package IronPdf. Objetivos net8.0 sin configuración adicional. Se implementa en Windows, Linux, macOS, Docker y Azure sin configuración específica de la plataforma.

¿Por qué fallan las bibliotecas PDF antiguas en .NET 8?

iTextSharp - No compatible con .NET 8

iTextSharp (el puerto .NET original de iText) no se ha actualizado desde 2018. Está dirigido únicamente a .NET Framework:

error NU1202: El paquete iTextSharp 5.5.13 no es compatible con net8.0

La ruta de migración es iText 7, que tiene una API diferente y requiere el cumplimiento de la AGPL (código abierto de toda la aplicación) o una licencia comercial. No se ha publicado el precio, pero los datos de terceros sugieren entre 15.000 y 210.000 dólares al año.

wkhtmltopdf Wrappers - Fallos de carga de DLL en .NET 8

Las envolturas de C# alrededor de wkhtmltopdf (DinkToPdf, Rotativa, NReco.PdfGenerator) fallan con errores específicos de la plataforma que son exclusivos del modelo de despliegue de .NET 8:

DinkToPdf - biblioteca nativa no encontrada:

System.DllNotFoundException: No se ha podido cargar la DLL 'libwkhtmltox'

Rotativa.AspNetCore - requiere una configuración manual de la ruta binaria que entra en conflicto con el despliegue de contenedores de .NET 8:

// This pattern requires deploying wkhtmltopdf binaries alongside your app
// and breaks in Docker containers without explicit path configuration
RotativaConfiguration.Setup(env.WebRootPath, "wkhtmltopdf");
// This pattern requires deploying wkhtmltopdf binaries alongside your app
// and breaks in Docker containers without explicit path configuration
RotativaConfiguration.Setup(env.WebRootPath, "wkhtmltopdf");
$vbLabelText   $csharpLabel

TuesPechkin / NReco - desajuste de arquitectura:

System.BadImageFormatException: No se pudo cargar el archivo o ensamblado

Estos errores reflejan un problema más profundo: wkhtmltopdf fue archivado en julio de 2024 con CVEs sin parchear. La arquitectura binaria nativa es anterior a las mejoras de detección de plataformas de .NET 8. No hay arreglo - sólo la migración a una biblioteca diferente.

PdfSharp - System.Drawing.Common Fallos en Linux

PdfSharp depende de System.Drawing.Common, que Microsoft dejó obsoleto para plataformas que no fueran Windows en .NET 6. En .NET 8, esto produce fallos de ejecución cuando se despliega en Linux o Docker:

using PdfSharp.Pdf;
using PdfSharp.Drawing;

var document = new PdfDocument();
// PlatformNotSupportedException on Linux:
// System.Drawing.Common is not supported on this platform
using PdfSharp.Pdf;
using PdfSharp.Drawing;

var document = new PdfDocument();
// PlatformNotSupportedException on Linux:
// System.Drawing.Common is not supported on this platform
$vbLabelText   $csharpLabel

PdfSharp 6.x ha estado trabajando para eliminar esta dependencia, pero el soporte multiplataforma sigue siendo incompleto a principios de 2026. Para implementaciones solo en Windows, PdfSharp funciona con .NET 8. Para Linux, Docker, o despliegues en la nube, no es fiable.

¿Qué bibliotecas PDF funcionan con .NET 8?

IronPDF- Compatibilidad total con .NET 8, multiplataforma

IronPDF apunta a net8.0 de forma nativa con renderizado de Chromium integrado. Sin dependencia de System.Drawing.Common, sin gestión de binarios nativos, sin configuración específica de plataforma.

Integración mínima de API (el patrón principal de .NET 8):

using IronPdf;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/invoice/{id}/pdf", async (int id, InvoiceService service) =>
{
    var invoice = await service.GetInvoiceAsync(id);
    var renderer = new ChromePdfRenderer();

    var pdf = renderer.RenderHtmlAsPdf(invoice.ToHtml());

    return Results.File(pdf.BinaryData, "application/pdf", $"invoice-{id}.pdf");
});

app.Run();
using IronPdf;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/invoice/{id}/pdf", async (int id, InvoiceService service) =>
{
    var invoice = await service.GetInvoiceAsync(id);
    var renderer = new ChromePdfRenderer();

    var pdf = renderer.RenderHtmlAsPdf(invoice.ToHtml());

    return Results.File(pdf.BinaryData, "application/pdf", $"invoice-{id}.pdf");
});

app.Run();
$vbLabelText   $csharpLabel

Para los equipos que utilizan el patrón de controlador, el mismo código funciona dentro de una acción de controlador: RenderHtmlAsPdf devuelve un PdfDocument que puede convertir a bytes con .BinaryData.

Licencias: Licencia perpetua a partir de 749 $ (Lite - 1 desarrollador, 1 proyecto). Professional: 1.499 $ (10 desarrolladores). Enterprise: 2.999 dólares (ilimitado). Publicado en ironpdf.com.

QuestPDF - Compatible con .NET 8, sin HTML

QuestPDF funciona con .NET 8 sin dependencias de plataforma. Su fluida API de C# construye documentos mediante programación: sin analizador HTML, sin motor CSS, sin motor de navegador:

using QuestPDF.Fluent;
using QuestPDF.Infrastructure;

QuestPDF.Settings.License = LicenseType.Community; // Free under $1M revenue

Document.Create(container =>
{
    container.Page(page =>
    {
        page.Size(PageSizes.A4);
        page.Margin(2, Unit.Centimetre);
        page.Content().Column(col =>
        {
            col.Item().Text("Q4 Report").FontSize(24).Bold();
            col.Item().Table(table =>
            {
                table.ColumnsDefinition(c => { c.RelativeColumn(2); c.RelativeColumn(1); c.RelativeColumn(1); });
                table.Header(h =>
                {
                    h.Cell().Text("Metric").Bold();
                    h.Cell().Text("Value").Bold();
                    h.Cell().Text("Change").Bold();
                });
                table.Cell().Text("Revenue"); table.Cell().Text("$1.2M"); table.Cell().Text("+12%");
                table.Cell().Text("Users"); table.Cell().Text("45,230"); table.Cell().Text("+23%");
            });
        });
    });
}).GeneratePdf("report.pdf");
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;

QuestPDF.Settings.License = LicenseType.Community; // Free under $1M revenue

Document.Create(container =>
{
    container.Page(page =>
    {
        page.Size(PageSizes.A4);
        page.Margin(2, Unit.Centimetre);
        page.Content().Column(col =>
        {
            col.Item().Text("Q4 Report").FontSize(24).Bold();
            col.Item().Table(table =>
            {
                table.ColumnsDefinition(c => { c.RelativeColumn(2); c.RelativeColumn(1); c.RelativeColumn(1); });
                table.Header(h =>
                {
                    h.Cell().Text("Metric").Bold();
                    h.Cell().Text("Value").Bold();
                    h.Cell().Text("Change").Bold();
                });
                table.Cell().Text("Revenue"); table.Cell().Text("$1.2M"); table.Cell().Text("+12%");
                table.Cell().Text("Users"); table.Cell().Text("45,230"); table.Cell().Text("+23%");
            });
        });
    });
}).GeneratePdf("report.pdf");
$vbLabelText   $csharpLabel

QuestPDF no convierte HTML. Si su flujo de trabajo utiliza plantillas HTML (vistas Razor, exportación de cuadros de mando, archivo de contenidos web), necesitará una biblioteca diferente. La licencia comunitaria cubre empresas con ingresos anuales inferiores a un millón de dólares; por encima de eso, se requiere licencia comercial.

iText 7 - Compatible con .NET 8, con licencia AGPL

iText 7 (el sucesor de iTextSharp) es compatible con .NET 8. El complemento pdfHTML ofrece conversión de HTML a PDF con un analizador personalizado, no un motor de navegador, por lo que las funciones CSS modernas (Flexbox, Grid) no se muestran correctamente.

Licencias: AGPL para uso de código abierto, licencia comercial (suscripción, precios no publicados) para aplicaciones propietarias. iText pasó a ofrecer licencias comerciales por suscripción en 2024.

Despliegue de Docker

Imagen estándar de Debian (recomendada)

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app

#IronPDFworks without additional apt-get installs
# Chromium dependencies are handled internally

COPY --from=build /app/publish .

ENV DOTNET_RUNNING_IN_CONTAINER=true
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]

Imagen alpina (huella más pequeña)

FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
WORKDIR /app

# Alpine requires explicit Chromium dependencies
RUN apk add --no-cache chromium nss freetype harfbuzz ca-certificates ttf-freefont

COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]

La imagen de Debian no requiere ningún paquete adicional. La imagen Alpine es más pequeña, pero requiere la instalación explícita de la biblioteca Chromium. Para la mayoría de las implantaciones, la imagen estándar de Debian es más sencilla y fiable.

Funciones Azure (Trabajador aislado)

.NET 8 Azure Functions utiliza el modelo de trabajador aislado.IronPDFtrabaja con este modelo para la generación de PDF bajo demanda:

using IronPdf;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;

namespace MyApp.Functions;

public class PdfFunctions
{
    [Function("GenerateInvoice")]
    public async Task<HttpResponseData> GenerateInvoice(
        [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
    {
        var invoice = await req.ReadFromJsonAsync<InvoiceRequest>();

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(BuildInvoiceHtml(invoice));

        var response = req.CreateResponse(System.Net.HttpStatusCode.OK);
        response.Headers.Add("Content-Type", "application/pdf");
        response.Headers.Add("Content-Disposition",
            $"attachment; filename=invoice-{invoice.Id}.pdf");
        await response.Body.WriteAsync(pdf.BinaryData);

        return response;
    }

    private string BuildInvoiceHtml(InvoiceRequest invoice)
    {
        return $@"<html><body>
            <h1>Invoice #{invoice.Id}</h1>
            <p>Amount: ${invoice.Amount:F2}</p>
        </body></html>";
    }
}

public record InvoiceRequest(string Id, decimal Amount);
using IronPdf;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;

namespace MyApp.Functions;

public class PdfFunctions
{
    [Function("GenerateInvoice")]
    public async Task<HttpResponseData> GenerateInvoice(
        [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
    {
        var invoice = await req.ReadFromJsonAsync<InvoiceRequest>();

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(BuildInvoiceHtml(invoice));

        var response = req.CreateResponse(System.Net.HttpStatusCode.OK);
        response.Headers.Add("Content-Type", "application/pdf");
        response.Headers.Add("Content-Disposition",
            $"attachment; filename=invoice-{invoice.Id}.pdf");
        await response.Body.WriteAsync(pdf.BinaryData);

        return response;
    }

    private string BuildInvoiceHtml(InvoiceRequest invoice)
    {
        return $@"<html><body>
            <h1>Invoice #{invoice.Id}</h1>
            <p>Amount: ${invoice.Amount:F2}</p>
        </body></html>";
    }
}

public record InvoiceRequest(string Id, decimal Amount);
$vbLabelText   $csharpLabel

Consideración de despliegue: El binario Chromium deIronPDFañade ~200 MB al paquete de despliegue. El plan de consumo de Azure Functions tiene un límite de tamaño de despliegue de 1,5 GB - verifique el tamaño total de su paquete. Para los planes Premium o Dedicado, este límite no se aplica. La latencia de arranque en frío para la primera generación de PDF es de 2-5 segundos mientras Chromium se inicializa.

Compatibilidad AOT nativa

.NET 8 amplió la compatibilidad con AOT nativo, pero las bibliotecas PDF se enfrentan a limitaciones fundamentales. Las bibliotecas basadas en Chromium (IronPDF, Puppeteer Sharp) no pueden compilar AOT porque incrustan o generan procesos de navegador. iText 7 utiliza una amplia reflexión que entra en conflicto con el recorte.

Estado actual con <PublishAot>true</PublishAot>:

BibliotecaEstado de AOTRazón
IronPDFNo compatibleIncorpora el tiempo de ejecución de Chromium
iText 7No compatibleReflexión intensa, generación dinámica de código
QuestPDFParcial (con TrimMode=partial)Algunos usos de reflexión
PdfSharpNo compatibleDependencia de System.Drawing.Common

Si AOT nativo es un requisito imprescindible, QuestPDF con TrimMode=partial es la opción más cercana, pero solo para la generación programática de documentos, no para la conversión HTML. Para los escenarios de HTML a PDF, AOT no es viable actualmente con ninguna biblioteca.

Comparación de licencias

BibliotecaModeloCostecompatibilidad con .NET 8
IronPDFPerpetuo749 $ (Lite) / 1.499 $ (Pro) / 2.999 $ (Enterprise)Completo
iText 7AGPL o suscripciónNo publicado ($15K-$210K/año est.)Completo
QuestPDFComunidad / ComercialGratuito <1 millón de dólares de ingresos, luego comercialCompleto
PdfSharpMIT (gratuito)$0Sólo Windows (Linux incompleto)
Aspose.PDFPor desarrollador~$999+Completo (problemas de memoria en Linux)

Compatibilidad con .NET 9

.NET 9 (publicado en noviembre de 2025) continúa los patrones establecidos en .NET 8. Las bibliotecas que funcionan con .NET 8 generalmente funcionan con .NET 9 sin cambios. Las principales adiciones de .NET 9 relevantes para la generación de PDF son la mejora del rendimiento de ARM64 (ventajas de la renderización basada en Chromium en Apple Silicon y AWS Graviton) y las continuas mejoras de Native AOT (aunque se mantienen las limitaciones fundamentales para las bibliotecas PDF).

Si su objetivo es .NET 9 o tiene previsto actualizarlo, lo más seguro es elegir una biblioteca que sea totalmente compatible con la implantación multiplataforma de .NET 8. Es poco probable que las bibliotecas con problemas específicos de plataforma (PdfSharp en Linux, Aspose con libgdiplus) resuelvan esos problemas en .NET 9, ya que la eliminación de las dependencias subyacentes es permanente.

Guía de migración

De iTextSharp a IronPDF

// Before (iTextSharp — doesn't compile against net8.0)
using iTextSharp.text;
using iTextSharp.text.pdf;

var doc = new Document();
PdfWriter.GetInstance(doc, new FileStream("output.pdf", FileMode.Create));
doc.Open();
doc.Add(new Paragraph("Hello World"));
doc.Close();

// After (IronPDF — targets net8.0)
using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<p>Hello World</p>");
pdf.SaveAs("output.pdf");
// Before (iTextSharp — doesn't compile against net8.0)
using iTextSharp.text;
using iTextSharp.text.pdf;

var doc = new Document();
PdfWriter.GetInstance(doc, new FileStream("output.pdf", FileMode.Create));
doc.Open();
doc.Add(new Paragraph("Hello World"));
doc.Close();

// After (IronPDF — targets net8.0)
using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<p>Hello World</p>");
pdf.SaveAs("output.pdf");
$vbLabelText   $csharpLabel

De wkhtmltopdf Wrappers a IronPDF

// Before (DinkToPdf — DllNotFoundException on .NET 8)
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument
{
    Objects = { new ObjectSettings { HtmlContent = html } }
};
var bytes = converter.Convert(doc);

// After (IronPDF — native .NET 8 support)
using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
var bytes = pdf.BinaryData;
// Before (DinkToPdf — DllNotFoundException on .NET 8)
var converter = new SynchronizedConverter(new PdfTools());
var doc = new HtmlToPdfDocument
{
    Objects = { new ObjectSettings { HtmlContent = html } }
};
var bytes = converter.Convert(doc);

// After (IronPDF — native .NET 8 support)
using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
var bytes = pdf.BinaryData;
$vbLabelText   $csharpLabel

La superficie de la API es más sencilla en ambos casos. El principal coste de la migración es probar las plantillas HTML existentes con el nuevo renderizador para comprobar que el resultado se ajusta a las expectativas.

La recomendación

Para proyectos .NET 8 que requieran conversión de HTML a PDF:IronPDFproporciona un renderizado Chromium integrado que funciona en varias plataformas sin necesidad de configuración. Maneja el despliegue de Docker, Azure Functions, y contenedores Linux fuera de la caja.

Para proyectos .NET 8 de creación de documentos mediante programación a partir de datos: La fluida API de QuestPDF está bien diseñada y es compatible con .NET 8, con la licencia comunitaria que cubre la mayoría de las nuevas empresas y pequeños equipos.

Para la manipulación de PDF (combinar, dividir, formularios) en Windows: PdfSharp sigue siendo viable si su objetivo de despliegue es sólo Windows.

Evite iTextSharp (no compatible), wkhtmltopdf wrappers (archivado, CVEs), y cualquier biblioteca que dependa de System.Drawing.Common para el despliegue multiplataforma.