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
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);
}
}
}
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();
π 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();
π 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.
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();
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();
});
}
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:
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}");
}
});
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");
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);
}
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);
}
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)