Saltar al pie de página
.NET AYUDA

Generador de informes ASP.NET para España: VeriFactu, TicketBAI y FACe con IronPDF

Generador de informes ASP.NET para España: VeriFactu, TicketBAI y FACe con IronPDF

Los desarrolladores .NET en España tienen un requisito que sus homólogos del resto de Europa no comparten en la misma escala: los informes generados por sus aplicaciones ASP.NET Core no son solo documentos de negocio — son facturas sujetas a VeriFactu, albaranes relacionados con TicketBAI, o documentos B2G para FACe que deben cumplir Facturae 3.2.2. ASP.NET Core con IronPDF es la combinación técnica más directa para generar esos informes con texto seleccionable real, código QR AEAT verificable, leyenda VERI*FACTU, y las capacidades de firma PAdES necesarias para el archivado conforme a LOPDGDD y eIDAS.

Esta guía cubre el flujo completo: desde la configuración del proyecto hasta la generación de informes PDF conformes con los requisitos del ecosistema de facturación electrónica español.

Índice del tutorial

  1. Crear una aplicación ASP.NET Core en Visual Studio
  2. Instalar IronPDF desde NuGet
  3. Diseñar el informe como documento HTML con elementos de cumplimiento español
  4. Generar el PDF con IronPDF: código QR AEAT, leyenda VERI*FACTU, firma PAdES
  5. Casos de uso avanzados: TicketBAI (Bizkaia, Gipuzkoa, Araba) y FACe

Contexto: por qué la generación de informes PDF tiene peso regulatorio en España

VeriFactu: los informes de facturación son territorio normativo

VeriFactu (sistema de verificación de facturas de la AEAT) requiere que los sistemas de facturación generen registros de facturación encadenados con huella (huella encadenada) y que los PDFs de facturas incluyan un código QR verificable que enlace a la sede electrónica de la AEAT. La leyenda obligatoria VERI*FACTU (con asterisco) o Factura verificable en la sede electrónica de la AEAT debe aparecer en la visualización de cada factura que haya pasado el proceso de registro.

La obligación de cumplimiento para proveedores de software de facturación entra en vigor el 1 de enero de 2027 (impuesto sobre sociedades) y el 1 de julio de 2027 (demás contribuyentes) según el Real Decreto-ley 15/2025. Los ISVs que desarrollan software de facturación ya deben tener productos conformes.

Importante: IronPDF es un componente de generación de PDF para usar DENTRO del software de facturación certificado. No es en sí mismo un sistema de facturación certificado por la AEAT.

TicketBAI: los informes de facturas del País Vasco requieren firma XAdES

TicketBAI está en vigor en el País Vasco. Cada factura debe estar firmada con XAdES y enviada a la hacienda foral correspondiente. Las tres diputaciones forales tienen implementaciones con diferencias específicas:

  • Bizkaia (bizkaia.eus): también gestiona BATUZ
  • Gipuzkoa (gipuzkoa.eus)
  • Araba (araba.eus)

Los desarrolladores que generen informes de facturas para clientes del País Vasco deben contemplar las tres variantes forales en su implementación ASP.NET Core.

Facturae y FACe: los informes B2G requieren formato estructurado

Para la Administración Pública española, los informes de facturación se envían a través de FACe (Punto General de Entrada de Facturas de la Administración del Estado) en formato Facturae XML 3.2.2, normalmente embebido en un PDF/A-3. IronPDF facilita la generación del contenedor PDF/A con el fichero XML adjunto.


Paso 1: Crear una aplicación ASP.NET Core en Visual Studio

Cree un nuevo proyecto ASP.NET Core. Seleccione la plantilla que corresponda a su arquitectura: Web API, MVC o Blazor Server son las opciones más habituales para aplicaciones de generación de informes de facturación.

Cómo generar informes PDF usando ASP.NET: Figura 1 - Plantilla de aplicación web ASP.NET Core

Configure el nombre y la ubicación del proyecto.

Cómo generar informes PDF usando ASP.NET: Figura 2 - Configuración del proyecto

Seleccione .NET 8 LTS (recomendado para proyectos de producción en 2026) o .NET 9+.

Cómo generar informes PDF usando ASP.NET: Figura 3 - Marco de destino

Cómo generar informes PDF usando ASP.NET: Figura 4 - Aplicación Blazor


Paso 2: Instalar IronPDF desde NuGet

Instale IronPDF a través del administrador de paquetes de Visual Studio:

Cómo generar informes PDF usando ASP.NET: Figura 5 - IronPDF

O desde la Galería NuGet:

Cómo generar informes PDF usando ASP.NET: Figura 6 - Galería NuGet

dotnet add package IronPdf
dotnet add package IronPdf
SHELL

Paso 3: Diseñar el informe como documento HTML con elementos de cumplimiento español

Los informes de facturación conformes con VeriFactu deben incluir en su estructura HTML:

  1. La leyenda VERI*FACTU (con asterisco, preservada verbatim)
  2. El código QR que enlaza al endpoint de verificación de la AEAT
  3. El texto Factura verificable en la sede electrónica de la AEAT

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <style>
        body { font-family: Arial, sans-serif; font-size: 10pt; }
        .factura-header { display: flex; justify-content: space-between; align-items: flex-start; }
        .datos-emisor { flex: 2; }
        .verifactu-block { flex: 1; text-align: right; }
        .verifactu-legend { font-weight: bold; font-size: 9pt; color: #000; }
        .qr-aeat { width: 80px; height: 80px; display: block; margin-left: auto; }
        .tabla-lineas { width: 100%; border-collapse: collapse; margin-top: 20px; }
        .tabla-lineas th, .tabla-lineas td { border: 1px solid #ccc; padding: 4px 8px; }
        .totales { text-align: right; margin-top: 10px; }
        .pie-factura { margin-top: 30px; font-size: 8pt; color: #555; }
    </style>
</head>
<body>
    <div class="factura-header">
        <div class="datos-emisor">
            <h2>Mi Empresa S.L.</h2>
            <p>NIF: B12345678<br>
            Calle Ejemplo, 1 — 28001 Madrid<br>
            facturacion@miempresa.com</p>
        </div>
        <div class="verifactu-block">

            <img class="qr-aeat" src="data:image/png;base64,@Model.QrAeatBase64" 
                 alt="Código QR verificación AEAT" />
            <p class="verifactu-legend">VERI*FACTU</p>
            <p style="font-size:7pt;">Factura verificable en la sede electrónica de la AEAT</p>
        </div>
    </div>

    <hr/>

    <table style="width:100%">
        <tr>
            <td><strong>Factura Nº:</strong> @Model.NumeroFactura</td>
            <td><strong>Fecha:</strong> @Model.Fecha.ToString("dd/MM/yyyy")</td>
            <td><strong>NIF Destinatario:</strong> @Model.NifDestinatario</td>
        </tr>
    </table>

    <table class="tabla-lineas">
        <thead>
            <tr><th>Descripción</th><th>Cantidad</th><th>Precio</th><th>IVA</th><th>Total</th></tr>
        </thead>
        <tbody>
            @foreach (var linea in Model.Lineas)
            {
                <tr>
                    <td>@linea.Descripcion</td>
                    <td style="text-align:right">@linea.Cantidad</td>
                    <td style="text-align:right">@linea.PrecioUnitario.ToString("N2") €</td>
                    <td style="text-align:right">@linea.TipoIva%</td>
                    <td style="text-align:right">@linea.Total.ToString("N2") €</td>
                </tr>
            }
        </tbody>
    </table>

    <div class="totales">
        <p><strong>Base imponible:</strong> @Model.BaseImponible.ToString("N2") €</p>
        <p><strong>IVA (21%):</strong> @Model.CuotaIva.ToString("N2") €</p>
        <p><strong>Total factura:</strong> @Model.TotalFactura.ToString("N2") €</p>
    </div>

    <div class="pie-factura">
        <p>Huella: @Model.HuellaEncadenada | Fecha registro: @Model.FechaRegistro</p>
    </div>
</body>
</html>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <style>
        body { font-family: Arial, sans-serif; font-size: 10pt; }
        .factura-header { display: flex; justify-content: space-between; align-items: flex-start; }
        .datos-emisor { flex: 2; }
        .verifactu-block { flex: 1; text-align: right; }
        .verifactu-legend { font-weight: bold; font-size: 9pt; color: #000; }
        .qr-aeat { width: 80px; height: 80px; display: block; margin-left: auto; }
        .tabla-lineas { width: 100%; border-collapse: collapse; margin-top: 20px; }
        .tabla-lineas th, .tabla-lineas td { border: 1px solid #ccc; padding: 4px 8px; }
        .totales { text-align: right; margin-top: 10px; }
        .pie-factura { margin-top: 30px; font-size: 8pt; color: #555; }
    </style>
</head>
<body>
    <div class="factura-header">
        <div class="datos-emisor">
            <h2>Mi Empresa S.L.</h2>
            <p>NIF: B12345678<br>
            Calle Ejemplo, 1 — 28001 Madrid<br>
            facturacion@miempresa.com</p>
        </div>
        <div class="verifactu-block">

            <img class="qr-aeat" src="data:image/png;base64,@Model.QrAeatBase64" 
                 alt="Código QR verificación AEAT" />
            <p class="verifactu-legend">VERI*FACTU</p>
            <p style="font-size:7pt;">Factura verificable en la sede electrónica de la AEAT</p>
        </div>
    </div>

    <hr/>

    <table style="width:100%">
        <tr>
            <td><strong>Factura Nº:</strong> @Model.NumeroFactura</td>
            <td><strong>Fecha:</strong> @Model.Fecha.ToString("dd/MM/yyyy")</td>
            <td><strong>NIF Destinatario:</strong> @Model.NifDestinatario</td>
        </tr>
    </table>

    <table class="tabla-lineas">
        <thead>
            <tr><th>Descripción</th><th>Cantidad</th><th>Precio</th><th>IVA</th><th>Total</th></tr>
        </thead>
        <tbody>
            @foreach (var linea in Model.Lineas)
            {
                <tr>
                    <td>@linea.Descripcion</td>
                    <td style="text-align:right">@linea.Cantidad</td>
                    <td style="text-align:right">@linea.PrecioUnitario.ToString("N2") €</td>
                    <td style="text-align:right">@linea.TipoIva%</td>
                    <td style="text-align:right">@linea.Total.ToString("N2") €</td>
                </tr>
            }
        </tbody>
    </table>

    <div class="totales">
        <p><strong>Base imponible:</strong> @Model.BaseImponible.ToString("N2") €</p>
        <p><strong>IVA (21%):</strong> @Model.CuotaIva.ToString("N2") €</p>
        <p><strong>Total factura:</strong> @Model.TotalFactura.ToString("N2") €</p>
    </div>

    <div class="pie-factura">
        <p>Huella: @Model.HuellaEncadenada | Fecha registro: @Model.FechaRegistro</p>
    </div>
</body>
</html>
HTML

El motor Chromium de IronPDF renderiza correctamente el CSS Flexbox utilizado en el encabezado de la factura. Otros generadores de PDF basados en motores obsoletos (IE) fallan en este tipo de maquetación.


Paso 4: Generar el informe PDF con IronPDF

Generación básica de informe VeriFactu

using IronPdf;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class FacturasController : ControllerBase
{
    [HttpGet("generar/{id}")]
    public IActionResult GenerarFacturaPdf(int id)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        // Obtener datos de la factura (incluyendo código QR AEAT en base64)
        var modeloFactura = ObtenerModeloFactura(id);

        // Renderizar la vista Razor a HTML
        var renderer = new ChromePdfRenderer();

        // Configurar para facturas A4
        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 15;
        renderer.RenderingOptions.MarginRight = 15;

        // Generar HTML de la factura (en producción, usar Razor View Engine)
        string htmlFactura = RenderizarPlantillaFactura(modeloFactura);

        var pdf = renderer.RenderHtmlAsPdf(htmlFactura);

        // Devolver el PDF directamente al cliente
        return File(pdf.BinaryData, "application/pdf", 
            $"factura_{modeloFactura.NumeroFactura}.pdf");
    }

    private string RenderizarPlantillaFactura(ModeloFactura modelo)
    {
        // En una aplicación real, usar IViewRenderService para renderizar Razor Views
        // o Razor Pages a HTML string
        return $@"<html>...</html>"; // Ver plantilla completa en Paso 3
    }

    private ModeloFactura ObtenerModeloFactura(int id)
    {
        // Obtener de base de datos
        return new ModeloFactura();
    }
}
using IronPdf;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class FacturasController : ControllerBase
{
    [HttpGet("generar/{id}")]
    public IActionResult GenerarFacturaPdf(int id)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        // Obtener datos de la factura (incluyendo código QR AEAT en base64)
        var modeloFactura = ObtenerModeloFactura(id);

        // Renderizar la vista Razor a HTML
        var renderer = new ChromePdfRenderer();

        // Configurar para facturas A4
        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 15;
        renderer.RenderingOptions.MarginRight = 15;

        // Generar HTML de la factura (en producción, usar Razor View Engine)
        string htmlFactura = RenderizarPlantillaFactura(modeloFactura);

        var pdf = renderer.RenderHtmlAsPdf(htmlFactura);

        // Devolver el PDF directamente al cliente
        return File(pdf.BinaryData, "application/pdf", 
            $"factura_{modeloFactura.NumeroFactura}.pdf");
    }

    private string RenderizarPlantillaFactura(ModeloFactura modelo)
    {
        // En una aplicación real, usar IViewRenderService para renderizar Razor Views
        // o Razor Pages a HTML string
        return $@"<html>...</html>"; // Ver plantilla completa en Paso 3
    }

    private ModeloFactura ObtenerModeloFactura(int id)
    {
        // Obtener de base de datos
        return new ModeloFactura();
    }
}
Imports IronPdf
Imports Microsoft.AspNetCore.Mvc

<ApiController>
<Route("api/[controller]")>
Public Class FacturasController
    Inherits ControllerBase

    <HttpGet("generar/{id}")>
    Public Function GenerarFacturaPdf(id As Integer) As IActionResult
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"

        ' Obtener datos de la factura (incluyendo código QR AEAT en base64)
        Dim modeloFactura = ObtenerModeloFactura(id)

        ' Renderizar la vista Razor a HTML
        Dim renderer = New ChromePdfRenderer()

        ' Configurar para facturas A4
        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
        renderer.RenderingOptions.MarginTop = 10
        renderer.RenderingOptions.MarginBottom = 10
        renderer.RenderingOptions.MarginLeft = 15
        renderer.RenderingOptions.MarginRight = 15

        ' Generar HTML de la factura (en producción, usar Razor View Engine)
        Dim htmlFactura As String = RenderizarPlantillaFactura(modeloFactura)

        Dim pdf = renderer.RenderHtmlAsPdf(htmlFactura)

        ' Devolver el PDF directamente al cliente
        Return File(pdf.BinaryData, "application/pdf", $"factura_{modeloFactura.NumeroFactura}.pdf")
    End Function

    Private Function RenderizarPlantillaFactura(modelo As ModeloFactura) As String
        ' En una aplicación real, usar IViewRenderService para renderizar Razor Views
        ' o Razor Pages a HTML string
        Return "<html>...</html>" ' Ver plantilla completa en Paso 3
    End Function

    Private Function ObtenerModeloFactura(id As Integer) As ModeloFactura
        ' Obtener de base de datos
        Return New ModeloFactura()
    End Function
End Class
$vbLabelText   $csharpLabel

Explicación del código

  • ChromePdfRenderer: convierte el HTML de la plantilla de factura a PDF usando el motor Chromium, garantizando texto real seleccionable — esencial para la indexación por sistemas AEAT.
  • RenderingOptions.PaperSize: configura el tamaño A4 estándar para facturas en España.
  • pdf.BinaryData: devuelve el PDF como array de bytes para enviarlo directamente como respuesta HTTP.

Resultado

Cómo generar informes PDF usando ASP.NET: Figura 7 - Generador de informes

Cómo generar informes PDF usando ASP.NET: Figura 8 - Salida PDF


Paso 5: Casos de uso avanzados para el ecosistema español

Firma PAdES para archivado conforme a LOPDGDD y eIDAS

Las facturas electrónicas deben conservarse con garantías de integridad. La firma PAdES-LTV permite el archivado a largo plazo conforme a eIDAS y LOPDGDD:

using IronPdf;
using IronPdf.Signing;

public class GeneradorFacturasConFirma
{
    public byte[] GenerarYFirmarFactura(string htmlFactura, string rutaCertificado, string passwordCert)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(htmlFactura);

        // Aplicar firma PAdES con certificado FNMT o equivalente
        var firma = new PdfSignature(rutaCertificado, passwordCert)
        {
            SigningReason = "Factura electrónica — archivado conforme LOPDGDD/eIDAS",
            SigningContact = "facturacion@miempresa.com",
            SigningLocation = "Madrid, España"
        };

        pdf.Sign(firma);

        return pdf.BinaryData;
    }
}
using IronPdf;
using IronPdf.Signing;

public class GeneradorFacturasConFirma
{
    public byte[] GenerarYFirmarFactura(string htmlFactura, string rutaCertificado, string passwordCert)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(htmlFactura);

        // Aplicar firma PAdES con certificado FNMT o equivalente
        var firma = new PdfSignature(rutaCertificado, passwordCert)
        {
            SigningReason = "Factura electrónica — archivado conforme LOPDGDD/eIDAS",
            SigningContact = "facturacion@miempresa.com",
            SigningLocation = "Madrid, España"
        };

        pdf.Sign(firma);

        return pdf.BinaryData;
    }
}
Imports IronPdf
Imports IronPdf.Signing

Public Class GeneradorFacturasConFirma
    Public Function GenerarYFirmarFactura(htmlFactura As String, rutaCertificado As String, passwordCert As String) As Byte()
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"

        Dim renderer As New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf(htmlFactura)

        ' Aplicar firma PAdES con certificado FNMT o equivalente
        Dim firma As New PdfSignature(rutaCertificado, passwordCert) With {
            .SigningReason = "Factura electrónica — archivado conforme LOPDGDD/eIDAS",
            .SigningContact = "facturacion@miempresa.com",
            .SigningLocation = "Madrid, España"
        }

        pdf.Sign(firma)

        Return pdf.BinaryData
    End Function
End Class
$vbLabelText   $csharpLabel

Generación de informe de factura para TicketBAI (País Vasco)

Para clientes del País Vasco, el PDF de la factura se genera después de que el XML TicketBAI haya sido firmado con XAdES y registrado en la hacienda foral correspondiente:

public class GeneradorFacturasTicketBai
{
    // Genera el PDF de la factura TicketBAI tras el registro foral
    public byte[] GenerarPdfPostRegistro(
        string htmlFactura,
        string provinciaForal, // "Bizkaia", "Gipuzkoa" o "Araba"
        string identificadorTicketBai)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        // Añadir al HTML el identificador TicketBAI del registro foral
        string htmlConTicketBai = htmlFactura
            .Replace("{{TBAI_ID}}", identificadorTicketBai)
            .Replace("{{PROVINCIA_FORAL}}", provinciaForal);

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(htmlConTicketBai);

        // Para TicketBAI, la firma PAdES del PDF es opcional pero recomendada
        // La firma obligatoria XAdES ya está en el XML TicketBAI

        return pdf.BinaryData;
    }
}
public class GeneradorFacturasTicketBai
{
    // Genera el PDF de la factura TicketBAI tras el registro foral
    public byte[] GenerarPdfPostRegistro(
        string htmlFactura,
        string provinciaForal, // "Bizkaia", "Gipuzkoa" o "Araba"
        string identificadorTicketBai)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        // Añadir al HTML el identificador TicketBAI del registro foral
        string htmlConTicketBai = htmlFactura
            .Replace("{{TBAI_ID}}", identificadorTicketBai)
            .Replace("{{PROVINCIA_FORAL}}", provinciaForal);

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(htmlConTicketBai);

        // Para TicketBAI, la firma PAdES del PDF es opcional pero recomendada
        // La firma obligatoria XAdES ya está en el XML TicketBAI

        return pdf.BinaryData;
    }
}
Public Class GeneradorFacturasTicketBai
    ' Genera el PDF de la factura TicketBAI tras el registro foral
    Public Function GenerarPdfPostRegistro(
        htmlFactura As String,
        provinciaForal As String, ' "Bizkaia", "Gipuzkoa" o "Araba"
        identificadorTicketBai As String) As Byte()

        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"

        ' Añadir al HTML el identificador TicketBAI del registro foral
        Dim htmlConTicketBai As String = htmlFactura _
            .Replace("{{TBAI_ID}}", identificadorTicketBai) _
            .Replace("{{PROVINCIA_FORAL}}", provinciaForal)

        Dim renderer As New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf(htmlConTicketBai)

        ' Para TicketBAI, la firma PAdES del PDF es opcional pero recomendada
        ' La firma obligatoria XAdES ya está en el XML TicketBAI

        Return pdf.BinaryData
    End Function
End Class
$vbLabelText   $csharpLabel

Generación de informe en lote para cierre mensual y SII

El SII (Suministro Inmediato de Información) requiere que las grandes empresas comuniquen sus libros de registro a la AEAT. Los ISVs que generan informes para sistemas SII frecuentemente necesitan procesar lotes de facturas:

public class GeneradorLoteFacturas
{
    public async Task<byte[]> GenerarInformeResumenMensual(
        List<ModeloFactura> facturas,
        int anio, int mes)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        var renderer = new ChromePdfRenderer();
        var pdfsIndividuales = new List<PdfDocument>();

        foreach (var factura in facturas)
        {
            string html = RenderizarPlantillaFactura(factura);
            var pdfFactura = renderer.RenderHtmlAsPdf(html);
            pdfsIndividuales.Add(pdfFactura);
        }

        // Fusionar todas las facturas del mes en un único PDF
        var informeMensual = PdfDocument.Merge(pdfsIndividuales.ToArray());

        informeMensual.SaveAs($"informe_sii_{anio}_{mes:D2}.pdf");
        return informeMensual.BinaryData;
    }

    private string RenderizarPlantillaFactura(ModeloFactura modelo)
    {
        return string.Empty; // Implementación con Razor View Engine
    }
}
public class GeneradorLoteFacturas
{
    public async Task<byte[]> GenerarInformeResumenMensual(
        List<ModeloFactura> facturas,
        int anio, int mes)
    {
        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

        var renderer = new ChromePdfRenderer();
        var pdfsIndividuales = new List<PdfDocument>();

        foreach (var factura in facturas)
        {
            string html = RenderizarPlantillaFactura(factura);
            var pdfFactura = renderer.RenderHtmlAsPdf(html);
            pdfsIndividuales.Add(pdfFactura);
        }

        // Fusionar todas las facturas del mes en un único PDF
        var informeMensual = PdfDocument.Merge(pdfsIndividuales.ToArray());

        informeMensual.SaveAs($"informe_sii_{anio}_{mes:D2}.pdf");
        return informeMensual.BinaryData;
    }

    private string RenderizarPlantillaFactura(ModeloFactura modelo)
    {
        return string.Empty; // Implementación con Razor View Engine
    }
}
Imports System.Collections.Generic
Imports System.Threading.Tasks
Imports IronPdf

Public Class GeneradorLoteFacturas
    Public Async Function GenerarInformeResumenMensual(
        facturas As List(Of ModeloFactura),
        anio As Integer, mes As Integer) As Task(Of Byte())

        IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"

        Dim renderer = New ChromePdfRenderer()
        Dim pdfsIndividuales = New List(Of PdfDocument)()

        For Each factura In facturas
            Dim html As String = RenderizarPlantillaFactura(factura)
            Dim pdfFactura = renderer.RenderHtmlAsPdf(html)
            pdfsIndividuales.Add(pdfFactura)
        Next

        ' Fusionar todas las facturas del mes en un único PDF
        Dim informeMensual = PdfDocument.Merge(pdfsIndividuales.ToArray())

        informeMensual.SaveAs($"informe_sii_{anio}_{mes:D2}.pdf")
        Return informeMensual.BinaryData
    End Function

    Private Function RenderizarPlantillaFactura(modelo As ModeloFactura) As String
        Return String.Empty ' Implementación con Razor View Engine
    End Function
End Class
$vbLabelText   $csharpLabel

Configuración de licencia en ASP.NET Core

Coloque la clave de licencia de IronPDF en el fichero appsettings.json de su aplicación:

{
  "IronPdf.LicenseKey": "your license key"
}

O configúrela programáticamente en Program.cs:

var builder = WebApplication.CreateBuilder(args);
IronPdf.License.LicenseKey = builder.Configuration["IronPdf:LicenseKey"]
    ?? throw new InvalidOperationException("IronPDF license key not configured");
var builder = WebApplication.CreateBuilder(args);
IronPdf.License.LicenseKey = builder.Configuration["IronPdf:LicenseKey"]
    ?? throw new InvalidOperationException("IronPDF license key not configured");
Imports IronPdf

Dim builder = WebApplication.CreateBuilder(args)
IronPdf.License.LicenseKey = If(builder.Configuration("IronPdf:LicenseKey"), Throw New InvalidOperationException("IronPDF license key not configured"))
$vbLabelText   $csharpLabel

Puede obtener una clave de prueba gratuita sin necesidad de tarjeta de crédito en la página de licencias de IronPDF.


Herramientas de informes habituales en ASP.NET Core (contexto ecosistema español)

Los generadores de informes de terceros (SSRS, DevExpress Reporting, Syncfusion, Telerik Reporting, GrapeCity ActiveReports, Crystal Reports, Stimulsoft) producen sus salidas en HTML o en formatos propietarios. IronPDF actúa como la capa de generación PDF final que transforma esas salidas en documentos conformes con los requisitos del ecosistema español: texto seleccionable real, capacidad de firma PAdES, y maquetación CSS3 para los elementos de cumplimiento (QR AEAT, leyenda VERI*FACTU).

Al seleccionar la combinación de herramientas para su proyecto, considere:

  • SSRS + IronPDF: SSRS genera el HTML del informe, IronPDF lo convierte a PDF con firma
  • Razor Views + IronPDF: solución directa para equipos ASP.NET Core — mayor control sobre el HTML de la factura
  • DevExpress / Syncfusion + IronPDF: combina el diseñador visual con la generación PDF conforme

Conclusión

ASP.NET Core con IronPDF es la base técnica para sistemas de generación de informes de facturación en España que deben ser conformes con VeriFactu (AEAT QR, leyenda VERI*FACTU, huella encadenada), TicketBAI (firma XAdES foral en Bizkaia, Gipuzkoa y Araba), FACe (Facturae 3.2.2 en PDF/A-3) y el archivado conforme a LOPDGDD y eIDAS (firma PAdES-LTV).

IronPDF aporta el motor de renderizado Chromium que garantiza texto PDF real seleccionable, el soporte CSS3 completo que permite las plantillas de factura modernas, y la API de firma PAdES que integra la cadena de certificados FNMT. Inicie la evaluación técnica con la prueba gratuita de IronPDF.

Preguntas Frecuentes

¿Cómo se genera un informe de factura conforme con VeriFactu en ASP.NET Core?

Se usa ChromePdfRenderer de IronPDF para convertir la plantilla HTML de la factura a PDF. La plantilla debe incluir el código QR AEAT (generado con IronQR), la leyenda VERI*FACTU con asterisco, y el texto 'Factura verificable en la sede electrónica de la AEAT'. El motor Chromium garantiza texto real seleccionable.

¿Cómo se manejan las tres variantes forales de TicketBAI en ASP.NET Core?

Cada factura para el País Vasco se genera tras el registro del XML TicketBAI firmado con XAdES en la hacienda foral correspondiente (bizkaia.eus, gipuzkoa.eus o araba.eus). IronPDF genera el PDF de presentación con el identificador TicketBAI incluido. Para la firma PAdES del PDF, el SigningLocation se configura con la provincia foral.

¿Qué diferencia hay entre generar informes para VeriFactu vs Facturae (FACe)?

Para VeriFactu, el PDF debe incluir QR AEAT y leyenda VERI*FACTU. Para FACe (B2G), el formato es Facturae XML 3.2.2, normalmente embebido en un contenedor PDF/A-3. IronPDF soporta ambos casos: generación de PDFs con elementos VeriFactu y generación de contenedores PDF/A para Facturae.

¿Cómo se firma un informe PDF para archivado conforme a LOPDGDD?

Se usa PdfSignature de IronPDF con un certificado FNMT o equivalente reconocido por la AEAT. La firma PAdES-LTV garantiza la validez a largo plazo del documento archivado, conforme a los requisitos de integridad de LOPDGDD y eIDAS.

Jacob Mellor, Director de Tecnología @ Team Iron
Director de Tecnología

Jacob Mellor es Director de Tecnología de Iron Software y un ingeniero visionario pionero en la tecnología C# PDF. Como desarrollador original de la base de código principal de Iron Software, ha dado forma a la arquitectura de productos de la empresa desde su creación, ...

Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame