DEV Community

Cover image for How to Merge PDFs in ASP.NET Core Without Office or Interop
Chloe
Chloe

Posted on • Edited on

How to Merge PDFs in ASP.NET Core Without Office or Interop

Need to merge PDF files in a .NET application?

If you're running on ASP.NET Core, Docker, Azure App Service, or Linux, relying on Microsoft Office or Interop isn't an option. Office automation was never designed for server-side workloads, and Microsoft explicitly discourages using Office applications in unattended environments.

Fortunately, PDF merging can be done entirely in managed code.

In fact, the merge itself usually takes only a few lines of code. The harder part is making sure it survives production workloads.

In this guide, you'll learn how to:

  • Merge multiple PDFs in C#
  • Avoid common PDF merging pitfalls
  • Handle large documents safely
  • Build a PDF merge API with ASP.NET Core
  • Extend merged PDFs with page selection, watermarks, and numbering

Let's start with the simplest implementation.

Quick Start: Merge Multiple PDFs in C

For the examples below, we'll use Spire.PDF. The same concepts apply to most modern .NET PDF libraries.

Install the package:

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

Then merge multiple PDF files in C# with just a few lines of code:

using Spire.Pdf;

namespace MergePDFs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Specify the PDF files to be merged
            string[] files = new string[] {"sample0.pdf", "sample1.pdf", "sample2.pdf"};

            // Merge PDF files 
            PdfDocumentBase pdf = PdfDocument.MergeFiles(files);

            // Save the result file
            pdf.Save("MergePDF.pdf", FileFormat.PDF);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Merge multiple PDF files in C#

That's all you need for a basic merge.

In a real application, however, PDF merging often becomes more complicated once larger files, different document sources, and production workloads are involved.

Why Developers Move Away from Office Automation

Many developers first encounter document automation through Microsoft Office Interop.

It often works fine on a local machine.

Then the application gets deployed.

Suddenly, you start seeing:

  • Missing Office installations
  • Permission issues
  • Random COM exceptions
  • Processes that never terminate
  • High memory consumption
  • Deployment headaches in containers

PDF merging doesn't require Office at all, so introducing Office dependencies simply adds complexity without providing any benefit.

A dedicated PDF library is typically more reliable, easier to deploy, and better suited for server environments.

Common PDF Merging Problems (And How to Fix Them)

Even with a straightforward API, PDF merging can go wrong in a few predictable ways. This section covers the most common ones β€” starting with the issues that tend to cause the most confusion.

Mistake #1: Forgetting to Dispose of PDF Objects

The merged file is generated, but when you try to open it, your PDF reader throws an error, or the file size looks suspiciously small.

Why does this happen?

The most common cause is that SaveToFile() or Close() was never called β€” or was called in the wrong order. If the program exits or throws an exception before the file is properly finalized, the output will be incomplete.

How to fix it

Always release resources after use.

sourceDocument.Close();
mergedDocument.Close();
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Tip: Use using statements where possible to ensure proper disposal.

Mistake #2: Assuming Fonts Will Always Exist

Text in the merged PDF appears garbled, substituted with a fallback font, or missing entirely β€” even though the original files looked fine.

Why does this happen?

PDFs may reference fonts without embedding them. When those fonts aren’t available in the runtime environment, the merged result can display incorrectly.

How to fix it

The most reliable solution is to ensure fonts are embedded in the source PDFs before merging. This guarantees consistent rendering across environments.

If you don’t control the source files, process and merge them using a consistent environment, and avoid relying on system-installed fonts.

PdfDocument mergedDocument = new PdfDocument();

foreach (string file in inputFiles)
{
    PdfDocument temp = new PdfDocument(file);
    mergedDocument.AppendPage(temp);
    temp.Close();
}

mergedDocument.SaveToFile(outputFile);
mergedDocument.Close();
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ In production, always test with real-world documentsβ€”not just simple PDFs.

Mistake #3: Loading Every PDF into Memory

The merge works fine for small files, but throws a System.OutOfMemoryException β€” or causes noticeable memory pressure β€” when the input files are large or numerous.

Why does this happen?

By default, loading a PdfDocument reads the entire file into memory. If you're merging ten 50MB PDFs, you're potentially holding 500MB in memory at once β€” before the output document is even written.

Memory loading mistakes in PDF processing

How to fix it

Process files one at a time and release each one before loading the next. Avoid holding all source documents open simultaneously:

PdfDocument merged = new PdfDocument();

foreach (string file in inputFiles)
{
    using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
    {
        PdfDocument temp = new PdfDocument(fs);
        merged.AppendPage(temp);
        temp.Close();
    }
}

merged.SaveToFile(outputFile);
merged.Close();
Enter fullscreen mode Exit fullscreen mode

Going further

For very large batches, consider merging in chunks β€” combine files in groups of 5–10, write each chunk to a temp file, then do a final merge of the temp files. This keeps peak memory usage bounded regardless of input size.

Handling Large Volumes Efficiently

Async Batch Processing for Large Volumes

For pipelines that process many files at once, avoid blocking threads on I/O. Here's a simple async wrapper:

public async Task<byte[]> MergePdfsAsync(IEnumerable<string> filePaths)
{
    // Since Spire.PDF's MergeFiles doesn't support async I/O,
    // you can omit the async wrapper in practice, or just add a caching layer
    return await Task.Run(() =>
    {
        var filesArray = filePaths.ToArray();

        // Use the officially recommended MergeFiles method
        using var mergedDocument = PdfDocument.MergeFiles(filesArray);

        using var output = new MemoryStream();
        mergedDocument.SaveToStream(output);
        mergedDocument.Close();

        return output.ToArray();
    });
}
Enter fullscreen mode Exit fullscreen mode

For high-throughput scenarios, pair this with a queue (e.g., Azure Service Bus or a simple Channel<T>) to process merge jobs one at a time rather than in parallel β€” PDF merging is memory-intensive enough that concurrency can backfire.

Real-World Scenario: Exposing Merge as an ASP.NET Core API Endpoint

If you're building a service that accepts PDF uploads and returns a merged file, here's a minimal endpoint structure:

PDF merge API workflow

app.MapPost("/merge-stream", async (HttpRequest request) =>
{
    var files = request.Form.Files;
    if (files.Count < 2)
        return Results.BadRequest("At least two files are required.");

    PdfDocument merged = new PdfDocument();

    try
    {
        foreach (var file in files)
        {
            using var stream = file.OpenReadStream();
            // Load PDF from stream
            using var tempDoc = new PdfDocument(stream);

            // Insert all pages
            for (int i = 0; i < tempDoc.Pages.Count; i++)
            {
                merged.InsertPage(tempDoc, i, i);
            }
        }

        using var output = new MemoryStream();
        merged.SaveToStream(output);
        merged.Close();

        output.Position = 0;
        return Results.File(output.ToArray(), "application/pdf", "merged.pdf");
    }
    catch (Exception ex)
    {
        merged.Close();
        return Results.Problem($"Error merging PDFs: {ex.Message}");
    }
});
Enter fullscreen mode Exit fullscreen mode

A few things to keep in mind for production use:

  • Validate file types before processing
  • Set a reasonable size limit per upload
  • Consider running the merge in a background job for large files rather than blocking the request thread

Beyond Basic Merging

In many real-world workflows, merging PDFs is only the first step.

Once the final document has been assembled, developers often need to perform additional operations such as selecting specific pages, applying watermarks, or adding page numbers. Most modern PDF libraries support these tasks without requiring major changes to the merge workflow.

Merging Specific Pages Only

Sometimes you don't need the entire document β€” just merge a range of pages from each source file.

A typical implementation looks like this:

PdfDocument newPDF = new PdfDocument();

// Insert selected pages
newPDF.InsertPageRange(pdfs[0], 1, 2);  // Pages 1-2 from first PDF
newPDF.InsertPage(pdfs[1], 0);          // First page from second PDF
newPDF.InsertPage(pdfs[2], 1);          // Second page from third PDF

newPDF.SaveToFile("SelectivePageMerging.pdf");
Enter fullscreen mode Exit fullscreen mode

Merging Specific Pages Only in Csharp

This is useful when you're pulling specific sections from multiple reports into a single summary document.

Adding a Watermark During Merge

If you need to stamp each page with a watermark β€” a company name, "CONFIDENTIAL", a draft label β€” the merge step is a natural place to do it.

foreach (var page in pdf.Pages)
{
     page.Canvas.SetTransparency(0.5f);
     page.Canvas.TranslateTransform(page.Canvas.Size.Width / 2, page.Canvas.Size.Height / 2);
     page.Canvas.RotateTransform(-45);
     page.Canvas.DrawString("CONFIDENTIAL", font, PdfBrushes.DarkGray, -150, -25);
     page.Canvas.SetTransparency(1f);
}
Enter fullscreen mode Exit fullscreen mode

Adding a Watermark During Merge

Adjust the transparency, font size, and position to suit your layout.

Adding Page Numbers After Merging

Page numbers should reflect the final document, not the originals β€” so add them after the merge is complete.

A simplified implementation might look like this:

for (int i = 0; i < total; i++)
{
     var page = pdf.Pages[i];
     string text = $"Page {i + 1} of {total}";
     float x = page.Canvas.ClientSize.Width - font.MeasureString(text).Width - 50f;
     page.Canvas.DrawString(text, font, PdfBrushes.Black, x, page.Canvas.ClientSize.Height - 50f);
}
Enter fullscreen mode Exit fullscreen mode

Adding Page Numbers After Merging

Choosing a PDF Library

For simple PDF merging, most modern .NET libraries will get the job done.

The differences become more noticeable when you need advanced features, commercial support, or specific licensing models.

Here's a quick rule of thumb:

  • Spire.PDF β€” easy to integrate and well-suited for general-purpose PDF processing

  • PDFsharp β€” a good free option for basic PDF workflows

  • iText 7 β€” ideal for advanced document manipulation and enterprise requirements

  • Aspose.PDF β€” a feature-rich choice for large document-processing projects

For most ASP.NET Core applications, choosing a library that's stable, actively maintained, and compatible with your licensing requirements matters more than the merging API itself.

FAQs

Can I merge PDFs on Linux?

Yes. Most modern .NET PDF libraries work on Linux without requiring Microsoft Office.

Can I merge PDFs inside Docker containers?

Yes. Dedicated PDF libraries are generally much better suited for containerized deployments than Office automation.

Do I need Microsoft Office installed?

No. PDF merging can be performed entirely in managed code.

Is Microsoft.Office.Interop suitable for ASP.NET Core?

Generally, no. Microsoft does not recommend using Office automation in unattended server environments. For ASP.NET Core applications, dedicated PDF libraries are typically more reliable and easier to deploy.

What is the biggest challenge when merging PDFs?

In production environments, memory usage and document quality (such as fonts and embedded resources) usually cause more issues than the merge operation itself.

Conclusion

The actual code required to merge PDFs in ASP.NET Core is surprisingly small.

What usually causes problems in production isn't the merge operation itselfβ€”it's everything around it:

  • Resource cleanup
  • Memory usage
  • Font availability
  • Upload validation

By avoiding Office dependencies and understanding these common pitfalls, you can build a PDF merge service that runs reliably in ASP.NET Core, Docker containers, and cloud environments.

With the right PDF library, merging PDFs in ASP.NET Core can be completely independent of Microsoft Office, making deployment simpler and far more reliable across servers, containers, and cloud platforms.

Top comments (0)