Saltar al pie de página
USANDO IRONXL

SII AEAT: Tabla Dinámica Excel C# con IronXL sin Office | Modelo 303

Trabajar programáticamente con una tabla dinámica de Excel es un requisito común en aplicaciones empresariales que necesitan analizar y calcular datos fuente. En España, este escenario es especialmente relevante para los equipos de cumplimiento tributario que deben conciliar operaciones para el SII (Suministro Inmediato de Información), generar los modelos 303, 347 y 390 de la AEAT, o preparar los informes prudenciales que exige el Banco de España y la CNMV. Si bien el uso tradicional del Interop de Excel de Microsoft ha sido el método habitual para crear una tabla dinámica en un archivo de Excel, soluciones modernas como IronXL ofrecen ventajas significativas. Esta guía detalla ambos métodos con ejemplos prácticos para ayudarte a crear una tabla dinámica en Excel usando el Interop de C# o elegir una mejor alternativa — ideal para flujos de trabajo de librería Excel C# SII AEAT.

Entendiendo los dos enfoques

¿Qué es la interoperabilidad de Excel?

Excel Interop utiliza COM (Modelo de Objeto Componente) para controlar Microsoft Excel directamente a través de C#. Requiere que Office esté instalado en el sistema y esencialmente automatiza Excel como si un usuario estuviera interactuando con la aplicación. Cada hoja de cálculo, libro de trabajo y celda se convierte en un objeto que puedes manipular a través del código.

Este requisito de instalación de Office es un obstáculo crítico para los equipos de cumplimiento en España: los servidores de preparación del SII y los pipelines de AEAT modelo 303 suelen correr en Linux o contenedores Docker donde Microsoft Excel no puede instalarse.

¿Qué es IronXL?

IronXL es una biblioteca .NET independiente que puede leer, editar y crear archivos de Excel sin requerir Microsoft Office. Funciona en Windows, Linux, macOS y contenedores Docker, lo que lo hace ideal para escenarios modernos de implementación. Puedes abrir, guardar y exportar datos sin la sobrecarga del Interop de COM.

Para los desarrolladores que trabajan en entornos de cumplimiento tributario español, la capacidad de IronXL de funcionar en Linux/Docker sin Office resulta decisiva: permite preparar ficheros SII para el envío a la AEAT, generar archivos XLSX del modelo 347 en servidores cloud sin licencias de Office, y exportar informes al Banco de España y la CNMV en entornos contenedorizados. La obligación de datos mínimos que impone la LOPDGDD también se satisface mejor con IronXL, ya que permite exportar únicamente las columnas requeridas — sin arrastrar datos personales innecesarios.

Configuración de su entorno

Para la interoperabilidad de Excel

Install-Package Microsoft.Office.Interop.Excel

Para IronXL

Install-Package IronXL.Excel

Alternativamente, usa la interfaz de usuario de NuGet Package Manager buscando "IronXL.Excel" y haciendo clic en instalar. También puedes instalar a través de la CLI de .NET con argumentos de comando o referenciarlo directamente desde GitHub.

Ambas bibliotecas están disponibles a través de NuGet. Ten en cuenta que Excel Interop requiere una instalación completa de Microsoft Office, mientras que IronXL opera de manera independiente. Antes de continuar, asegúrate de que tu sistema cumpla con los requisitos.

Crear una tabla dinámica de Excel con C# Interop para conciliar operaciones SII

Aquí tienes un ejemplo completo que muestra cómo crear una tabla dinámica programáticamente usando el enfoque tradicional de Interop. Imagina que necesitas conciliar las facturas emitidas recibidas del sistema SII para validar las bases imponibles declaradas en el modelo 303:

using Excel = Microsoft.Office.Interop.Excel;
class Program
{
    static void Main(string[] args)
    {
        // Create Excel application instance
        var excelApp = new Excel.Application();
        var workbook = excelApp.Workbooks.Add();
                    var dataSheet = (Excel.Worksheet)workbook.Worksheets[1];
            var pivotSheet = (Excel.Worksheet)workbook.Worksheets.Add();
            // Add header row and sample data
            dataSheet.Cells[1, 1] = "Product";
            dataSheet.Cells[1, 2] = "Region";
            dataSheet.Cells[1, 3] = "Sales";
            // ... populate data rows with values
            // Add sample data rows
            dataSheet.Cells[2, 1] = "Laptop";
            dataSheet.Cells[2, 2] = "North";
            dataSheet.Cells[2, 3] = 1200;
            dataSheet.Cells[3, 1] = "Laptop";
            dataSheet.Cells[3, 2] = "South";
            dataSheet.Cells[3, 3] = 1500;
            dataSheet.Cells[4, 1] = "Phone";
            dataSheet.Cells[4, 2] = "North";
            dataSheet.Cells[4, 3] = 800;
            dataSheet.Cells[5, 1] = "Phone";
            dataSheet.Cells[5, 2] = "South";
            dataSheet.Cells[5, 3] = 950;
            dataSheet.Cells[6, 1] = "Tablet";
            dataSheet.Cells[6, 2] = "East";
            dataSheet.Cells[6, 3] = 600;
            dataSheet.Cells[7, 1] = "Tablet";
            dataSheet.Cells[7, 2] = "West";
            dataSheet.Cells[7, 3] = 750;
            dataSheet.Cells[8, 1] = "Monitor";
            dataSheet.Cells[8, 2] = "North";
            dataSheet.Cells[8, 3] = 400;
            dataSheet.Cells[9, 1] = "Monitor";
            dataSheet.Cells[9, 2] = "South";
            dataSheet.Cells[9, 3] = 500;
            dataSheet.Cells[10, 1] = "Keyboard";
            dataSheet.Cells[10, 2] = "East";
            dataSheet.Cells[10, 3] = 300;
            // Create pivot cache from source data range
            Excel.Range dataRange = dataSheet.Range["A1:C10"];
            Excel.PivotCache pivotCache = workbook.PivotCaches().Create(
                Excel.XlPivotTableSourceType.xlDatabase, dataRange);
            // Create PivotTable at specific location
            Excel.PivotTables pivotTables = (Excel.PivotTables)pivotSheet.PivotTables();
            Excel.PivotTable pivotTable = pivotTables.Add(
                pivotCache, pivotSheet.Range["A3"], "SalesPivot");
            // Configure pivot table fields - row and column headers
            ((Excel.PivotField)pivotTable.PivotFields("Product")).Orientation =
                Excel.XlPivotFieldOrientation.xlRowField;
            ((Excel.PivotField)pivotTable.PivotFields("Region")).Orientation =
                Excel.XlPivotFieldOrientation.xlColumnField;
            ((Excel.PivotField)pivotTable.PivotFields("Sales")).Orientation =
                Excel.XlPivotFieldOrientation.xlDataField;
            // Configure grand totals and formatting
            pivotTable.RowGrand = true;
            pivotTable.ColumnGrand = true;
            // Save the Excel file
            workbook.SaveAs("pivot_interop.xlsx");
            workbook.Close();
            excelApp.Quit();
            // Critical: Release COM objects to avoid errors
            #if WINDOWS
            Marshal.ReleaseComObject(pivotTable);
            Marshal.ReleaseComObject(pivotSheet);
            Marshal.ReleaseComObject(dataSheet);
            Marshal.ReleaseComObject(workbook);
            Marshal.ReleaseComObject(excelApp);
            #endif
    }
}
using Excel = Microsoft.Office.Interop.Excel;
class Program
{
    static void Main(string[] args)
    {
        // Create Excel application instance
        var excelApp = new Excel.Application();
        var workbook = excelApp.Workbooks.Add();
                    var dataSheet = (Excel.Worksheet)workbook.Worksheets[1];
            var pivotSheet = (Excel.Worksheet)workbook.Worksheets.Add();
            // Add header row and sample data
            dataSheet.Cells[1, 1] = "Product";
            dataSheet.Cells[1, 2] = "Region";
            dataSheet.Cells[1, 3] = "Sales";
            // ... populate data rows with values
            // Add sample data rows
            dataSheet.Cells[2, 1] = "Laptop";
            dataSheet.Cells[2, 2] = "North";
            dataSheet.Cells[2, 3] = 1200;
            dataSheet.Cells[3, 1] = "Laptop";
            dataSheet.Cells[3, 2] = "South";
            dataSheet.Cells[3, 3] = 1500;
            dataSheet.Cells[4, 1] = "Phone";
            dataSheet.Cells[4, 2] = "North";
            dataSheet.Cells[4, 3] = 800;
            dataSheet.Cells[5, 1] = "Phone";
            dataSheet.Cells[5, 2] = "South";
            dataSheet.Cells[5, 3] = 950;
            dataSheet.Cells[6, 1] = "Tablet";
            dataSheet.Cells[6, 2] = "East";
            dataSheet.Cells[6, 3] = 600;
            dataSheet.Cells[7, 1] = "Tablet";
            dataSheet.Cells[7, 2] = "West";
            dataSheet.Cells[7, 3] = 750;
            dataSheet.Cells[8, 1] = "Monitor";
            dataSheet.Cells[8, 2] = "North";
            dataSheet.Cells[8, 3] = 400;
            dataSheet.Cells[9, 1] = "Monitor";
            dataSheet.Cells[9, 2] = "South";
            dataSheet.Cells[9, 3] = 500;
            dataSheet.Cells[10, 1] = "Keyboard";
            dataSheet.Cells[10, 2] = "East";
            dataSheet.Cells[10, 3] = 300;
            // Create pivot cache from source data range
            Excel.Range dataRange = dataSheet.Range["A1:C10"];
            Excel.PivotCache pivotCache = workbook.PivotCaches().Create(
                Excel.XlPivotTableSourceType.xlDatabase, dataRange);
            // Create PivotTable at specific location
            Excel.PivotTables pivotTables = (Excel.PivotTables)pivotSheet.PivotTables();
            Excel.PivotTable pivotTable = pivotTables.Add(
                pivotCache, pivotSheet.Range["A3"], "SalesPivot");
            // Configure pivot table fields - row and column headers
            ((Excel.PivotField)pivotTable.PivotFields("Product")).Orientation =
                Excel.XlPivotFieldOrientation.xlRowField;
            ((Excel.PivotField)pivotTable.PivotFields("Region")).Orientation =
                Excel.XlPivotFieldOrientation.xlColumnField;
            ((Excel.PivotField)pivotTable.PivotFields("Sales")).Orientation =
                Excel.XlPivotFieldOrientation.xlDataField;
            // Configure grand totals and formatting
            pivotTable.RowGrand = true;
            pivotTable.ColumnGrand = true;
            // Save the Excel file
            workbook.SaveAs("pivot_interop.xlsx");
            workbook.Close();
            excelApp.Quit();
            // Critical: Release COM objects to avoid errors
            #if WINDOWS
            Marshal.ReleaseComObject(pivotTable);
            Marshal.ReleaseComObject(pivotSheet);
            Marshal.ReleaseComObject(dataSheet);
            Marshal.ReleaseComObject(workbook);
            Marshal.ReleaseComObject(excelApp);
            #endif
    }
}
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices

Class Program
    Shared Sub Main(ByVal args() As String)
        ' Create Excel application instance
        Dim excelApp As New Excel.Application()
        Dim workbook As Excel.Workbook = excelApp.Workbooks.Add()
        Dim dataSheet As Excel.Worksheet = CType(workbook.Worksheets(1), Excel.Worksheet)
        Dim pivotSheet As Excel.Worksheet = CType(workbook.Worksheets.Add(), Excel.Worksheet)

        ' Add header row and sample data
        dataSheet.Cells(1, 1) = "Product"
        dataSheet.Cells(1, 2) = "Region"
        dataSheet.Cells(1, 3) = "Sales"
        ' ... populate data rows with values
        ' Add sample data rows
        dataSheet.Cells(2, 1) = "Laptop"
        dataSheet.Cells(2, 2) = "North"
        dataSheet.Cells(2, 3) = 1200
        dataSheet.Cells(3, 1) = "Laptop"
        dataSheet.Cells(3, 2) = "South"
        dataSheet.Cells(3, 3) = 1500
        dataSheet.Cells(4, 1) = "Phone"
        dataSheet.Cells(4, 2) = "North"
        dataSheet.Cells(4, 3) = 800
        dataSheet.Cells(5, 1) = "Phone"
        dataSheet.Cells(5, 2) = "South"
        dataSheet.Cells(5, 3) = 950
        dataSheet.Cells(6, 1) = "Tablet"
        dataSheet.Cells(6, 2) = "East"
        dataSheet.Cells(6, 3) = 600
        dataSheet.Cells(7, 1) = "Tablet"
        dataSheet.Cells(7, 2) = "West"
        dataSheet.Cells(7, 3) = 750
        dataSheet.Cells(8, 1) = "Monitor"
        dataSheet.Cells(8, 2) = "North"
        dataSheet.Cells(8, 3) = 400
        dataSheet.Cells(9, 1) = "Monitor"
        dataSheet.Cells(9, 2) = "South"
        dataSheet.Cells(9, 3) = 500
        dataSheet.Cells(10, 1) = "Keyboard"
        dataSheet.Cells(10, 2) = "East"
        dataSheet.Cells(10, 3) = 300

        ' Create pivot cache from source data range
        Dim dataRange As Excel.Range = dataSheet.Range("A1:C10")
        Dim pivotCache As Excel.PivotCache = workbook.PivotCaches().Create(Excel.XlPivotTableSourceType.xlDatabase, dataRange)

        ' Create PivotTable at specific location
        Dim pivotTables As Excel.PivotTables = CType(pivotSheet.PivotTables(), Excel.PivotTables)
        Dim pivotTable As Excel.PivotTable = pivotTables.Add(pivotCache, pivotSheet.Range("A3"), "SalesPivot")

        ' Configure pivot table fields - row and column headers
        CType(pivotTable.PivotFields("Product"), Excel.PivotField).Orientation = Excel.XlPivotFieldOrientation.xlRowField
        CType(pivotTable.PivotFields("Region"), Excel.PivotField).Orientation = Excel.XlPivotFieldOrientation.xlColumnField
        CType(pivotTable.PivotFields("Sales"), Excel.PivotField).Orientation = Excel.XlPivotFieldOrientation.xlDataField

        ' Configure grand totals and formatting
        pivotTable.RowGrand = True
        pivotTable.ColumnGrand = True

        ' Save the Excel file
        workbook.SaveAs("pivot_interop.xlsx")
        workbook.Close()
        excelApp.Quit()

        ' Critical: Release COM objects to avoid errors
#If WINDOWS Then
        Marshal.ReleaseComObject(pivotTable)
        Marshal.ReleaseComObject(pivotSheet)
        Marshal.ReleaseComObject(dataSheet)
        Marshal.ReleaseComObject(workbook)
        Marshal.ReleaseComObject(excelApp)
#End If
    End Sub
End Class
$vbLabelText   $csharpLabel

Este código crea una aplicación de Excel, añade una hoja de cálculo con datos fuente incluyendo una fila de encabezado, establece un caché de tabla dinámica, construye el objeto PivotTable y configura la orientación del campo. La sección de limpieza es crítica: no liberar los objetos COM causa pérdidas de memoria. Cada celda, rango y hoja de cálculo deben ser desechados adecuadamente para evitar errores en tiempo de ejecución.

Además, este enfoque requiere Microsoft Office instalado, lo que lo hace inviable en los servidores Linux que suelen gestionar el envío de ficheros XML al SII o la generación de los modelos 347 y 390 de la AEAT.

El enfoque alternativo de IronXL: tabla dinámica para el modelo 303 AEAT

IronXL adopta un enfoque diferente al trabajar directamente con el formato de archivo de Excel. A continuación se muestra cómo crear un libro Excel para el modelo 303 — conciliando las cuotas de IVA devengado y soportado por trimestre sin necesidad de tener Office instalado, lo que resulta especialmente valioso para flujos de trabajo de IronXL genera ficheros SII en servidores Linux o Docker:

using IronXL;
using System.Linq;
class Program 
{
    static void Main(string[] args)
    {
        // Create workbook and add worksheet with data
        WorkBook workbook = WorkBook.Create();
        WorkSheet sheet = workbook.CreateWorkSheet("Operaciones SII");
        // Add header row to define column structure
        sheet["A1"].Value = "NIF Contraparte";
        sheet["B1"].Value = "Tipo Operación";
        sheet["C1"].Value = "Base Imponible (EUR)";
        // Add sample data to cells (operaciones SII 1T)
        sheet["A2"].Value = "B12345678";
        sheet["B2"].Value = "Factura Emitida";
        sheet["C2"].Value = 12500;
        sheet["A3"].Value = "A87654321";
        sheet["B3"].Value = "Factura Emitida";
        sheet["C3"].Value = 8300;
        sheet["A4"].Value = "B12345678";
        sheet["B4"].Value = "Factura Recibida";
        sheet["C4"].Value = 4200;
        sheet["A5"].Value = "C11223344";
        sheet["B5"].Value = "Factura Emitida";
        sheet["C5"].Value = 6750;
        sheet["A6"].Value = "A87654321";
        sheet["B6"].Value = "Factura Recibida";
        sheet["C6"].Value = 2100;
        sheet["A7"].Value = "C11223344";
        sheet["B7"].Value = "Factura Recibida";
        sheet["C7"].Value = 980;
        sheet["A8"].Value = "D55667788";
        sheet["B8"].Value = "Factura Emitida";
        sheet["C8"].Value = 15200;
        sheet["A9"].Value = "D55667788";
        sheet["B9"].Value = "Factura Recibida";
        sheet["C9"].Value = 3400;
        sheet["A10"].Value = "E99001122";
        sheet["B10"].Value = "Factura Emitida";
        sheet["C10"].Value = 7600;
        // Create summary analysis worksheet — modelo 303 AEAT
        var summarySheet = workbook.CreateWorkSheet("Modelo 303");
        // Group and calculate aggregated data
        var data = sheet["A1:C10"].ToDataTable(true);
        var tipoSummary = data.AsEnumerable()
            .GroupBy(row => row.Field<string>("Tipo Operación"))
            .Select((group, index) => new {
                Tipo = group.Key,
                TotalBase = group.Sum(r => Convert.ToDecimal(r["Base Imponible (EUR)"])),
                Count = group.Count(),
                RowIndex = index + 2
            });
        // Write column headers for modelo 303 summary
        summarySheet["A1"].Value = "Resumen Modelo 303 — 1T";
        summarySheet["A2"].Value = "Tipo Operación";
        summarySheet["B2"].Value = "Base Imponible Total (EUR)";
        summarySheet["C2"].Value = "Num. Facturas";
        // Export results to cells
        foreach (var item in tipoSummary)
        {
            summarySheet[$"A{item.RowIndex + 1}"].Value = item.Tipo;
            summarySheet[$"B{item.RowIndex + 1}"].Value = item.TotalBase;
            summarySheet[$"C{item.RowIndex + 1}"].Value = item.Count;
        }
        // Apply number formatting and style
        summarySheet["B:B"].FormatString = "#,##0.00 €";
        // Save the xlsx file — Excel sin Office para declaraciones AEAT
        workbook.SaveAs("modelo_303_1T.xlsx");
    }
}
using IronXL;
using System.Linq;
class Program 
{
    static void Main(string[] args)
    {
        // Create workbook and add worksheet with data
        WorkBook workbook = WorkBook.Create();
        WorkSheet sheet = workbook.CreateWorkSheet("Operaciones SII");
        // Add header row to define column structure
        sheet["A1"].Value = "NIF Contraparte";
        sheet["B1"].Value = "Tipo Operación";
        sheet["C1"].Value = "Base Imponible (EUR)";
        // Add sample data to cells (operaciones SII 1T)
        sheet["A2"].Value = "B12345678";
        sheet["B2"].Value = "Factura Emitida";
        sheet["C2"].Value = 12500;
        sheet["A3"].Value = "A87654321";
        sheet["B3"].Value = "Factura Emitida";
        sheet["C3"].Value = 8300;
        sheet["A4"].Value = "B12345678";
        sheet["B4"].Value = "Factura Recibida";
        sheet["C4"].Value = 4200;
        sheet["A5"].Value = "C11223344";
        sheet["B5"].Value = "Factura Emitida";
        sheet["C5"].Value = 6750;
        sheet["A6"].Value = "A87654321";
        sheet["B6"].Value = "Factura Recibida";
        sheet["C6"].Value = 2100;
        sheet["A7"].Value = "C11223344";
        sheet["B7"].Value = "Factura Recibida";
        sheet["C7"].Value = 980;
        sheet["A8"].Value = "D55667788";
        sheet["B8"].Value = "Factura Emitida";
        sheet["C8"].Value = 15200;
        sheet["A9"].Value = "D55667788";
        sheet["B9"].Value = "Factura Recibida";
        sheet["C9"].Value = 3400;
        sheet["A10"].Value = "E99001122";
        sheet["B10"].Value = "Factura Emitida";
        sheet["C10"].Value = 7600;
        // Create summary analysis worksheet — modelo 303 AEAT
        var summarySheet = workbook.CreateWorkSheet("Modelo 303");
        // Group and calculate aggregated data
        var data = sheet["A1:C10"].ToDataTable(true);
        var tipoSummary = data.AsEnumerable()
            .GroupBy(row => row.Field<string>("Tipo Operación"))
            .Select((group, index) => new {
                Tipo = group.Key,
                TotalBase = group.Sum(r => Convert.ToDecimal(r["Base Imponible (EUR)"])),
                Count = group.Count(),
                RowIndex = index + 2
            });
        // Write column headers for modelo 303 summary
        summarySheet["A1"].Value = "Resumen Modelo 303 — 1T";
        summarySheet["A2"].Value = "Tipo Operación";
        summarySheet["B2"].Value = "Base Imponible Total (EUR)";
        summarySheet["C2"].Value = "Num. Facturas";
        // Export results to cells
        foreach (var item in tipoSummary)
        {
            summarySheet[$"A{item.RowIndex + 1}"].Value = item.Tipo;
            summarySheet[$"B{item.RowIndex + 1}"].Value = item.TotalBase;
            summarySheet[$"C{item.RowIndex + 1}"].Value = item.Count;
        }
        // Apply number formatting and style
        summarySheet["B:B"].FormatString = "#,##0.00 €";
        // Save the xlsx file — Excel sin Office para declaraciones AEAT
        workbook.SaveAs("modelo_303_1T.xlsx");
    }
}
Imports IronXL
Imports System.Linq

Class Program
    Shared Sub Main(args As String())
        ' Create workbook and add worksheet with data
        Dim workbook As WorkBook = WorkBook.Create()
        Dim sheet As WorkSheet = workbook.CreateWorkSheet("Operaciones SII")
        ' Add header row to define column structure
        sheet("A1").Value = "NIF Contraparte"
        sheet("B1").Value = "Tipo Operación"
        sheet("C1").Value = "Base Imponible (EUR)"
        ' Add sample data to cells (operaciones SII 1T)
        sheet("A2").Value = "B12345678"
        sheet("B2").Value = "Factura Emitida"
        sheet("C2").Value = 12500
        sheet("A3").Value = "A87654321"
        sheet("B3").Value = "Factura Emitida"
        sheet("C3").Value = 8300
        sheet("A4").Value = "B12345678"
        sheet("B4").Value = "Factura Recibida"
        sheet("C4").Value = 4200
        sheet("A5").Value = "C11223344"
        sheet("B5").Value = "Factura Emitida"
        sheet("C5").Value = 6750
        sheet("A6").Value = "A87654321"
        sheet("B6").Value = "Factura Recibida"
        sheet("C6").Value = 2100
        sheet("A7").Value = "C11223344"
        sheet("B7").Value = "Factura Recibida"
        sheet("C7").Value = 980
        sheet("A8").Value = "D55667788"
        sheet("B8").Value = "Factura Emitida"
        sheet("C8").Value = 15200
        sheet("A9").Value = "D55667788"
        sheet("B9").Value = "Factura Recibida"
        sheet("C9").Value = 3400
        sheet("A10").Value = "E99001122"
        sheet("B10").Value = "Factura Emitida"
        sheet("C10").Value = 7600
        ' Create summary analysis worksheet — modelo 303 AEAT
        Dim summarySheet = workbook.CreateWorkSheet("Modelo 303")
        ' Group and calculate aggregated data
        Dim data = sheet("A1:C10").ToDataTable(True)
        Dim tipoSummary = data.AsEnumerable() _
            .GroupBy(Function(row) row.Field(Of String)("Tipo Operación")) _
            .Select(Function(group, index) New With {
                .Tipo = group.Key,
                .TotalBase = group.Sum(Function(r) Convert.ToDecimal(r("Base Imponible (EUR)"))),
                .Count = group.Count(),
                .RowIndex = index + 2
            })
        ' Write column headers for modelo 303 summary
        summarySheet("A1").Value = "Resumen Modelo 303 — 1T"
        summarySheet("A2").Value = "Tipo Operación"
        summarySheet("B2").Value = "Base Imponible Total (EUR)"
        summarySheet("C2").Value = "Num. Facturas"
        ' Export results to cells
        For Each item In tipoSummary
            summarySheet($"A{item.RowIndex + 1}").Value = item.Tipo
            summarySheet($"B{item.RowIndex + 1}").Value = item.TotalBase
            summarySheet($"C{item.RowIndex + 1}").Value = item.Count
        Next
        ' Apply number formatting and style
        summarySheet("B:B").FormatString = "#,##0.00 €"
        ' Save the xlsx file — Excel sin Office para declaraciones AEAT
        workbook.SaveAs("modelo_303_1T.xlsx")
    End Sub
End Class
$vbLabelText   $csharpLabel

Este ejemplo de IronXL demuestra cómo crear un libro de trabajo, agregar hojas de cálculo, llenar celdas con datos de operaciones SII y realizar análisis de agregación para el modelo 303. El código agrupa datos por tipo de operación y calcula totales y conteos, generando un informe resumen directamente aprovechable para la declaración trimestral de IVA ante la AEAT. No se necesita gestionar objetos COM y los métodos son colecciones estándar de .NET que manejan automáticamente la memoria.

Este flujo de trabajo funciona igualmente bien para generar los modelos 390 (resumen anual de IVA) y 130 (pagos fraccionados del IRPF para autónomos), así como los reportes prudenciales requeridos por el Banco de España o la CNMV en formato XLSX. Gracias a la compatibilidad de LOPDGDD, solo se exportan las columnas NIF/base imponible requeridas, sin incluir datos personales adicionales.

Resultado

Cómo crear una tabla dinámica de Excel en C#: Figura 6 - Salida de IronXL

Cómo crear una tabla dinámica de Excel en C#: Figura 7 - Resumen de salida

Diferencias y consideraciones clave

Requisitos de implementación

Excel Interop requiere:

  • Instalación de Microsoft Excel con una licencia válida
  • Sistema operativo Windows
  • Permisos y configuraciones COM adecuadas
  • Configuración del servidor para la automatización de Office IronXL requiere:

  • Solo el paquete de biblioteca de IronXL
  • Funciona en cualquier plataforma que soporte .NET
  • No se necesita instalación ni licencia de Office
  • Proceso de implementación simplificado

Para los equipos de cumplimiento tributario en España, la ventaja de IronXL es determinante: los pipelines de preparación de datos para el SII, el modelo 347 (operaciones con terceros superiores a 3.005,06 €) o los informes al Banco de España y la CNMV pueden ejecutarse en contenedores Docker en la nube sin dependencias de Office ni de Windows.

Cómo crear una tabla dinámica de Excel en C#: Figura 8 - Características

Calidad y mantenimiento del código

Interop implica gestionar objetos COM cuidadosamente para evitar pérdidas de memoria y errores. Cada objeto Excel creado debe ser liberado explícitamente usando los métodos correctos. IronXL utiliza objetos estándar de .NET con recolección automática de basura, reduciendo el riesgo de problemas de recursos.

Manejo de errores

Con Interop, los errores a menudo se relacionan con la disponibilidad de Excel, diferencias de versión o fallas de COM. Los errores de IronXL son excepciones estándar de .NET, lo que facilita la depuración. Puedes confiar en patrones de try-catch familiares sin preocuparte por problemas específicos de COM.

Cumplimiento normativo español: TicketBAI, VeriFactu y datos mínimos

TicketBAI y VeriFactu con IronXL

Para las empresas del País Vasco sometidas a TicketBAI (Bizkaia, Gipuzkoa y Araba), IronXL facilita la generación de exportaciones XLSX compatibles con los registros de facturación, que luego se firman y envían al sistema TicketBAI. Del mismo modo, el Real Decreto-Ley 15/2025 (VeriFactu) obliga a generar registros de factura verificables; IronXL puede crear los ficheros XLSX con los datos de registro que se embeben en el QR de la factura VERI*FACTU.

En ambos casos, el cumplimiento de la LOPDGDD exige exportar únicamente las columnas estrictamente necesarias. La API de IronXL permite seleccionar con precisión qué rangos exportar, evitando la inclusión de datos personales innecesarios.

Mejores prácticas y recomendaciones

Elige Excel Interop cuando:

  • Necesitas características exactas de tabla dinámica de Excel con todas las opciones de formato
  • Excel está garantizado para estar disponible en el sistema
  • Trabajando solo en aplicaciones de escritorio de Windows
  • Requisitos de código heredado Elige IronXL cuando:

  • Construyendo aplicaciones de servidor o soluciones web
  • Requiriendo compatibilidad multiplataforma (Linux, Docker, Azure)
  • Preparando ficheros para el SII, modelos 303/347/390/130 de la AEAT, o informes al Banco de España/CNMV
  • Implementando exportaciones TicketBAI o VeriFactu en servidores sin Office
  • Necesitando un rendimiento confiable sin la sobrecarga de COM

Visita la documentación de IronXL para aprender más detalles sobre la implementación. Para preguntas o soporte, contacta al equipo de Iron Software.

Conclusión

Mientras que el Interop de C# proporciona acceso directo para crear funciones de tablas dinámicas en Excel, viene con limitaciones de implementación y complejidad, especialmente en entornos cloud y Linux donde los flujos de trabajo del SII y la AEAT suelen ejecutarse. IronXL ofrece una alternativa moderna que simplifica la manipulación de archivos de Excel proporcionando la flexibilidad para ejecutarse en cualquier lugar donde .NET sea compatible — incluyendo los servidores que gestionan las declaraciones del modelo 303, los ficheros de operaciones del modelo 347, o los informes prudenciales para el Banco de España y la CNMV.

Para los desarrolladores que construyen nuevas aplicaciones o modernizan soluciones de Excel sin Office para declaraciones AEAT, el enfoque de IronXL elimina la sobrecarga de COM Interop mientras proporciona potentes capacidades de manipulación de datos y cumplimiento con la LOPDGDD mediante exportación selectiva de columnas. Ya sea que necesites leer, editar o exportar datos de Excel para el modelo 390, 130 o una exportación TicketBAI, IronXL ofrece una solución más limpia.

Comienza con la prueba gratuita de IronXL para experimentar la diferencia o explora tutoriales para ver más ejemplos. ¿Listo para implementar? Ve opciones de licencia para elegir el paquete adecuado para tu tarea.

Cómo crear una tabla dinámica de Excel en C#: Figura 9 - Licenciamiento

Preguntas Frecuentes

¿Puede IronXL generar ficheros XLSX para el SII y los modelos 303, 347 y 390 de la AEAT sin Office?

Sí. IronXL es una librería Excel C# SII AEAT que funciona en Linux y Docker sin Microsoft Office. Puedes crear libros XLSX con las bases imponibles del modelo 303, las operaciones con terceros del modelo 347, el resumen anual del modelo 390 y los pagos fraccionados del modelo 130, todo mediante código C# ejecutado en servidores cloud o contenedores.

¿Cómo ayuda IronXL al cumplimiento de la LOPDGDD al generar declaraciones para la AEAT?

La LOPDGDD exige minimización de datos: solo deben exportarse las columnas estrictamente necesarias. La API de IronXL permite seleccionar rangos específicos — por ejemplo, solo NIF y base imponible — sin arrastrar datos personales adicionales al fichero XLSX enviado a la AEAT.

¿Es necesario tener instalado Microsoft Excel para usar IronXL?

No, IronXL no requiere que Microsoft Excel esté instalado en tu sistema. Esto lo convierte en la solución ideal para los servidores Linux/Docker que preparan datos del SII, generan ficheros para el Banco de España y la CNMV, o producen exportaciones TicketBAI y VeriFactu.

¿Cuáles son los pasos para crear una tabla dinámica en Excel usando IronXL?

Para crear una tabla dinámica usando IronXL, primero carga tu archivo de Excel, especifica el rango de datos, define los campos de tu tabla dinámica y luego genera la tabla dinámica. La completa API de IronXL hace que este proceso sea sencillo.

¿IronXL admite otras funcionalidades de Excel además de las tablas dinámicas?

Sí, IronXL admite una amplia gama de funcionalidades de Excel, incluyendo la lectura y escritura de archivos de Excel, el formato de celdas y la realización de cálculos, entre otros.

¿Cómo maneja IronXL grandes conjuntos de datos al crear tablas dinámicas?

IronXL está diseñado para manejar eficientemente grandes conjuntos de datos, asegurando la creación rápida y confiable de tablas dinámicas incluso con datos extensos.

¿Puede usarse IronXL en aplicaciones en la nube?

Sí, IronXL puede integrarse en aplicaciones en la nube, proporcionando una solución perfecta para gestionar archivos de Excel en la nube.

¿Qué lenguajes de programación son compatibles con IronXL para crear tablas dinámicas?

IronXL admite principalmente C#, facilitando la creación de tablas dinámicas y otras operaciones de Excel dentro de aplicaciones .NET.

¿Existen tutoriales disponibles para aprender a usar IronXL?

Sí, Iron Software proporciona documentación completa y tutoriales en su sitio web para ayudar a los usuarios a aprender a usar IronXL de manera efectiva.

¿Cuáles son las opciones de licencia disponibles para IronXL?

IronXL ofrece varias opciones de licencia, incluyendo niveles gratuitos y de pago, para acomodar diferentes necesidades y escalas de proyectos.

Curtis Chau
Escritor Técnico

Curtis Chau tiene una licenciatura en Ciencias de la Computación (Carleton University) y se especializa en el desarrollo front-end con experiencia en Node.js, TypeScript, JavaScript y React. Apasionado por crear interfaces de usuario intuitivas y estéticamente agradables, disfruta trabajando con frameworks modernos y creando manuales bien ...

Leer más

Equipo de soporte de Iron

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