Tutorial on how to convert databases to PDF in C# using Spire.XLS for .NET

Exporting database query results to PDF is a common requirement in applications such as reporting, data archiving, and document generation. In these scenarios, SQL query results need to be transformed into structured, readable documents that can be easily shared or printed.

Because database data is inherently tabular, preserving its structure during the export process is essential for maintaining clarity and usability. Without proper layout control, the resulting document can quickly become difficult to read, especially when dealing with large datasets.

This article demonstrates how to convert databases to PDF in C# using Spire.XLS for .NET, including examples on retrieving query results, organizing them into a structured table, and exporting them as a formatted PDF document.

Table of Contents


1. Understanding the Task

Converting database content to PDF typically involves several key steps:

  • Data retrieval: Execute SQL queries and load results into memory
  • Data structuring: Organize query results into a consistent tabular format
  • PDF export: Generate a document that preserves layout and readability

In practice, this workflow is commonly used for generating reports, creating invoices, or archiving query results, where maintaining a clear and structured presentation of data is essential.


2. Convert Database to PDF Using C# (Step-by-Step)

This section provides a complete workflow for converting database query results into a PDF document, including data retrieval, table structuring, formatting, and export.

2.1 Environment Setup

Before implementing the solution, make sure your development environment is ready:

  • .NET environment
    Install Visual Studio or use the .NET CLI with a compatible .NET version (e.g., .NET 6 or later).

  • Database access
    Prepare a SQL Server database (or any relational database) and ensure you have a valid connection string. For modern .NET applications, use the recommended SQL client library:

    dotnet add package Microsoft.Data.SqlClient
    

    This package provides the ADO.NET implementation for SQL Server and replaces the legacy System.Data.SqlClient.

  • Spire.XLS for .NET Install Spire.XLS via NuGet to handle table formatting and PDF export:

    dotnet add package Spire.XLS
    

    You can also download the Spire.XLS for .NET package and add it to your project manually.

Once configured, you can retrieve data from the database and use Spire.XLS to generate and export PDF documents.

2.2 Read Data from Database

The first step is to execute a SQL query and load the results into a DataTable. This structure preserves the schema and data types of the query result, making it suitable for further transformation.

using System.Data;
using Microsoft.Data.SqlClient;

string connectionString = "Server=localhost\\SQLEXPRESS;Database=SalesDB;User ID=demouser;Password=YourPassword;Encrypt=true;TrustServerCertificate=true;";
string query = @"
    SELECT o.OrderID, c.CustomerName, o.OrderDate, o.TotalAmount
    FROM Orders o
    JOIN Customers c ON o.CustomerID = c.CustomerID
    WHERE YEAR(o.OrderDate) = 2026;
";

DataTable dataTable = new DataTable();

using (SqlConnection conn = new SqlConnection(connectionString))
{
    SqlDataAdapter adapter = new SqlDataAdapter(query, conn);
    adapter.Fill(dataTable);
}

This example uses Microsoft.Data.SqlClient, the modern SQL client library for .NET, which is recommended over the legacy System.Data.SqlClient.

The SqlDataAdapter acts as a bridge between the database and in-memory data. It executes the query and fills the DataTable without requiring explicit connection management for reading operations.

In practical scenarios, this step can be extended to include:

  • Parameterized queries to avoid SQL injection
  • Stored procedures for complex data retrieval
  • Data filtering and aggregation directly in SQL

By preparing clean and structured data at this stage, you reduce the complexity of downstream formatting and improve overall performance.

For a similar scenario involving exporting database query results to Excel instead of PDF, you can also refer to this guide: Export Database to Excel in C#.

2.3 Import Data and Export to PDF with Formatting

After retrieving the data, the next step is to map it into a worksheet, apply formatting, and export it as a PDF document. This approach leverages worksheet-based layout control to ensure the output remains structured and readable.

using Spire.Xls;
using System.Drawing;

// Create workbook and worksheet
Workbook workbook = new Workbook();
Worksheet sheet = workbook.Worksheets[0];

// Import DataTable with headers
sheet.InsertDataTable(dataTable, true, 1, 1);

// Format header row
CellRange headerRange = sheet.Range[1, 1, 1, dataTable.Columns.Count];
headerRange.Style.Font.IsBold = true;
headerRange.Style.Font.Size = 11;
headerRange.Style.Color = Color.LightGray;

// Apply borders to enhance table structure
CellRange dataRange = sheet.AllocatedRange;
dataRange.BorderAround(LineStyleType.Thin);
dataRange.BorderInside(LineStyleType.Thin);

// Align content for consistency
dataRange.Style.HorizontalAlignment = HorizontalAlignType.Center;
dataRange.Style.VerticalAlignment = VerticalAlignType.Center;

// Auto-fit columns for better layout
sheet.AllocatedRange.AutoFitColumns();

// Center the content horizontally in the page
sheet.PageSetup.CenterHorizontally = true;

// Export to PDF
workbook.SaveToFile("SalesReport_2026.pdf", FileFormat.PDF);

This step combines layout control and PDF generation into a single workflow.

Key points to note:

  • Worksheet as layout engine The worksheet acts as a structured canvas where database data is arranged into rows and columns. This ensures the original tabular structure is preserved in the final document.

  • Formatting directly impacts PDF output Adjustments such as column width, font style, and borders are not just visual improvements—they determine how the content is rendered in the PDF. Poor formatting can lead to truncated text or unreadable layouts.

  • Automatic pagination When exporting, the worksheet content is automatically split across pages based on layout and paper size, which is particularly useful for large datasets.

For further layout optimization, you can enhance the table formatting by:

If your project requires more flexible PDF structure control, you can also explore converting DataTable to PDF in C# directly using Spire.PDF for .NET, which provides more advanced document-level layout capabilities for complex reporting needs.


3. Complete C# Example for Converting Databases to PDF

Below is the complete implementation that combines database retrieval, data formatting, and PDF export into a single workflow.

using System;
using System.Data;
using Microsoft.Data.SqlClient;
using Spire.Xls;
using System.Drawing;

class Program
{
    static void Main()
    {
        // Step 1: Retrieve data from database
        string connectionString = "Server=localhost\\SQLEXPRESS;Database=SalesDB;User ID=demouser;Password=YourPassword;Encrypt=true;TrustServerCertificate=true;";
        string query = @"
            SELECT o.OrderID, c.CustomerName, o.OrderDate, o.TotalAmount
            FROM Orders o
            JOIN Customers c ON o.CustomerID = c.CustomerID
            WHERE YEAR(o.OrderDate) = 2026;
        ";

        DataTable dataTable = new DataTable();

        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            SqlDataAdapter adapter = new SqlDataAdapter(query, conn);
            adapter.Fill(dataTable);
        }

        // Step 2: Create workbook and import data
        Workbook workbook = new Workbook();
        Worksheet sheet = workbook.Worksheets[0];
        sheet.InsertDataTable(dataTable, true, 1, 1);

        // Step 3: Apply professional formatting
        // Format header row
        CellRange headerRange = sheet.Range[1, 1, 1, dataTable.Columns.Count];
        headerRange.Style.Font.IsBold = true;
        headerRange.Style.Font.Size = 11;
        headerRange.Style.Color = Color.LightGray;

        // Apply borders
        CellRange dataRange = sheet.AllocatedRange;
        dataRange.BorderAround(LineStyleType.Thin);
        dataRange.BorderInside(LineStyleType.Thin);

        // Set alignment
        dataRange.Style.HorizontalAlignment = HorizontalAlignType.Center;
        dataRange.Style.VerticalAlignment = VerticalAlignType.Center;

        // Auto-fit columns
        sheet.AllocatedRange.AutoFitColumns();

        // Center the content horizontally in the pages
        sheet.PageSetup.CenterHorizontally = true;

        // Step 4: Export to PDF
        workbook.SaveToFile("SalesReport_2026.pdf", FileFormat.PDF);

        Console.WriteLine("Database query results successfully exported to PDF.");
    }
}

Below is a preview of the generated PDF:

Convert Database Query Results to PDF with C#

This example demonstrates an end-to-end workflow from SQL query execution to PDF generation.


4. Advanced Scenarios

In real-world applications, exporting database data to PDF often requires more than just basic conversion. You may need to handle batch exports, improve document readability, or adjust layout settings for better presentation. The following examples demonstrate common enhancements for real-world usage.

Export Multiple Query Results

For scenarios such as batch report generation or scheduled tasks, you may need to execute multiple queries and export each result as a separate PDF document:

string[] queries = {
    "SELECT * FROM Orders WHERE Status = 'Pending'",
    "SELECT * FROM Customers WHERE Region = 'North'"
};

for (int i = 0; i < queries.Length; i++)
{
    DataTable dt = ExecuteQuery(queries[i]);
    Workbook wb = new Workbook();
    Worksheet ws = wb.Worksheets[0];
    ws.InsertDataTable(dt, true, 1, 1);
    ws.AllocatedRange.AutoFitColumns();
    wb.SaveToFile($"Report_{i + 1}.pdf", FileFormat.PDF);
}

This approach is useful for automating report generation where multiple datasets need to be exported independently.

Add Title and Metadata

To improve readability and provide context, you can add a title row above the data before exporting to PDF:

// Insert title row
sheet.InsertRow(1);
sheet.Range[1, 1].Text = "Sales Report - 2026";
sheet.Range[1, 1].Style.Font.IsBold = true;
sheet.Range[1, 1].Style.Font.Size = 14;

// Merge title cells
sheet.Range[1, 1, 1, dataTable.Columns.Count].Merge();

// Auto-fit the title row
sheet.AutoFitRow(1);

The following image shows the generated PDF with the title row applied:

Convert Database Query Results to PDF with C#

Adding a title helps users quickly understand the context of the document, especially when sharing or printing reports.

Set Page Size, Orientation, and Margins

To ensure the PDF layout fits your data properly, you can configure page size, orientation, and margins before exporting:

// Set the page size and orientation
sheet.PageSetup.PaperSize = PaperSizeType.PaperA4;
sheet.PageSetup.Orientation = PageOrientationType.Portrait;

// Set the page margins
sheet.PageSetup.TopMargin = 0.5f;
sheet.PageSetup.BottomMargin = 0.2f;
sheet.PageSetup.LeftMargin = 0.2f;
sheet.PageSetup.RightMargin = 0.2f;

Adjusting these settings helps prevent content overflow and ensures consistent layout across different reports.

Control Page Layout and Scaling

When working with large tables, you may need to control how content is distributed across pages. By default, content is split automatically, but you can adjust scaling behavior to fit more data within a page.

// Fit content to page width
workbook.ConverterSetting.SheetFitToWidth = true;

// Fit entire sheet into a single page (may reduce readability)
workbook.ConverterSetting.SheetFitToPage = true;
  • SheetFitToWidth ensures the table fits within the page width while allowing vertical pagination
  • SheetFitToPage scales the entire worksheet to fit into a single page

These settings are useful when generating compact reports, but should be used carefully to avoid making text too small.

Add Headers and Footers

Headers and footers are useful for adding contextual information such as report titles, timestamps, or page numbers:

sheet.PageSetup.LeftHeader = "&\"Arial,Bold\"&16 Sales Report - 2026";
sheet.PageSetup.RightHeader = "&\"Arial,Italic\"&10 Generated on &D";
sheet.PageSetup.CenterFooter = "&\"Arial,Regular\"&16 Page &P of &N";

The following image shows the generated PDF with headers and footers applied:

Convert Database Query Results to PDF with C#

These elements improve document navigation and are especially valuable for multi-page reports.

Encrypt PDFs

To protect sensitive data, you can apply encryption to the exported PDF:

workbook.ConverterSetting.PdfSecurity.Encrypt("openpsd");

Encryption ensures that only authorized users can access the document, which is important for reports containing confidential or business-critical data.

For more related scenarios involving document export and PDF customization, you can also explore Excel to PDF conversion in C#.


5. Common Pitfalls

Database Connection Issues

Ensure the connection string is correct and the database server is accessible. Verify authentication settings (e.g., SQL authentication or integrated security) and confirm that encryption-related parameters match your environment configuration.

Empty Query Results

Check whether the DataTable contains data before proceeding. Empty result sets may lead to blank PDFs or unexpected formatting behavior.

if (dataTable.Rows.Count == 0)
{
    Console.WriteLine("No data found for the specified query.");
    return;
}

In production scenarios, you may also choose to generate a placeholder PDF or log the issue instead of exiting the process.

Column Width Overflow

When working with long text fields, AutoFitColumns() may produce excessively wide columns, which can negatively affect PDF layout.

To improve readability, consider:

  • Setting a maximum column width
  • Enabling text wrapping for long content
  • Manually adjusting key columns based on data type

This is especially important when exporting large datasets with variable-length text.

Missing Font Support

If the exported PDF contains special characters (e.g., non-Latin text) or custom fonts, ensure the required fonts are installed and accessible at runtime.

Missing fonts may cause text rendering issues or fallback substitutions, which can affect document appearance and readability.

Unexpected PDF Layout

If the exported PDF layout appears compressed or improperly scaled, check page setup and scaling options such as SheetFitToWidth or SheetFitToPage.

Improper scaling may cause content to appear too small or distort the original table structure.


Conclusion

This article demonstrated a practical approach to converting database query results to PDF in C#. By combining structured data retrieval with worksheet-based formatting, you can generate clear and professional documents directly from SQL data.

This method is particularly effective for report generation and data presentation scenarios where maintaining table structure and readability is essential.

If you are evaluating Spire.XLS, you can request a free temporary license to remove evaluation limitations during development.


FAQ

Can Spire.XLS export database data to PDF without third-party tools?

Yes. Spire.XLS performs all operations independently and does not require Microsoft Office or any other external tools.

How do I handle large datasets when exporting to PDF?

For large datasets, consider paginating the results or filtering the query to retrieve only necessary data. You can also adjust PDF page settings to optimize output size.

Can I customize the PDF page layout?

Yes. Spire.XLS allows you to configure page settings including orientation, margins, and paper size before exporting to PDF.

Does this method work with databases other than SQL Server?

Yes. The approach works with any database that supports ADO.NET data providers, including MySQL, PostgreSQL, and Oracle. Simply use the appropriate connection class and data adapter.

Should I use Microsoft.Data.SqlClient or System.Data.SqlClient?

For modern .NET applications, it is recommended to use Microsoft.Data.SqlClient. It is actively maintained and provides better support for newer SQL Server features, while System.Data.SqlClient is considered legacy and no longer receives major updates.

Tutorial on How to Add and Manage Excel VBA Macros in C#

VBA macros provide a convenient way to automate data processing, formatting, and business logic within Excel, especially for repetitive or rule-based tasks. However, managing macros manually inside Excel becomes inefficient when you need to generate, update, or maintain files at scale.

For .NET developers, a more scalable approach is to programmatically add macros to Excel using C#. By working with Excel VBA in C#, you can write Excel macros, read existing macro code, and modify VBA logic across multiple files without opening Excel and manually editing the VBA code.

In this article, you'll learn how to add, read, and edit Excel VBA macros in C# for automated workflows. Using Spire.XLS for .NET, you can directly manipulate VBA projects embedded in Excel files without requiring Microsoft Excel installation.

Quick Navigation


Understanding Excel Macros and How C# Works with Them

An Excel macro is essentially VBA (Visual Basic for Applications) code stored inside a workbook. In macro-enabled files (such as .xlsm), this code is organized within a VBA project, which contains modules and procedures.

In practice, most programmatic macro operations focus on standard modules, which are simple containers for VBA procedures (Sub or Function). When working with C#, you typically do not interact with Excel UI elements like buttons or events. Instead, you directly create modules and inject VBA code.

From a technical perspective, macros are not just executable scripts—they are part of the file structure. This means they can be accessed and modified programmatically, provided that your tool supports VBA project manipulation.

In C#, there are two main approaches to working with Excel macros:

  • Using Microsoft Excel Interop to automate Excel
  • Using standalone libraries such as Spire.XLS for .NET to manipulate the file directly

The first approach depends on Excel being installed and is typically used to execute macros. The second approach allows you to create, read, edit, and delete VBA code directly inside Excel files, making it more suitable for backend services and automated workflows.

In the following sections, we'll focus on the second approach and demonstrate how to manage Excel macros entirely in C#.


Environment Setup: Install Spire.XLS for .NET

Before working with Excel macros in C#, you need to install Spire.XLS for .NET, which allows you to manage Excel files and manipulate VBA projects without requiring Microsoft Excel.

Install via NuGet

You can install Spire.XLS for .NET using NuGet Package Manager:

Install-Package Spire.XLS

Or via the .NET CLI:

dotnet add package Spire.XLS

You can also download the Spire.XLS for .NET package and add it to your project manually.

Project Requirements

  • .NET Framework, .NET Core, .NET Standard, or .NET 5+
  • No Microsoft Excel installation required
  • Supports Windows, Linux, and macOS environments

The library is runtime-agnostic and can be used in any .NET-supported environment, including web, desktop, and cross-platform applications.

Namespace to Import

After installation, include the following namespaces in your project:

using Spire.Xls;

Once the setup is complete, you can start creating, reading, and modifying Excel VBA macros programmatically.


How to Add a Macro to Excel in C# (Complete Example)

Before writing macro code, it's important to understand how Spire.XLS exposes the VBA structure in Excel:

  • Workbook.VbaProject represents the VBA project embedded in the workbook
  • IVbaProject.Modules provides access to all VBA modules
  • IVbaModule represents an individual module that stores macro code

In addition to modules, the VBA project also supports project-level configuration, such as name, description, password protection, and conditional compilation settings.

The following example shows how to create a VBA project, configure its properties, add a module, and write a macro into an Excel file programmatically.

using Spire.Xls;

Workbook workbook = new Workbook();

// Create VBA project
IVbaProject vbaProject = workbook.VbaProject;

// Configure project-level properties (optional but important in real scenarios)
vbaProject.Name = "ReportGenerator";
vbaProject.Description = "VBA project for generating quarterly reports";
vbaProject.Password = "securepassword";
vbaProject.LockProjectView = false;
vbaProject.HelpFileName = "ReportGeneratorHelp.chm";
vbaProject.ConditionalCompilation = "DEBUG_MODE=1"; // External compile-time flag

// Add a VBA module
IVbaModule vbaModule = vbaProject.Modules.Add("ReportModule", VbaModuleType.Module);

// Write VBA macro code
vbaModule.SourceCode = @"
Sub GenerateQuarterlyReport()
    Dim ws As Worksheet
    Dim i As Integer
    Dim quarter As String

    Set ws = ActiveSheet
    ws.Cells.Clear

    ' Prompt user input
    quarter = InputBox(""Enter quarter (e.g., Q1 2026):"", ""Report Generation"")

    With ws
        .Range(""A1:E1"").Value = Array(""Date"", ""Product"", ""Region"", ""Sales"", ""Status"")

        For i = 1 To 50
            .Cells(i + 1, 1).Value = DateSerial(2026, 1 + Int((i - 1) / 17), 1 + ((i - 1) Mod 17))
            .Cells(i + 1, 2).Value = ""Product "" & (1 + Int((i - 1) / 10))
            .Cells(i + 1, 3).Value = Choose((i Mod 5) + 1, ""North"", ""South"", ""East"", ""West"", ""Central"")
            .Cells(i + 1, 4).Value = Round(Rnd() * 10000, 2)
            .Cells(i + 1, 5).Value = IIf(.Cells(i + 1, 4).Value > 5000, ""Target Met"", ""Below Target"")
        Next i

        .Columns(""A:E"").AutoFit

        ' Conditional compilation example
        #If DEBUG_MODE = 1 Then
            MsgBox ""DEBUG: Report generated (50 rows)"", vbInformation, ""Debug Info""
        #End If
    End With

    MsgBox ""Quarterly report for "" & quarter & "" generated successfully!"", vbInformation, ""Report Status""
End Sub";

// Save as macro-enabled Excel file
workbook.SaveToFile("QuarterlyReportGenerator.xlsm", FileFormat.Version2016);
workbook.Dispose();

Below is a preview of the generated Macro in Excel:

Add Macros to Excel Using C#

In this workflow, Spire.XLS allows you to construct the full VBA structure—not only modules and macro code, but also project-level metadata and compilation behavior—directly in code. This is conceptually similar to configuring a VBA project in the editor, but fully automated and independent of Excel.

Key API Breakdown

  • workbook.VbaProject

    Initializes or retrieves the VBA project within the workbook.

  • vbaProject.Modules.Add(name, type)

    Adds a new module to the project as a container for macro code.

  • vbaModule.SourceCode

    Defines the full VBA script inside the module.

  • vbaProject.Description

    Adds a description to the VBA project.

  • vbaProject.CodePage

    Defines the character encoding used in the VBA project.

  • vbaProject.Password / LockProjectView

    Controls access and visibility of the VBA project.

  • vbaProject.ConditionalCompilation

    Enables compile-time flags (e.g., debug logic) inside VBA using #If.

Workbooks containing macros must be saved in macro-enabled formats such as .xls, .xlsm, .xltm, or .xlsb, as other formats (e.g., .xlsx) do not support VBA. Refer to the FileFormat enumeration to correctly set the output format when saving.


Reading, Editing, and Removing Excel Macros in C#

Once a VBA project exists, you can use Spire.XLS to inspect and modify its contents programmatically, including both module code and project-level metadata.

In real-world scenarios, this allows you to analyze existing macros, update business logic, enforce security settings, or remove legacy VBA code without opening Excel. Whether you're maintaining automated reporting systems or processing third-party Excel files, having full control over VBA projects in code is essential.

Read Macro Code and Project-Level Metadata

To read macros from an Excel file, load the workbook and iterate through all modules in the VBA project.

using Spire.Xls;

Workbook workbook = new Workbook();
workbook.LoadFromFile("QuarterlyReportGenerator.xlsm");

IVbaProject vbaProject = workbook.VbaProject;

string macroInfo = "VBA Project Name: " + vbaProject.Name + Environment.NewLine;
macroInfo += "Code Page: " + vbaProject.CodePage + Environment.NewLine;
macroInfo += "Is Protected: " + vbaProject.IsProtected + Environment.NewLine;

foreach (IVbaModule module in vbaProject.Modules)
{
    macroInfo += Environment.NewLine + "Module: " + module.Name + Environment.NewLine;
    macroInfo += "Source Code:" + Environment.NewLine;
    macroInfo += module.SourceCode + Environment.NewLine;
}

Console.WriteLine(macroInfo);

System.IO.File.WriteAllText("MacroAnalysis.txt", macroInfo);
workbook.Dispose();

Below is a preview of the console output:

Read Macros from Excel Using C#

Here, each module exposes its VBA code through the SourceCode property, while the VBA project itself provides metadata such as name, encoding, and protection status.

The property vbaProject.IsProtected in this example indicates whether the VBA project is protected (locked for viewing or editing).

Edit Macro Code and Project-Level Metadata

To edit a macro, access a specific module and update its SourceCode. You can also modify project-level properties if needed. If the VBA project is protected, the correct password must be provided through vbaProject.Password before making such changes.

using Spire.Xls;

Workbook workbook = new Workbook();
workbook.LoadFromFile("QuarterlyReportGenerator.xlsm");

IVbaProject vbaProject = workbook.VbaProject;

// Update macro logic
IVbaModule module = vbaProject.Modules["ReportModule"];  // Or use index if name is unknown
module.SourceCode = module.SourceCode.Replace(
    "\"North\", \"South\", \"East\", \"West\", \"Central\"",
    "\"North America\", \"Europe\", \"Asia Pacific\", \"Latin America\", \"Middle East\"");

// Update project metadata
// For protected VBA projects, passwords are required to modify the project-level metadata
vbaProject.Password = "securepassword";
vbaProject.Description = "Updated report logic with global regions";
vbaProject.Name = "UpdatedReportGenerator";

workbook.SaveToFile("UpdatedReportGenerator.xlsm", FileFormat.Version2016);
workbook.Dispose();

Below is a preview of the updated macro code:

Edit Macros in Excel Using C#

Spire.XLS treats macro code as editable text within a module, so updates are typically done by modifying the existing source and saving the workbook.

If you need to convert legacy .xls files to .xlsm format while preserving macros, see How to Convert XLS to XLSM and Maintain Macros Using C#.

Remove Macros

To remove macros, delete modules from the VBA project. This effectively removes all macro logic from the workbook.

using Spire.Xls;
using Spire.Xls.Core.Spreadsheet;

Workbook workbook = new Workbook();
workbook.LoadFromFile("LegacyReport.xlsm");

IVbaProject vbaProject = workbook.VbaProject;

// Remove specific module by its name
vbaProject.Modules.Remove("ReportModule");

// Or remove a module by its index
vbaProject.Modules.RemoveAt(0);

// Remove all modules
vbaProject.Modules.Clear();

workbook.SaveToFile("CleanReport.xlsm", FileFormat.Version2016);
workbook.Dispose();

After removing all modules, the workbook no longer contains executable VBA code, making it equivalent to a macro-free Excel file.

Alternatively, converting a macro-enabled Excel file to .xlsx will remove all macros, since the .xlsx format does not support VBA code.


Common Pitfalls When Working with Excel Macros

File Format Requirements

Macros require macro-enabled formats such as .xlsm, .xls, or .xlsb. The .xlsx format does not support VBA code. Always save files with the appropriate extension.

Encoding Issues

VBA code uses specific encoding (typically CodePage 1252 for Western languages). When working with international characters, ensure the CodePage is set correctly before writing macro code.

Common CodePage values include:

  • 1252 – English / Western European (default in many environments)
  • 936 – Simplified Chinese (GBK)
  • 950 – Traditional Chinese (Big5)
  • 932 – Japanese (Shift-JIS)
  • 65001 – UTF-8 (⚠️ limited support in VBA, may cause compatibility issues)

Macro Security Settings

Excel macro security settings may prevent macros from running. When distributing macro-enabled files, consider adding instructions for enabling macros or digitally signing the VBA project.

Excel Version Compatibility

VBA code written for newer Excel versions may not work correctly in older versions. Test macros across target Excel versions to ensure compatibility.


Conclusion

C# provides robust capabilities for managing Excel macros programmatically. By using Spire.XLS for .NET, developers can add, read, edit, and remove VBA code directly inside Excel files without requiring Excel installation.

This approach focuses on managing macro code rather than executing it, making it ideal for automated workflows, backend services, and large-scale document processing.

To test these features without limitations, you can apply for a free temporary license of Spire.XLS for .NET.


Frequently Asked Questions (FAQ)

Can C# add VBA macros without Microsoft Excel?

Yes. Libraries such as Spire.XLS for .NET allow you to manipulate VBA projects directly without requiring Excel installation.

What format is required for Excel macros?

Macros require macro-enabled formats such as .xlsm, .xls, .xlsb, or .xltm (for templates). The .xlsx format does not support VBA code.

Can I edit existing macros in Excel using C#?

Yes. You can access VBA modules and modify their source code programmatically to update business logic or fix issues across multiple files.

Is this approach suitable for server environments?

Yes. Since it does not rely on Microsoft Excel, this approach is ideal for backend services, automated systems, and cloud-based applications.

Can I read macro code from password-protected Excel files?

It depends on the type of protection applied to the Excel file.

  • Workbook protection (file password): You must provide the password (e.g., via Workbook.OpenPassword) when loading the file before accessing its contents.
  • VBA project protection: Reading macro code is generally allowed, but modifying project-level properties (such as name or description) requires the VBA project password.

Additionally, if the Excel file is digitally signed, any modification to the document (including macros or metadata) will invalidate the signature.

Tutorial on How to Export List to Excel Without Interop in C#

Exporting list data to Excel with C# is a common requirement in modern .NET applications. Whether you are building a desktop application, a web system, or a background service, developers often need to convert in-memory collections—especially List<T>—into well-structured Excel files that users can download, analyze, or share.

This tutorial demonstrates how to export a list of objects to Excel in C# without using Excel Interop, using Spire.XLS for .NET. The solution is fully compatible with .NET Core and modern .NET versions, works with typical business data models, and does not require Microsoft Excel to be installed.

Table of Contents


Why Export a List to Excel in C# Without Interop?

Exporting list data to Excel is a practical way to present structured information in a familiar and widely accepted format. In real-world applications, this requirement commonly appears in scenarios such as:

  • Generating operational or financial reports
  • Allowing users to download query results from web applications
  • Sharing structured data with non-technical stakeholders
  • Performing offline analysis or audits using Excel

Traditionally, many developers rely on Excel Interop to generate Excel files. While Interop can work in certain desktop environments, it also introduces several limitations:

  • Microsoft Excel must be installed on the machine
  • It is not recommended for server-side or ASP.NET Core applications
  • It adds unnecessary dependencies for simple export tasks

As a result, exporting Excel files without Interop has become the preferred approach for modern .NET applications. Libraries such as Spire.XLS for .NET provide a clean, reliable, and server-friendly way to export a List<T> directly to Excel—without requiring Microsoft Office.


Export a List of Objects to Excel in C#

In most real-world applications, data is stored as a list of business objects rather than simple values. This section focuses on exporting a List<T> that represents a realistic reporting scenario, using a reusable and Interop-free approach.

Prerequisites

Before exporting a list to Excel, make sure Spire.XLS for .NET is installed in your project.

You can install it via NuGet:

Install-Package Spire.XLS

Once installed, you can start exporting List<T> data to Excel without any additional configuration.

Core Export Workflow

The overall process of exporting a list of objects to Excel can be summarized as follows:

  1. Prepare business-ready data in a List<T>
  2. Create an Excel workbook and worksheet
  3. Generate column headers dynamically from object properties
  4. Write list data into worksheet rows
  5. Save the Excel file

The following example demonstrates the complete implementation.

Complete Example: Export List to Excel

using Spire.Xls;
using System;
using System.Collections.Generic;
using System.Reflection;

public class OrderReport
{
    public int OrderId { get; set; }
    public string CustomerName { get; set; }
    public DateTime OrderDate { get; set; }
    public decimal TotalAmount { get; set; }
    public string Status { get; set; }
}

class Program
{
    static void Main()
    {
        // Prepare sample business data
        List<OrderReport> orders = new List<OrderReport>
        {
            new OrderReport { OrderId = 1001, CustomerName = "Alice", OrderDate = DateTime.Today.AddDays(-2), TotalAmount = 1200.50m, Status = "Completed" },
            new OrderReport { OrderId = 1002, CustomerName = "Bob", OrderDate = DateTime.Today.AddDays(-1), TotalAmount = 850.00m, Status = "Pending" },
            new OrderReport { OrderId = 1003, CustomerName = "Charlie", OrderDate = DateTime.Today, TotalAmount = 430.75m, Status = "Cancelled" }
        };

        // Create workbook and worksheet
        Workbook workbook = new Workbook();
        Worksheet sheet = workbook.Worksheets[0];

        // Read object properties dynamically
        PropertyInfo[] properties = typeof(OrderReport).GetProperties();

        // Write column headers
        for (int i = 0; i < properties.Length; i++)
        {
            sheet.Range[1, i + 1].Text = properties[i].Name;
        }

        // Write data rows
        for (int row = 0; row < orders.Count; row++)
        {
            for (int col = 0; col < properties.Length; col++)
            {
                object value = properties[col].GetValue(orders[row]);
                sheet.Range[row + 2, col + 1].Value2 = value;
            }
        }

        // Save Excel file
        workbook.SaveToFile("OrderReport.xlsx", ExcelVersion.Version2016);
    }
}

Below is a preview of the generated Excel file:

Simple List to Excel Exporting Using Spire.XLS for .NET in C#

Technical Notes and Implementation Details

  • An Excel file is created by instantiating Workbook, with the first worksheet accessed via workbook.Worksheets[0]
  • Column headers are generated dynamically using reflection (Type.GetProperties) to avoid hardcoded mappings
  • Header cells are written using Range.Text, ensuring clear string output in the first row
  • Object values are written row by row using Range.Value2 to preserve native Excel data types
  • The final Excel document is generated with Workbook.SaveToFile, without requiring Microsoft Excel or Interop

This pattern is ideal for building reusable export utilities and report-generation modules.

In scenarios where data is retrieved as a DataTable instead of a List, Spire.XLS also provides an efficient export approach. Refer to How to Export a DataTable to Excel in C# for detailed instructions.


Formatting the Exported Excel Worksheet

Beyond basic data export, Spire.XLS for .NET allows you to apply formatting to improve readability and usability of the generated Excel file.

Common formatting tasks include:

  • Styling header rows
  • Formatting dates and numeric values
  • Adjusting column widths automatically
  • Highlighting key fields

Example: Apply Basic Formatting

using System.Drawing;

// Format header row
CellStyle headerStyle = workbook.Styles.Add("HeaderStyle");
headerStyle.Font.FontName = "Arial";
headerStyle.Font.Size = 12f;
headerStyle.Font.IsBold = true;
headerStyle.Color = Color.LightGray;  // Set cell background color
headerStyle.HorizontalAlignment = HorizontalAlignType.Center;

sheet.Range[1, 1, 1, sheet.LastColumn].Style = headerStyle;

// Format date and amount columns
sheet.Range[2, 3, orders.Count + 1, 3].NumberFormat = "yyyy-mm-dd";
sheet.Range[2, 4, orders.Count + 1, 4].NumberFormat = "#,##0.00";

// Auto-fit row height and column width
sheet.AllocatedRange.AutoFitRows();
sheet.AllocatedRange.AutoFitColumns();

Below is a preview of the formatted Excel sheet:

Excel Sheet Formatted in C# Using Spire.XLS for .NET

Applying formatting makes the exported Excel file more professional and suitable for direct business use.

For more advanced worksheet formatting—such as styles, merged cells, conditional formatting, and formulas—see How to Create and Format Excel Worksheets in C#.


.NET Core and Server-Side Compatibility

Spire.XLS for .NET is fully compatible with .NET Core and modern .NET versions, making it suitable for:

  • ASP.NET Core web applications
  • Web APIs
  • Cloud and containerized environments
  • Background services and scheduled jobs

Because it does not rely on Excel Interop, the export logic is safe to use in server-side and production environments.

If you are working in an ASP.NET Core or Web API project, this guide shows how to generate and format Excel files and return them to the client: Export Excel Files in ASP.NET Core Using C#.


Conclusion

Exporting a list to Excel in C# does not have to rely on Excel Interop. With Spire.XLS for .NET, you can efficiently convert a List<T> into a well-structured and formatted Excel file that works seamlessly across .NET Framework and .NET Core environments.

By adopting an Interop-free approach, you reduce deployment complexity, improve application stability, and gain greater flexibility when exporting business data.

Whether you need to export complex reports or simple lists, Spire.XLS provides a reliable and scalable solution for modern C# applications. For evaluation purposes or to remove trial limitations, a 30-day temporary license is available.


Frequently Asked Questions

Q1. Can this approach export large lists efficiently?

Yes. Spire.XLS for .NET is designed for server-side usage and can handle large List datasets efficiently. For very large exports, batching or streaming strategies can further improve performance.

Q2. Does this solution require Microsoft Excel to be installed?

No. Spire.XLS for .NET works independently of Microsoft Excel and does not rely on Excel Interop, making it suitable for server and cloud environments.

Q3. Can I customize column headers or formats?

Yes. Column headers can be customized manually, and cell formats such as dates, numbers, and styles can be applied programmatically. For advanced formatting scenarios, refer to the C# Excel formatting guide.

Q4. Is this compatible with ASP.NET Core and Web APIs?

Yes. The export logic works seamlessly in ASP.NET Core applications, Web APIs, background services, and other server-side .NET environments.

DataGrid/GridView to Excel Export with C#

Exporting tabular data from UI controls to Excel is a common requirement in C# applications. In both WinForms and ASP.NET projects, users often need to take the data currently displayed in a DataGrid, DataGridView, or GridView and export it to an Excel file for reporting, sharing, or further processing.

In real-world scenarios, exported Excel files are rarely used as raw data only. Readable layouts, header styles, column widths, and number formats are usually expected as part of the export result.

This article demonstrates how to export DataGridView and GridView/DataGrid data to Excel in C# using Spire.XLS for .NET, without relying on Microsoft Office Interop. The solution focuses on exporting displayed data accurately, keeping the implementation clean, and applying Excel formatting in a consistent and reusable way.

Table of Contents


Advantages of Programmatic Excel Export in C#

While Microsoft Office Interop can generate Excel files, using a programmatic approach in C# provides clear benefits for exporting data from DataGrid, DataGridView, or GridView:

  • Does not require Microsoft Excel to be installed on the machine
  • Suitable for server-side or cloud environments
  • Maintains high performance even with large datasets
  • Simplifies automation and background export scenarios

By exporting data directly via code, developers can create reliable, maintainable, and scalable Excel exports that work consistently across different application types.


Core Concept: Export Displayed Data via a DataTable

Although DataGrid, DataGridView, and GridView are UI controls, they serve the same fundamental purpose: displaying structured data in rows and columns. Attempting to export these controls directly often leads to UI-dependent logic and maintenance challenges.

A more reliable and reusable workflow is:

Displayed UI data → DataTable → Excel file

In this design:

  • The DataTable represents exactly what the user sees
  • The Excel export logic remains independent of the UI layer
  • The same approach works for WinForms and ASP.NET applications
  • Formatting and layout can be applied at the Excel level

The DataTable acts as a clean intermediate structure rather than the final export target, and using Spire.XLS for .NET, DataTable can be easily exported to a well-formatted Excel file.


Step 1: Extract Displayed Data into a DataTable

The first step is to extract the currently displayed data from the UI control into a DataTable. This step focuses on capturing visible rows and columns, not on reconstructing the original data source.

Export Displayed Data from DataGridView (WinForms)

In WinForms applications, users typically expect the DataGridView content to be exported as it appears on screen. The following method converts the displayed DataGridView data into a DataTable:

DataTable ConvertDataGridViewToDataTable(DataGridView dgv)
{
    DataTable dt = new DataTable();

    foreach (DataGridViewColumn column in dgv.Columns)
    {
        dt.Columns.Add(column.HeaderText, column.ValueType ?? typeof(string));
    }

    foreach (DataGridViewRow row in dgv.Rows)
    {
        if (row.IsNewRow) continue;

        DataRow dr = dt.NewRow();
        for (int i = 0; i < dgv.Columns.Count; i++)
        {
            dr[i] = row.Cells[i].Value ?? DBNull.Value;
        }
        dt.Rows.Add(dr);
    }

    return dt;
}

This approach preserves column headers, column order, and displayed values when exporting DataGridView data to Excel in C#.

Export Displayed Data from GridView (ASP.NET)

In ASP.NET applications, GridView controls render tabular data for users to view and interact with. To export the displayed GridView data, the rendered rows can be converted into a DataTable as shown below:

DataTable ConvertGridViewToDataTable(GridView gv)
{
    DataTable dt = new DataTable();

    foreach (TableCell cell in gv.HeaderRow.Cells)
    {
        dt.Columns.Add(cell.Text);
    }

    foreach (GridViewRow row in gv.Rows)
    {
        DataRow dr = dt.NewRow();
        for (int i = 0; i < row.Cells.Count; i++)
        {
            dr[i] = row.Cells[i].Text;
        }
        dt.Rows.Add(dr);
    }

    return dt;
}

This method provides a consistent data structure that can be reused for exporting GridView data to Excel in C#, without introducing UI-specific export logic.

If you need to export data directly from a database to an Excel file, you can refer to this guide: Export Database to Excel in C#.


Step 2: Export DataTable to Excel in C#

Once the displayed data has been extracted into a DataTable, exporting it to Excel becomes a UI-independent operation.

In this example, Spire.XLS for .NET is used to generate Excel files programmatically, without requiring Microsoft Excel to be installed.

Install Spire.XLS for .NET

Spire.XLS for .NET can be installed via NuGet:

Install-Package Spire.XLS

You can also download Spire.XLS for .NET and add it to your project manually.

Basic Excel Export Example

using Spire.Xls;

Workbook workbook = new Workbook();
Worksheet worksheet = workbook.Worksheets[0];

// Import DataTable into Excel, including column headers
worksheet.InsertDataTable(exportTable, true, 1, 1);

// Save the Excel file
workbook.SaveToFile("ExportedData.xlsx", ExcelVersion.Version2016);

Below is a preview of the exported Excel file:

Basic DataGridView to Excel Export with C#

This export logic can be reused for DataGrid, DataGridView, and GridView scenarios without modification.


Step 3: Apply Formatting to the Exported Excel File

Formatting is a common requirement for Excel exports, regardless of how the data was sourced. Applying styles, adjusting column widths, and setting number formats significantly improves the usability of the exported file.

The following example demonstrates common formatting operations that can be applied to any exported Excel worksheet:

CellStyle headerStyle = workbook.Styles.Add("HeaderStyle");
headerStyle.Font.IsBold = true;
headerStyle.Font.Size = 13;
headerStyle.HorizontalAlignment = HorizontalAlignType.Center;
headerStyle.VerticalAlignment = VerticalAlignType.Center;
headerStyle.Color = Color.LightGray;

// Apply header style
CellRange headerRange = worksheet.Range[1, 1, 1, worksheet.AllocatedRange.Rows[0].CellsCount];
headerRange.Style = headerStyle;

// Auto-fit columns
worksheet.AllocatedRange.AutoFitColumns();

// Format date and currency columns
worksheet.Range[$"C2:C{worksheet.AllocatedRange.RowCount}"].NumberFormat = "yyyy-mm-dd";
worksheet.Range[$"F2:G{worksheet.AllocatedRange.RowCount}"].NumberFormat = "$#,##0.00";

Below is a preview of the Excel file after applying formatting:

DataGridView to Excel Export with Formatting in C#

These formatting steps can be combined or extended based on reporting requirements, without changing the data extraction logic.

Spire.XLS for .NET also supports more Excel formatting features, such as conditional formatting, charts, and more. You can check How to Create Excel Files in C# for more formating options.


Performance and Practical Considerations

When exporting large DataGrid or GridView datasets:

  • Run export operations asynchronously in desktop applications
  • Avoid blocking the UI thread during Excel generation
  • Export only necessary or visible columns
  • Generate Excel files server-side in ASP.NET applications

Because the export process operates on a DataTable rather than UI elements, it remains maintainable and scalable as data volume increases.


Summary

Exporting DataGrid, DataGridView, or GridView data to Excel in C# does not require Microsoft Office Interop. By extracting the displayed data into a DataTable and generating Excel files programmatically, developers can implement reliable and reusable Excel export functionality.

With consistent formatting support and a clear separation between UI and export logic, this approach works well for real-world reporting scenarios in both desktop and web applications. For evaluating the library or testing export functionality, you can apply for a temporary license.


FAQ

Q1: How can I export DataGridView data to Excel in C#?

A1: You can extract the displayed data from a DataGridView into a DataTable and then use Spire.XLS for .NET to generate an Excel file programmatically, without relying on Microsoft Excel.

Q2: Can I apply formatting when exporting GridView to Excel in C#?

A2: Yes, Spire.XLS allows you to apply styles, adjust column widths, and set number formats to any exported Excel worksheet, ensuring readable and professional-looking reports.

Q3: Do I need Microsoft Excel installed to export DataGrid or GridView data in C#?

A3: No. By using a programmatic library like Spire.XLS, Excel files can be generated directly from DataTable objects without requiring Excel on the machine, making it suitable for server-side and cloud applications.

Tutorial on How to Export a DataTable to PDF Using C#

In many .NET-based business systems, structured data is often represented as a DataTable. When this data needs to be distributed, archived, or delivered as a read-only report, exporting a DataTable to PDF using C# becomes a common and practical requirement.

Compared with formats such as Excel or CSV, PDF is typically chosen when layout stability, visual consistency, and document integrity are more important than data editability. This makes PDF especially suitable for reports, invoices, audit records, and system-generated documents.

This tutorial takes a code-first approach to converting a DataTable to PDF in C#, focusing on the technical implementation rather than conceptual explanations. The solution is based on Spire.PDF for .NET, using its PdfGrid component to render DataTable content as a structured table inside a PDF document.

Table of Contents


1. Overview: DataTable to PDF Export in C#

Exporting a DataTable to PDF is fundamentally a data-binding and rendering task, not a low-level drawing problem.

Instead of manually calculating row positions, column widths, or page breaks, the recommended approach is to bind an existing DataTable to a PDF table component and let the rendering engine handle layout and pagination automatically.

In Spire.PDF for .NET, this role is fulfilled by the PdfGrid class.

Why PdfGrid Is the Right Abstraction

PdfGrid is a Spire.PDF for .NET component designed specifically for rendering structured, tabular data in PDF documents. It treats rows, columns, headers, and pagination as first-class concepts rather than graphical primitives.

From a technical standpoint, PdfGrid provides:

  • Direct binding via the DataSource property, which accepts a DataTable
  • Automatic column generation based on the DataTable schema
  • Built-in header and row rendering
  • Automatic page breaking when content exceeds page bounds

As a result, exporting a DataTable to PDF becomes a declarative operation: you describe what data should be rendered, and the PDF engine determines how it is laid out across pages.

The following sections focus on the concrete implementation and practical refinements of this approach.


2. Environment Setup

All examples in this article apply to both .NET Framework and modern .NET (6+) projects. The implementation is based entirely on managed code and does not require platform-specific configuration.

Installing Spire.PDF for .NET

Spire.PDF for .NET can be installed via NuGet:

Install-Package Spire.PDF

You can also download Spire.PDF for .NET and include it in your project manually.

Once installed, the library provides APIs for PDF document creation, page management, table rendering, and style control.


3. DataTable to PDF in C#: Core Workflow and Code Implementation

With the environment prepared, exporting a DataTable to PDF becomes a linear, implementation-driven process.

At its core, the workflow relies on binding an existing DataTable to PdfGrid and delegating layout, pagination, and table rendering to the PDF engine. There is no need to manually draw rows, columns, or borders.

From an implementation perspective, the process consists of the following steps:

  1. Prepare a populated DataTable
  2. Create a PDF document and page
  3. Bind the DataTable to a PdfGrid
  4. Render the grid onto the page
  5. Save the PDF output

These steps are typically executed together as a single, continuous code path in real-world applications. The following example demonstrates the complete workflow in one place.

Complete Example: Exporting a DataTable to PDF

The example below uses a business-oriented DataTable schema to reflect a typical reporting scenario. The source of the DataTable (database, API, or in-memory processing) does not affect the export logic.

DataTable dataTable = new DataTable();
dataTable.Columns.Add("OrderId", typeof(int));
dataTable.Columns.Add("CustomerName", typeof(string));
dataTable.Columns.Add("OrderDate", typeof(DateTime));
dataTable.Columns.Add("TotalAmount", typeof(decimal));

dataTable.Rows.Add(1001, "Contoso Ltd.", DateTime.Today, 1280.50m);
dataTable.Rows.Add(1002, "Northwind Co.", DateTime.Today, 760.00m);
dataTable.Rows.Add(1003, "Adventure Works", DateTime.Today, 2145.75m);
dataTable.Rows.Add(1004, "Wingtip Toys", DateTime.Today, 1230.00m);
dataTable.Rows.Add(1005, "Bike World", DateTime.Today, 1230.00m);
dataTable.Rows.Add(1006, "Woodgrove Bank", DateTime.Today, 1230.00m);

PdfDocument document = new PdfDocument();
PdfPageBase page = document.Pages.Add();

PdfGrid grid = new PdfGrid();
grid.DataSource = dataTable;

grid.Draw(page, new PointF(40f, 0));

document.SaveToFile("DataTableToPDF.pdf");
document.Close();

This single code block completes the entire DataTable-to-PDF export process. Below is a preview of the generated PDF:

PDF document generated from DataTable using C#

Key technical characteristics of this implementation:

  • PdfGrid.DataSource accepts a DataTable directly, with no manual row or column mapping
  • Column headers are generated automatically from DataColumn.ColumnName
  • Row data is populated from each DataRow
  • Pagination and page breaks are handled internally during rendering
  • No coordinate-level table layout logic is required

The result is a structured, paginated PDF table that accurately reflects the DataTable’s schema and data. This method is already a fully functional and production-ready solution for exporting a DataTable to PDF in C#.

In practical applications, however, additional control is often required for layout positioning, page size, orientation, and visual styling. The following sections focus on refining table placement, appearance, and pagination behavior without altering the core export logic.


4. Controlling Table Layout, Page Flow, and Pagination

In real-world documents, table rendering is part of a larger page composition. Page geometry, table start position, and pagination behavior together determine how tabular data flows across one or more pages.

In PdfGrid, these concerns are resolved during rendering. The grid itself does not manage absolute layout or page transitions; instead, layout and pagination are governed by page configuration and the parameters supplied when calling Draw.

The following example demonstrates a typical layout and pagination configuration used in production reports.

Layout and Pagination Example

PdfDocument document = new PdfDocument();

// Create an A4 page with margins
PdfPageBase page = document.Pages.Add(
    PdfPageSize.A4,
    new PdfMargins(40),
    PdfPageRotateAngle.RotateAngle0,  // Rotates the page coordinate system
    PdfPageOrientation.Landscape  // Sets the page orientation
);

PdfGrid grid = new PdfGrid();
grid.DataSource = dataTable;

// Enable header repetition across pages
grid.RepeatHeader = true;

// Define table start position
float startX = 40f;
float startY = 80f;

// Render the table
grid.Draw(page, new PointF(startX, startY));

Below is a preview of the generated PDF with page configuration applied:

PDF generated from DataTable with Page Configuration Using C#

Technical Explanation

The rendering behavior illustrated above can be understood as a sequence of layout and flow decisions applied at draw time:

  • PdfPageBase

    • Pages.Add creates a new page with configurable size, margins, rotation, and orientation.
  • RepeatHeader

    • Boolean property controlling whether column headers are rendered on each page. When enabled, headers repeat automatically during multi-page rendering.
  • Draw method

    • Accepts a PointF defining the starting position on the page.
    • Responsible for rendering the grid and automatically handling pagination.

By configuring page geometry, table start position, and pagination behavior together, PdfGrid enables predictable multi-page table rendering without manual page management or row-level layout control.

Page numbers are also important for PDF reports. Refer to How to Add Pages Numbers to PDF with C# to learn page numbering techniques.


5. Customizing Table Appearance

Once layout is stable, appearance becomes the primary concern. PdfGrid provides a centralized styling model that allows table-wide, column-level, and row-level customization without interfering with data binding or pagination.

The example below consolidates common styling configurations typically applied in reporting scenarios.

Styling Example: Headers, Rows, and Columns

PdfDocument document = new PdfDocument();
PdfPageBase page = document.AppendPage();

PdfGrid grid = new PdfGrid();
grid.DataSource = dataTable;

// Create and apply the header style
PdfGridCellStyle headerStyle = new PdfGridCellStyle();
headerStyle.Font =
    new PdfFont(PdfFontFamily.Helvetica, 10f, PdfFontStyle.Bold);
headerStyle.BackgroundBrush =
    new PdfSolidBrush(Color.FromArgb(60, 120, 200));
headerStyle.TextBrush = PdfBrushes.White;
grid.Headers.ApplyStyle(headerStyle);


// Create row styles
PdfGridCellStyle defaultStyle = new PdfGridCellStyle();
defaultStyle.Font = new PdfFont(PdfFontFamily.Helvetica, 9f);
PdfGridCellStyle alternateStyle = new PdfGridCellStyle();
alternateStyle.BackgroundBrush = new PdfSolidBrush(Color.LightSkyBlue);
// Apply row styles
for (int rowIndex = 0; rowIndex < grid.Rows.Count; rowIndex++)
{
    if (rowIndex % 2 == 0)
    {
        grid.Rows[rowIndex].ApplyStyle(defaultStyle);
    }
    else
    {
        grid.Rows[rowIndex].ApplyStyle(alternateStyle);
    }
}

// Explicit column widths
grid.Columns[0].Width = 60f;    // OrderId
grid.Columns[1].Width = 140f;   // CustomerName
grid.Columns[2].Width = 90f;    // OrderDate
grid.Columns[3].Width = 90f;    // TotalAmount

// Render the table
grid.Draw(page, new PointF(40f, 80f));

Below is a preview of the generated PDF with the above styling applied:

PDF document generated from DataTable with styling applied

Styling Behavior Notes

  • Header styling

    • Header appearance is defined through a dedicated PdfGridCellStyle and applied using grid.Headers.ApplyStyle(...).
    • This ensures all header cells share the same font, background color, text color, and alignment across pages.
  • Row styling

    • Data rows are styled explicitly via grid.Rows[i].ApplyStyle(...).
    • Alternating row appearance is controlled by the row index, making the behavior predictable and easy to extend with additional conditions if needed.
  • Column width control

    • Column widths are assigned directly through grid.Columns[index].Width.
    • Explicit widths avoid layout shifts caused by content length and produce consistent results in report-style documents.

Make sure to bind the styles before applying styles.

All styles (header, rows, and columns) are resolved before calling grid.Draw(...). The rendering process applies these styles without affecting pagination or data binding.

For more complex styling scenarios, check out How to Create and Style Tables in PDF with C#.


6. Output Options: File vs Stream

Once the table has been rendered, the final step is exporting the PDF output.
The rendering logic remains identical regardless of the output destination.

Saving to a File

Saving directly to a file is suitable for desktop applications, background jobs, and batch exports.

document.SaveToFile("DataTableReport.pdf");
document.Close();

This approach is typically used in:

  • Windows desktop applications
  • Scheduled report generation
  • Offline or server-side batch processing

Writing to a Stream (Web and API Scenarios)

In web-based systems, saving to disk is often unnecessary or undesirable. Instead, the PDF can be written directly to a stream.

using (MemoryStream stream = new MemoryStream())
{
    document.SaveToStream(stream);
    document.Close();

    byte[] pdfBytes = stream.ToArray();
    // return pdfBytes as HTTP response
}

Stream output integrates cleanly with ASP.NET controllers or minimal APIs, without the need for temporary file storage.

For a complete example of returning a generated PDF from an ASP.NET application, see how to create and return PDF documents in ASP.NET.


7. Practical Tips and Common Issues

This section focuses on issues commonly encountered in real-world projects when exporting DataTables to PDF.

7.1 Formatting Dates and Numeric Values

PdfGrid renders values using their string representation. To ensure consistent formatting, values should be normalized before binding.

Typical examples include:

  • Formatting DateTime values using a fixed culture
  • Standardizing currency precision
  • Avoiding locale-dependent formats in multi-region systems

This preparation step belongs in the data layer, not the rendering layer.

7.2 Handling Null and Empty Values

DBNull.Value may result in empty cells or inconsistent alignment. Normalizing values before binding avoids layout surprises.

row["TotalAmount"] =
    row["TotalAmount"] == DBNull.Value ? 0m : row["TotalAmount"];

This approach keeps rendering logic simple and predictable.

7.3 Preventing Table Width Overflow

Wide DataTables can exceed page width if left unconfigured.

Common mitigation strategies include:

  • Explicit column width configuration
  • Slight font size reduction
  • Switching to landscape orientation
  • Increasing page margins selectively

These adjustments should be applied at the layout level rather than modifying the underlying data.

7.4 Large DataTables and Performance Considerations

When exporting DataTables with hundreds or thousands of rows, performance characteristics become more visible.

Practical recommendations:

  • Avoid per-cell or per-row styling in large tables.
  • Prefer table-level or column-level styles
  • Use standard fonts instead of custom embedded fonts
  • Keep layout calculations simple and consistent

For example, applying styles using grid.Rows[rowIndex].ApplyStyle(...) inside a loop can introduce unnecessary overhead for large datasets. In such cases, prefer applying a unified style at the row or column collection level (e.g., grid.Rows.ApplyStyle(...)) when individual row differentiation is not required.

In addition to rendering efficiency, in web environments, PDF generation should be performed outside the request thread when possible to avoid blocking.


8. Conclusion

Exporting a DataTable to PDF in C# can be handled directly through PdfGrid without manual table construction or low-level drawing. By binding an existing DataTable, you can generate paginated PDF tables while keeping layout and appearance fully under control.

This article focused on a practical, code-first approach, covering layout positioning, styling, and data preparation as they apply in real-world export scenarios. With these patterns in place, the same workflow scales cleanly from simple reports to large, multi-page documents.

If you plan to evaluate this workflow in a real project, you can apply for a temporary license from E-ICEBLUE to test the full functionality without limitations.


FAQ: DataTable to PDF in C#

When is PdfGrid the right choice for exporting DataTables to PDF?

PdfGrid is most suitable when you need structured, paginated tables with consistent layout. It handles column generation, headers, and page breaks automatically, making it a better choice than manual drawing for reports, invoices, and audit documents.

Should formatting be handled in the DataTable or in PdfGrid?

Data normalization (such as date formats, numeric precision, and null handling) should be done before binding. PdfGrid is best used for layout and visual styling, not for value transformation.

Can PdfGrid handle large DataTables efficiently?

Yes. PdfGrid supports automatic pagination and header repetition. For large datasets, applying table-level or column-level styles instead of per-cell styling helps maintain stable performance.

A guide to create CSV files in C#/.NET

CSV (Comma-Separated Values) files remain one of the most widely used data exchange formats in modern software development. Their simplicity, human-readability, and compatibility across different systems make them ideal for data export, import, and transformation tasks. If you’re a developer looking to create a CSV file in C#, the Spire.XLS for .NET library offers a robust, easy-to-use solution—no need for manual string manipulation or complex Excel interop.

In this guide, we’ll walk you through everything you need to know to create or write CSV files in C# with Spire.XLS, from basic CSV creation to advanced Excel to CSV conversion.


Why Choose Spire.XLS to Create CSV?

Spire.XLS for .NET is a professional Excel API that provides extensive spreadsheet manipulation capabilities, including robust CSV support. Here's why developers prefer it:

  • No Excel Dependency: Unlike Microsoft Office Interop, Spire.XLS works independently of Excel, eliminating dependency issues in production environments.
  • Simplified API: Intuitive methods to create, populate, and save CSV files without low-level file handling.
  • Seamless Excel-CSV Conversion: Export existing Excel files (XLS/XLSX) to CSV with zero manual parsing.
  • Customization: Control delimiters, encodings, and formatting to meet specific CSV requirements.

Getting Started with Spire.XLS

To get started, you need to:

  • Have Visual Studio installed.
  • Install the Spire.XLS for .NET library via NuGet:
    • Visual Studio GUI: Right-click your project → Manage NuGet Packages → Search for Spire.XLS → Install.
    • Package Manager Console:
PM> Install-Package Spire.XLS

Create a Basic CSV File in C#

Here's a straightforward example demonstrating how to create a CSV file from scratch:

using System.Text;
using Spire.Xls;

namespace CreateCSV
{
    class Program
    {
        static void Main(string[] args)
        {
            // 1. Create a new Excel workbook
            Workbook workbook = new Workbook();

            // 2. Add a worksheet (CSV is based on a single worksheet)
            Worksheet worksheet = workbook.Worksheets.Add("ProductData");

            // 3. Define header row
            worksheet.Range["A1"].Value = "ProductID";
            worksheet.Range["B1"].Value = "ProductName";
            worksheet.Range["C1"].Value = "Price";
            worksheet.Range["D1"].Value = "InStock";

            // 4. Populate sample data rows
            worksheet.Range["A2"].Value2 = 1001;
            worksheet.Range["B2"].Value = "Laptop XPS 15";
            worksheet.Range["C2"].Value2 = 1299.99;
            worksheet.Range["D2"].Value = "YES";

            worksheet.Range["A3"].Value2 = 1002;
            worksheet.Range["B3"].Value = "Wireless Mouse";
            worksheet.Range["C3"].Value2 = 29.99;
            worksheet.Range["D3"].Value = "NO";

            worksheet.Range["A4"].Value2 = 1003;
            worksheet.Range["B4"].Value = "Mechanical Keyboard";
            worksheet.Range["C4"].Value2 = 89.99;
            worksheet.Range["D4"].Value = "YES";

            // 5. Save as CSV
            worksheet.SaveToFile("ProductList.csv", ",", Encoding.UTF8);
            workbook.Dispose();
        }
    }
}

How It Works:

  • Workbook Initialization: Start by creating a Workbook object (Spire.XLS’s core object for Excel/CSV operations).
  • Worksheet Creation: Add a worksheet to write data as CSV files map to a single worksheet.
  • Data Population: Spire.XLS provides two properties for cell values to handle data types correctly:
    • Value: Used for text/string data.
    • Value2: Used for booleans, strings, numbers, dates, etc.
  • Save as CSV: The SaveToFile method converts the worksheet to a CSV file.

Output:

The generated ProductList.csv will look like this:

Create a simple CSV file from scratch using C#

If you need to read a CSV file, refer to: Read CSV Files in C#: Basic Parsing & DataTable Conversion


Create a CSV from a List of Objects with C#

In real projects, data usually comes from collections (e.g., List<T>). This example populates a CSV from a list of Product objects:

using System.Collections.Generic;
using System.Text;
using Spire.Xls;

namespace CreateCSVFromList
{
    // Define a custom Product class
    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public bool InStock { get; set; }
    }

    class Program
    {
        static void Main(string[] args)

        {
            // Step 1: Prepare structured list data
            List<Product> productList = new List<Product>()
            {
                new Product { ID = 1001, Name = "Laptop", Price = 999.99m, InStock = true },
                new Product { ID = 1002, Name = "T-shirt", Price = 19.99m, InStock = false  },
                new Product { ID = 1003, Name = "Coffee Mug", Price = 8.99m, InStock = false  },
                new Product { ID = 1004, Name = "Wireless Mouse", Price = 24.99m, InStock = true  }
            };

            // Step 2: Create Spire.XLS objects
            Workbook workbook = new Workbook();
            Worksheet worksheet = workbook.Worksheets[0];

            // Step 3: Write CSV header (Row 1)
            worksheet.Range[1, 1].Text = "ID";
            worksheet.Range[1, 2].Text = "Name";
            worksheet.Range[1, 3].Text = "Price";
            worksheet.Range[1, 4].Text = "InStock";

            // Step 4: Fill structured data into worksheet (start from Row 2)
            for (int i = 0; i < productList.Count; i++)
            {
                int rowNum = i + 2;
                Product product = productList[i];

                // Assign data to cells
                worksheet.Range[rowNum, 1].NumberValue = product.ID; // Numeric type
                worksheet.Range[rowNum, 2].Text = product.Name;     // String type
                worksheet.Range[rowNum, 3].NumberValue = (double)product.Price; // Decimal → Double
                worksheet.Range[rowNum, 4].BooleanValue = product.InStock; // Boolean value
            }

            // Step 5: Save as CSV
            string csvPath = "structured_products.csv";
            worksheet.SaveToFile(csvPath, ",", Encoding.UTF8);
            workbook.Dispose();
        }
    }
}

Key Code Explanations:

  • Workbook/Worksheet: Spire.XLS uses Workbook to manage worksheets, even for CSV.
  • Cell Indexing: Spire.XLS uses 1-based indexing (rows/columns start at 1, not 0).
  • Data Type Handling:
    • Use .Text for string values (e.g., product name/category).
    • Use .NumberValue for numeric values (int/decimal/double).
    • Use .BooleanValue for Boolean values.

Output CSV:

Create a CSV file from a list using C#


Create a CSV File from Excel in C#

A common real-world scenario is converting Excel to CSV. This example loads an existing Excel file (.xls or .xlsx) and exports its first worksheet to a CSV file.

using System.Text;
using Spire.Xls;

namespace ExcelToCSV
{
    class Program
    {
        static void Main(string[] args)
        {
            // 1. Load an existing Excel file
            Workbook workbook = new Workbook();
            workbook.LoadFromFile("Test.xlsx");

            // 2. Select the first worksheet
            Worksheet worksheet = workbook.Worksheets[0];

            // 3. Save worksheet as CSV
            worksheet.SaveToFile("ExcelToCSV.csv", ",", Encoding.UTF8);
            workbook.Dispose();

        }
    }
}

Excel to CSV Conversion Result:

Convert Excel to CSV in C#

Customization Tip: You can change the delimiter and encoding parameters of the SaveToFile() method to meet regional requirements.


Conclusion​

Creating a CSV file in C# with Spire.XLS for .NET is fast, reliable, and requires minimal code compared to manual file writing. Whether you’re building a basic CSV from scratch, mapping collections to CSV, or converting from Excel files, this guide offers detailed, actionable instructions to streamline your workflow.

With Spire.XLS, you can generate CSV file in C# easily. For more Excel or CSV-related tasks in .NET development, visit the online documentation.


FAQs (Common Questions)

Q1: How to handle non-English characters in CSV?

A: Use Encoding.UTF8 or Encoding.Unicode in SaveToFile to preserve non-ASCII characters.

Q2: Can I create a CSV with multiple worksheets?

A: No—CSV is a single-sheet format. For multiple datasets, create separate CSV files or merge sheets into one before saving.

Q3: How do I save a CSV without a header row?

A: Simply skip writing the header row in the worksheet and start populating data from the first row.

Q4: Is Spire.XLS free?

A: Spire.XLS offers a free version with limitations. Or you can request a trial license here to test its full features without restrictions.

To print Word, Excel, PowerPoint, PDF, and other document types, Spire.Printing is used together with the corresponding Spire.Office document libraries—Spire.Doc, Spire.XLS, Spire.Presentation, and Spire.PDF (especially the .NET Standard version)—to load the source files, save them into IPrintDocumentStream, and send them to the printer.

To print Word, Excel, PowerPoint, PDF, and other document types, Spire.Printing is used together with the corresponding Spire.Office document libraries—Spire.Doc, Spire.XLS, Spire.Presentation, and Spire.PDF (especially the .NET Standard version)—to load the source files, save them into IPrintDocumentStream, and send them to the printer.

Page 1 of 95
page 1