DEV Community

Cover image for How to Export Excel to PDF in .NET (Fast & Accurate Method)
Jen
Jen

Posted on

How to Export Excel to PDF in .NET (Fast & Accurate Method)

If you’ve ever tried exporting Excel to PDF in a backend service, you probably started with Microsoft.Office.Interop.Excel. And then it broke.

No Office is installed on the server. Random crashes under load. Processes that refuse to die. It might work on your machine — but not in production. What you really want is something predictable: no Office dependency, no layout surprises, and something that actually survives in a server or container environment.

So how do you do that cleanly in .NET?

Why Traditional Approaches Fall Short

The go-to options for Excel-to-PDF conversion in .NET each come with real trade-offs.

  • Microsoft.Office.Interop.Excel requires a full Office installation on the server — something Microsoft explicitly advises against for server-side use. Even when it works, it's single-threaded COM automation running in a multi-request environment: slow, fragile, and prone to leaving zombie processes when something goes wrong.

  • Manual rendering with libraries like iTextSharp flips the problem. No Office dependency, but now you're manually reading every cell, recreating styles, handling merged regions, and rebuilding layouts from scratch. The code is brittle, and even after all that work, the output rarely looks like the original.

These approaches either don't scale well or fail to preserve formatting — often both.

What We Actually Need

The real challenge isn't just converting Excel to PDF — it's doing it reliably in a backend environment where Office doesn't exist and formatting still has to look right.

A practical solution needs to check a few boxes:

  • No Microsoft Office dependency — must run on a clean server or Linux container.
  • Accurate output — merged cells, fonts, column widths, and print layout all preserved.
  • Handles complex files — charts, images, and multi-sheet workbooks shouldn't break it.
  • Simple API — integration shouldn't require rebuilding your document rendering logic from scratch.

With these requirements in mind, let's look at a practical approach.

Getting Started (Minimal Setup)

A practical way to achieve this is by using a dedicated .NET Excel processing library such as Spire.XLS for .NET — a standalone Excel processing library that handles conversion without any Office dependency.

Install it via NuGet:

dotnet add package Spire.XLS
Enter fullscreen mode Exit fullscreen mode

Or through the Package Manager Console:

Install-Package Spire.XLS
Enter fullscreen mode Exit fullscreen mode

A few things worth noting before we write any code:

  • Works with .NET 6, 7, 8 and .NET Framework.
  • Runs on Windows, Linux, and in Docker containers.
  • No Microsoft Office installation required.

That's all the setup needed. Let's convert something.

Basic Example: Export Entire Workbook to PDF

Here's the simplest form of the conversion — load a workbook, export to PDF:

using Spire.Xls;

class Program
{
    static void Main()
    {
        // Create a Workbook object
        Workbook workbook = new Workbook();

        // Load the Excel file
        workbook.LoadFromFile(@"C:\Users\Sample.xlsx");

        // Option: Fit each sheet to a page on export
        workbook.ConverterSetting.SheetFitToPage = true;

        // Save as PDF
        workbook.SaveToFile(@"C:\Users\Sample.pdf", FileFormat.PDF);

        // Release resources
        workbook.Dispose();
    }
}
Enter fullscreen mode Exit fullscreen mode

Basic Excel to PDF in C#

That's the full conversion. No COM objects, no Office installation, no temp files to clean up. This approach works especially well in background jobs, scheduled tasks, or API-based report generation.

A few things the library handles automatically:

  • Merged cells — preserved as-is.
  • Fonts and cell styles — carried over to the output.
  • Column widths and row heights — no reflow or guesswork.

SheetFitToPage = true is worth setting by default. Without it, wide sheets may split across pages in ways that break the layout — we'll cover more layout controls in a later section.

At this point, you already have a reliable Excel-to-PDF pipeline that works without Office and preserves most formatting out of the box.

Advanced Excel to PDF Conversion Scenarios

The basic example works well — but real-world projects rarely stay that simple. Here are three variations you'll likely run into.

Export a Specific Worksheet

Useful when your workbook contains multiple sheets and you only need to export one — a department report, a specific template tab:

using Spire.Xls;

class Program
{
    static void Main()
    {
        // Create a Workbook object
        Workbook workbook = new Workbook();

        // Load the Excel file
        workbook.LoadFromFile(@"C:\Users\Multi-SheetChart.xlsx");

        // Get the second worksheet (index starts from 0)
        Worksheet sheet = workbook.Worksheets[1];

        // Option: Fit the worksheet to a single page (worksheet level)
        sheet.PageSetup.FitToPagesWide = 1;   // Fit width to 1 page
        sheet.PageSetup.FitToPagesTall = 0;   // Height adjusts automatically

        // Save the specific worksheet as PDF
        sheet.SaveToPdf(@"C:\Users\Multi-SheetChart_Sheet2.pdf");

        // Release resources
        workbook.Dispose();
    }
}
Enter fullscreen mode Exit fullscreen mode

Specific Worksheet to PDF in C#

Batch Export Multiple Worksheets

When you need each sheet as a separate PDF file:

using Spire.Xls;
using System.IO;

class Program
{
    static void Main()
    {
        // Create a Workbook object and load the Excel file
        Workbook workbook = new Workbook();
        workbook.LoadFromFile(@"C:\Users\Multi-SheetChart.xlsx");

        // Get the output directory (same as input file location)
        string outputDir = Path.GetDirectoryName(@"C:\Users\Multi-SheetChart.xlsx");

        // Iterate through all worksheets
        for (int i = 0; i < workbook.Worksheets.Count; i++)
        {
            Worksheet sheet = workbook.Worksheets[i];

            // Use the worksheet name as the PDF filename
            string fileName = $"{sheet.Name}.pdf";
            string outputPath = Path.Combine(outputDir, fileName);

            // Save the worksheet as PDF
            sheet.SaveToPdf(outputPath);

            System.Console.WriteLine($"Exported: {sheet.Name}{fileName}");
        }

        // Release resources
        workbook.Dispose();

        System.Console.WriteLine("\nAll worksheets exported successfully!");
    }
}
Enter fullscreen mode Exit fullscreen mode

C#: Batch Export Multiple Worksheets

Each sheet is saved as an individual file named after the sheet tab. Pair this with Directory.CreateDirectory() to ensure the output folder exists before running.

Export a Defined Print Area

If your sheet has a defined print area — say, a template where only rows 10–34 contain actual data — you can export just that range:

using Spire.Xls;

class Program
{
    static void Main()
    {
        // Create a Workbook object
        Workbook workbook = new Workbook();

        // Load the Excel file
        workbook.LoadFromFile(@"C:\Users\StyleSheet.xlsx");

        // Get the first worksheet
        Worksheet sheet = workbook.Worksheets[0];

        // Define the range to export
        sheet.PageSetup.PrintArea = "A10:H34";

        // Optional: Fit the print area to a single page width
        sheet.PageSetup.FitToPagesWide = 1;    // Scale width to 1 page
        sheet.PageSetup.FitToPagesTall = 0;    // Height automatically adjusts

        // Save the print area as PDF
        sheet.SaveToPdf(@"C:\Users\StyleSheet_PrintArea.pdf");

        // Release resources
        workbook.Dispose();
    }
}
Enter fullscreen mode Exit fullscreen mode

Export a Defined Print Area in C#

This is particularly useful for template-based reports where the sheet contains helper formulas or reference data outside the visible range that you don't want included in the output.

Returning PDF in ASP.NET Core

In a real backend service, you usually don't want to write files to disk — especially in containerized environments where the filesystem may be read-only or ephemeral. Here's how to convert and return the PDF entirely in memory:

using Microsoft.AspNetCore.Mvc;
using Spire.Xls;

[ApiController]
[Route("api/[controller]")]
public class ReportController: ControllerBase
{
    [HttpGet("export")]
    public IActionResult ExportToPdf()
    {
        // Load the Excel workbook
        Workbook workbook = new Workbook();
        workbook.LoadFromFile("report.xlsx");  // Ensure file exists in the correct location
        workbook.ConverterSetting.SheetFitToPage = true;

        // Convert directly to memory — no temp file needed
        using var stream = new MemoryStream();
        workbook.SaveToStream(stream, FileFormat.PDF);
        workbook.Dispose();

        // Rewind before reading
        stream.Position = 0;

        // Return as file download
        return File(
            stream.ToArray(),  // Can be optimized (For large files, consider returning the stream directly instead of ToArray())
            "application/pdf",
            "report.pdf"         // triggers download in the browser
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

A few things worth noting:

  • SaveToStream with FileFormat.PDF writes directly to the MemoryStream — no intermediate file on disk.
  • stream.Position = 0 rewinds the stream before reading; skipping this returns an empty response.
  • Content-Disposition is handled automatically by ASP.NET Core's File() result when you pass a filename as the third argument.

This pattern works cleanly in Docker containers, Azure App Service, AWS Lambda, or any environment where writing to the local filesystem isn't an option. It also avoids file I/O overhead, which can become a bottleneck under high concurrency.

Controlling Layout for Accurate Output

The conversion works — but on complex sheets, the default settings don't always produce clean output. Wide tables get sliced across pages, margins clip content, and landscape data ends up portrait. These three settings fix most of it.

Page Size & Orientation

using Spire.Xls;

Workbook workbook = new Workbook();
workbook.LoadFromFile("report.xlsx");

Worksheet sheet = workbook.Worksheets[0];

// Set paper size and orientation
sheet.PageSetup.PaperSize = PaperSizeType.PaperA4;
sheet.PageSetup.Orientation = PageOrientationType.Landscape;

sheet.SaveToPdf("report.pdf");
workbook.Dispose();
Enter fullscreen mode Exit fullscreen mode

Margins

// Values are in inches
sheet.PageSetup.TopMargin    = 0.5;
sheet.PageSetup.BottomMargin = 0.5;
sheet.PageSetup.LeftMargin   = 0.5;
sheet.PageSetup.RightMargin  = 0.5;
Enter fullscreen mode Exit fullscreen mode

Tightening the margins gives your content more room to breathe — particularly useful when you're fitting a wide table onto a single page.

Scaling (the important one)

// Force the sheet to fit within one page wide
sheet.PageSetup.FitToPagesWide = 1;
sheet.PageSetup.FitToPagesTall = 0; // 0 = no vertical limit
Enter fullscreen mode Exit fullscreen mode

FitToPagesWide = 1 is the single most effective setting for preventing wide sheets from splitting mid-column across pages. Setting FitToPagesTall = 0 lets the content grow vertically as needed — you get a clean single-column layout without squashing everything onto one page.

These three settings mirror what you'd configure in Excel's Page Layout tab before printing — if the sheet looks right there, it'll look right in the exported PDF.

Common Issues & Fixes

Fonts render as squares or tofu characters

Scenario: PDF output looks fine on Windows but shows blank boxes where text should be on your CI server or container.

Cause: The Excel file uses fonts that aren't available in the server environment. The library falls back to a missing font and renders nothing.

Fix: Install the missing fonts in your environment, or point the library to a custom font directory:

// Tell Spire.XLS where to find fonts at runtime
workbook.CustomFontPath = "/usr/share/fonts/custom";
Enter fullscreen mode Exit fullscreen mode

For Windows-style fonts on Linux, installing ttf-mscorefonts-installer via apt usually resolves the most common cases.

Charts or images missing from the PDF

Scenario: Your workbook contains charts or embedded images that simply don't appear in the exported PDF.

Cause: Chart rendering requires the sheet to be processed in a specific rendering mode. Default settings may skip embedded objects.

Fix: Make sure you're converting via the workbook-level method rather than the worksheet-level one — workbook-level conversion applies full rendering passes, including charts:

// Prefer this for sheets with charts or images
workbook.ConverterSetting.SheetFitToPage = true;
workbook.SaveToFile("report.pdf", FileFormat.PDF);
Enter fullscreen mode Exit fullscreen mode

Layout errors or crashes on Linux / Docker

Scenario: Everything works locally on Windows, but after deploying to a Linux container you get a DllNotFoundException or the PDF layout is completely broken.

Cause: Spire.XLS depends on System.Drawing.Common, which in turn requires libgdiplus — a native library that isn't included in the default .NET Linux base image.

Fix: Add the following to your Dockerfile:

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        libgdiplus \
        libc6-dev \
        libx11-dev \
    && rm -rf /var/lib/apt/lists/*
Enter fullscreen mode Exit fullscreen mode

This is the officially recommended setup for running Spire.XLS in Linux containers.

Wrap-Up

At this point, you’ve got a solid Excel-to-PDF workflow in .NET — no Office dependencies, no fragile COM automation, and no need to rebuild layouts from scratch. It works just as well for background jobs, APIs, or containerized services, and scales from simple exports to more complex reporting scenarios.

If you're dealing with document generation in your own projects, I’m curious — how are you handling Excel-to-PDF today?

Top comments (0)