
如何使用IronPDF在C#中合并两个PDF字节数组
在ASP.NET中使用C#从数据库检索PDF文件需要三个步骤:查询数据库表中的二进制BLOB列,使用IronPDF将字节加载到File()响应将字节返回到浏览器。 IronPDF 负责渲染、水印和安全功能,让您可以专注于数据访问逻辑。
如何为 ASP.NET 安装 IronPDF?
在编写任何 PDF 获取代码之前,请通过 NuGet 包管理器将 IronPDF 添加到您的项目中:
安装后,在调用任何IronPDF方法之前,在appsettings.json中设置您的许可证密钥:
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"IronPDF 支持.NET 10 、.NET 8、.NET 6 和 .NET Framework 4.6.2+。 它可在 Windows、Linux 和 macOS 上运行,无需任何额外的依赖项或无头浏览器安装。 提供免费试用许可证供您评估。
如何设置 SQL Server 数据库表?
最常见的方法是将PDF文件存储为SQL Server VARBINARY(MAX)列中的二进制数据。 这样可以将文档及其元数据保存在单个表中,简化备份,并避免文件系统路径管理。
使用以下 SQL 脚本创建存储表:
// SQL Server table definition (run this in SSMS or via EF migrations)
// CREATE TABLE PdfDocuments (
// ID INT 身份(1,1) PRIMARY KEY,
// 文件名 NVARCHAR(255) NOT NULL,
// 文件内容 VARBINARY(MAX) NOT NULL,
// 上传于 日期时间2 DEFAULT GETUTCDATE()
// );net表格存在后,在appsettings.json中配置连接字符串:
// appsettings.json snippet (not C# -- shown as reference)
// "ConnectionStrings": {
// "DefaultConnection": "Server=localhost;Database=PdfStorage;Integrated Security=True;"
// }' appsettings.json snippet (not VB.NET -- shown as reference)
' "ConnectionStrings": {
' "DefaultConnection": "Server=localhost;Database=PdfStorage;Integrated Security=True;"
' }通过在Program.cs中使用依赖注入注册连接字符串:
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
IronPdf.License.LicenseKey = builder.Configuration["IronPdf:LicenseKey"];
var app = builder.Build();
app.MapControllers();
app.Run();Imports Microsoft.Extensions.DependencyInjection
Dim builder = WebApplication.CreateBuilder(args)
builder.Services.AddControllers()
builder.Services.AddSingleton(Of IConfiguration)(builder.Configuration)
IronPdf.License.LicenseKey = builder.Configuration("IronPdf:LicenseKey")
Dim app = builder.Build()
app.MapControllers()
app.Run()如何在 ASP.NET Core 中从 SQL Server 检索 PDF 文件?
检索模式遵循三个步骤:打开连接,执行参数化的SELECT查询,并将二进制列读入byte[]。 然后IronPDF将该数组加载到 PdfDocument 对象中以进行可选处理,然后流式传输到客户端。
构建 API 控制器
创建一个控制器,该控制器公开用于内联显示和文件下载的 GET 端点:
using IronPdf;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly string _connectionString;
public PdfController(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string not found.");
}
[HttpGet("{id}")]
public async Task<IActionResult> GetPdf(int id)
{
byte[] pdfBytes = await RetrievePdfBytesAsync(id);
if (pdfBytes is null || pdfBytes.Length == 0)
return NotFound("PDF document not found.");
// Load into IronPDF for validation or optional modification
using var pdfDocument = new PdfDocument(pdfBytes);
// Inline display -- browser opens PDF viewer
Response.Headers.Append("Content-Disposition", "inline; filename=\"document.pdf\"");
return File(pdfDocument.BinaryData, "application/pdf");
}
private async Task<byte[]> RetrievePdfBytesAsync(int documentID)
{
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
const string query = "SELECT 文件内容 FROM PdfDocuments WHERE ID = @ID";
await using var command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@ID", documentID);
var result = await command.ExecuteScalarAsync();
return result as byte[] ?? Array.Empty<byte>();
}
}Imports IronPdf
Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.Data.SqlClient
<ApiController>
<Route("api/[controller]")>
Public Class PdfController
Inherits ControllerBase
Private ReadOnly _connectionString As String
Public Sub New(configuration As IConfiguration)
_connectionString = configuration.GetConnectionString("DefaultConnection")
If _connectionString Is Nothing Then
Throw New InvalidOperationException("Connection string not found.")
End If
End Sub
<HttpGet("{id}")>
Public Async Function GetPdf(id As Integer) As Task(Of IActionResult)
Dim pdfBytes As Byte() = Await RetrievePdfBytesAsync(id)
If pdfBytes Is Nothing OrElse pdfBytes.Length = 0 Then
Return NotFound("PDF document not found.")
End If
' Load into IronPDF for validation or optional modification
Using pdfDocument As New PdfDocument(pdfBytes)
' Inline display -- browser opens PDF viewer
Response.Headers.Append("Content-Disposition", "inline; filename=""document.pdf""")
Return File(pdfDocument.BinaryData, "application/pdf")
End Using
End Function
Private Async Function RetrievePdfBytesAsync(documentID As Integer) As Task(Of Byte())
Await Using connection As New SqlConnection(_connectionString)
Await connection.OpenAsync()
Const query As String = "SELECT 文件内容 FROM PdfDocuments WHERE ID = @ID"
Await Using command As New SqlCommand(query, connection)
command.Parameters.AddWithValue("@ID", documentID)
Dim result = Await command.ExecuteScalarAsync()
Return If(TryCast(result, Byte()), Array.Empty(Of Byte)())
End Using
End Using
End Function
End Class该控制器使用参数化查询来防止SQL注入,并使用SqlCommand。 PdfDocument类验证字节数组并公开BinaryData属性以进行流式传输。
返回一个可供下载的指定文件
当用户需要保存文档而不是内联查看时,将attachment并传递原始文件名:
[HttpGet("download/{id}")]
public async Task<IActionResult> DownloadPdf(int id)
{
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
const string query = "SELECT 文件名, 文件内容 FROM PdfDocuments WHERE ID = @ID";
await using var command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@ID", documentID);
await using var reader = await command.ExecuteReaderAsync();
if (!await reader.ReadAsync())
return NotFound("Document not found.");
var fileName = reader.GetString(reader.GetOrdinal("文件名"));
var pdfBytes = (byte[])reader["文件内容"];
using var pdfDocument = new PdfDocument(pdfBytes);
return File(pdfDocument.BinaryData, "application/pdf", fileName);
}Imports System.Data.SqlClient
Imports Microsoft.AspNetCore.Mvc
<HttpGet("download/{id}")>
Public Async Function DownloadPdf(id As Integer) As Task(Of IActionResult)
Await Using connection As New SqlConnection(_connectionString)
Await connection.OpenAsync()
Const query As String = "SELECT 文件名, 文件内容 FROM PdfDocuments WHERE ID = @ID"
Await Using command As New SqlCommand(query, connection)
command.Parameters.AddWithValue("@ID", id)
Await Using reader = Await command.ExecuteReaderAsync()
If Not Await reader.ReadAsync() Then
Return NotFound("Document not found.")
End If
Dim fileName As String = reader.GetString(reader.GetOrdinal("文件名"))
Dim pdfBytes As Byte() = CType(reader("文件内容"), Byte())
Using pdfDocument As New PdfDocument(pdfBytes)
Return File(pdfDocument.BinaryData, "application/pdf", fileName)
End Using
End Using
End Using
End Using
End Function将attachment。 ASP.NET Core 可以正确处理包含空格的文件名。
如何给下载的PDF文件添加水印?
检索后最实用的操作之一是在提供文档之前,在每一页上添加水印。 这对于机密报告、文件草稿或任何需要明显安全标记的文件都很有用。
使用 IronPDF 应用 HTML 水印
IronPDF 的水印 API 接受任何 HTML 字符串,这意味着您可以使用内联 CSS 设置水印文本的样式。 将透明度调低,使底层内容仍然清晰可读:
[HttpGet("watermarked/{id}")]
public async Task<IActionResult> GetWatermarkedPdf(int id)
{
byte[] pdfBytes = await RetrievePdfBytesAsync(id);
if (pdfBytes is null || pdfBytes.Length == 0)
return NotFound("PDF document not found.");
using var pdfDocument = new PdfDocument(pdfBytes);
// HTML watermark applied to every page
string watermarkHtml = "<h2 style='color:red; opacity:0.4; font-family:Arial;'>CONFIDENTIAL</h2>";
pdfDocument.ApplyWatermark(
watermarkHtml,
rotation: 30,
verticalAlignment: VerticalAlignment.Middle,
horizontalAlignment: HorizontalAlignment.Center
);
return File(pdfDocument.BinaryData, "application/pdf");
}Imports Microsoft.AspNetCore.Mvc
<HttpGet("watermarked/{id}")>
Public Async Function GetWatermarkedPdf(id As Integer) As Task(Of IActionResult)
Dim pdfBytes As Byte() = Await RetrievePdfBytesAsync(id)
If pdfBytes Is Nothing OrElse pdfBytes.Length = 0 Then
Return NotFound("PDF document not found.")
End If
Using pdfDocument As New PdfDocument(pdfBytes)
' HTML watermark applied to every page
Dim watermarkHtml As String = "<h2 style='color:red; opacity:0.4; font-family:Arial;'>CONFIDENTIAL</h2>"
pdfDocument.ApplyWatermark(
watermarkHtml,
rotation:=30,
verticalAlignment:=VerticalAlignment.Middle,
horizontalAlignment:=HorizontalAlignment.Center
)
Return File(pdfDocument.BinaryData, "application/pdf")
End Using
End FunctionApplyWatermark方法接受标准的HTML和CSS,因此您可以完全控制字体、颜色、不透明度和位置。 水印会自动应用于文档中的所有页面。 有关PDF 的其他操作功能,包括添加图像印章、添加页眉和页脚或合并多个文档,请参阅 IronPDF 文档。
如何将上传的PDF文件存储回SQL Server?
完成往返流程需要一个上传端点,该端点读取传入的表单文件并将其写入数据库。 这与上述检索端点配合使用,构成了一个完整的文档管理系统:
[HttpPost("upload")]
public async Task<IActionResult> UploadPdf(IFormFile file)
{
if (file is null || file.Length == 0)
return BadRequest("No file uploaded.");
if (!file.内容类型.Equals("application/pdf", StringComparison.OrdinalIgnoreCase))
return BadRequest("Only PDF files are accepted.");
using var memoryStream = new MemoryStream();
await file.CopyToAsync(memoryStream);
byte[] pdfBytes = memoryStream.ToArray();
// Validate using IronPDF before storage
using var pdfDocument = new PdfDocument(pdfBytes);
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
const string insertQuery = @"
INSERT INTO PdfDocuments (文件名, 文件内容)
VALUES (@文件名, @文件内容);
SELECT SCOPE_IDENTITY();";
await using var command = new SqlCommand(insertQuery, connection);
command.Parameters.AddWithValue("@文件名", file.文件名);
command.Parameters.AddWithValue("@文件内容", pdfDocument.BinaryData);
var newID = Convert.ToInt32(await command.ExecuteScalarAsync());
return Ok(new { id = newID, fileName = file.文件名 });
}Imports System
Imports System.IO
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Http
Imports Microsoft.AspNetCore.Mvc
Imports System.Data.SqlClient
Imports IronPdf
<HttpPost("upload")>
Public Async Function UploadPdf(file As IFormFile) As Task(Of IActionResult)
If file Is Nothing OrElse file.Length = 0 Then
Return BadRequest("No file uploaded.")
End If
If Not file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) Then
Return BadRequest("Only PDF files are accepted.")
End If
Using memoryStream As New MemoryStream()
Await file.CopyToAsync(memoryStream)
Dim pdfBytes As Byte() = memoryStream.ToArray()
' Validate using IronPDF before storage
Using pdfDocument As New PdfDocument(pdfBytes)
Await Using connection As New SqlConnection(_connectionString)
Await connection.OpenAsync()
Const insertQuery As String = "
INSERT INTO PdfDocuments (文件名, 文件内容)
VALUES (@文件名, @文件内容);
SELECT SCOPE_IDENTITY();"
Await Using command As New SqlCommand(insertQuery, connection)
command.Parameters.AddWithValue("@文件名", file.FileName)
command.Parameters.AddWithValue("@文件内容", pdfDocument.BinaryData)
Dim newID As Integer = Convert.ToInt32(Await command.ExecuteScalarAsync())
Return Ok(New With {.id = newID, .fileName = file.FileName})
End Using
End Using
End Using
End Using
End Function使用PdfDocument进行存储前验证,以确保只有可解析且结构良好的PDF文件进入数据库。 如果字节数组损坏或被截断,IronPDF会抛出一个异常,您可以捕获并作为400 Bad Request响应返回。
PDF 存储的关键表和列类型有哪些?
你使用的模式会影响查询性能和存储效率。 下表显示了 SQL Server 的推荐列配置:
| 列 | 数据类型 | 翻译目的 |
|---|---|---|
| ID | INT 身份 | 主键,自动递增 |
| 文件名 | NVARCHAR(255) | 下载头文件的原始文件名 |
| 文件内容 | VARBINARY(MAX) | 原始PDF二进制数据(BLOB) |
| 内容类型 | NVARCHAR(100) | MIME 类型,例如 application/pdf |
| 文件大小(字节) | 大情报 | 用于配额管理的存储大小 |
| 上传于 | 日期时间2 | 用于审计的UTC时间戳 |
| 上传者 | NVARCHAR(100) | 用于访问控制的用户身份 |
对于需要 SQL Server 文件流的大型系统,Microsoft 将FILESTREAM 功能作为替代方案记录下来,该功能将大型 BLOB 存储在文件系统中,同时仍可通过 T-SQL 进行查询。 然而,对于服务几个百兆字节的文档的大多数ASP.NET应用程序,VARBINARY(MAX)行内存储效果良好,并简化了部署。
如何处理错误并优化性能?
生产环境中可靠的 PDF 检索需要在每个层面进行错误处理——数据库、IronPDF 和 HTTP 响应。 下表总结了关键做法:
| 忧虑 | 建议 | 原因 |
|---|---|---|
| 连接处置 | await using语句 | 防止连接池耗尽 |
| PDF文档处理 | using语句 | 及时释放未管理的内存 |
| SQL注入 | 仅限参数化查询 | 防止恶意输入篡改查询 |
| 文件类型验证 | 检查 MIME 类型和魔数字节 | 存储前阻止非 PDF 文件的上传 |
| 大文件处理 | 使用FileStreamResult流响应 | 避免将整个文件加载到服务器内存中 |
| 缓存 | 使用IMemoryCache或IDistributedCache | 减少重复的数据库往返次数 |
| 异步操作 | async / await过程 | 在磁盘和网络等待期间保持线程空闲。 |
对于连接字符串管理,将值存储在appsettings.json中,切勿在源文件中硬编码。 在本地开发期间使用 ASP.NET Core内置的密钥管理,在生产环境中使用 Azure Key Vault 或 AWS Secrets Manager。 永远不要将连接字符串或许可证密钥提交到源代码控制系统中。
在服务大型PDF文件时,考虑返回由FileStreamResult,而不是将整个字节数组加载到内存中。 对于超过 100 MB 的大型文档, SQL Server FILESTREAM API可以直接从文件系统进行分块流式传输。
缓存常用文档
如果某些PDF文件被反复请求,例如条款和条件文档或产品目录,则在IMemoryCache中缓存字节数组可以避免反复的数据库来回。 在IMemoryCache,然后将其注入到控制器中,并在查询数据库之前检查缓存。 设置一个与文档预期更新频率相匹配的绝对过期时间。 当文档更新时,按键删除缓存条目,以便下次请求获取新版本。
对于分布式场景,例如具有多个服务器实例的负载平衡部署,将IMemoryCache替换为由Redis或SQL Server支持的IDistributedCache。 ASP.NET Core 的分布式缓存抽象使控制器代码几乎完全相同; 仅Program.cs中的注册发生变化。
如何使用 IronPDF 实现跨平台 PDF 检索?
IronPDF 可在 Linux、Windows 和 macOS 上运行,无需单独安装 Chromium 或进行任何配置更改。 同一个 NuGet 包适用于所有平台,因此无论您部署到哪个平台,您的 PDF 控制器都能正常工作:
- 带有 IIS 的 Windows Server
- 在 Docker 或 Kubernetes 上运行的 Ubuntu 容器
- Azure 应用服务(Linux 或 Windows)
- AWS Elastic Beanstalk
部署到 Docker 和 Linux
对于 Docker 部署,请将 IronPDF 依赖项添加到 Dockerfile 中。IronPDF Linux 文档提供了 Debian 和 Alpine 基础镜像所需的确切 apt 软件包。 典型的多阶段 Dockerfile 会在运行时镜像阶段安装操作系统依赖项,然后将已发布的 ASP.NET 应用程序复制到其上。使用 Azure 时, Azure 部署指南涵盖了应用服务配置,包括支持大规模 PDF 渲染的内存和 CPU 设置。
由于 IronPDF 捆绑了自己的基于 Chromium 的渲染引擎,因此您无需在服务器上安装单独的浏览器。 与需要系统级浏览器的解决方案相比,这大大简化了 Linux 容器的设置。 IronPDF 团队每次发布新版本都会针对最常见的 Linux 基础镜像进行测试,因此您可以放心,Alpine 或 Debian 容器可以开箱即用。
使用 Entity Framework Core 而不是 ADO.NET
IronPDF 还集成了Entity Framework Core ,作为原始 ADO.NET 的替代方案。 如果您的项目已经使用EF Core,您可以将byte[]属性,并让EF处理查询生成。 这种方法可以显著减少样板代码,并且可以通过 EF 的 LINQ 提供程序更轻松地添加筛选、分页和审计行为。
这样做的代价是,EF Core 会将整个 BLOB 作为实体图的一部分加载到内存中。 对于非常大的PDF文件,考虑使用原生ADO.NET或EF Core的FromSql方法和仅选择字节数组列而不是完整实体的投影。
下一步计划是什么?
使用C#和IronPDF在ASP.NET Core中从SQL Server数据库检索PDF文件遵循一个明确的模式:使用参数化SELECT查询BLOB列,将字节加载到Content-Disposition头返回二进制数据。 IronPDF 增加了在文档离开服务器之前对其进行验证、添加水印、合并或保护的功能。
要进一步了解 IronPDF 的文档管理功能,请探索以下资源:
IronPDF 从 HTML 生成 PDF——动态生成 PDF 并将其直接存储到您的数据库中 IronPDF 合并和拆分 PDF——将检索到的文档合并成单个响应
- IronPDF 安全性和权限——在提供敏感文档之前添加密码保护 IronPDF HTML 转 PDF 教程——将网页内容转换为 PDF 以便存档
- IronPDF PDF 加盖印章-- 将文本和图像印章应用于检索到的文件
- IronPDF 许可——查看开发、测试和生产用途的许可级别
首先获取IronPDF 的免费试用许可证,即可不受限制地测试所有功能。 该试验产生带有水印的输出; 使用付费许可证密钥即可去除水印。 本文中使用的每种方法的完整API 参考文档和代码示例均可在 IronPDF 网站上找到。
如果您的项目已在使用 Entity Framework Core, IronPDF EF Core 集成指南将展示如何在保持 IronPDF 处理管道不变的情况下,用实体模型替换原始 ADO.NET。对于使用 .NET 10 和最新 ASP.NET Core 功能的团队,此处描述的模式无需修改即可使用——IronPDF 支持所有活跃的 .NET LTS 和 STS 版本。
请查看IronPDF 定价页面,找到适合您部署的许可证级别。 单个开发者许可证涵盖本地开发和测试; SaaS 产品和具有多个服务器的本地部署均可获得再分发许可。

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。
相关文章


