
如何使用IronPDF在C#中合併兩個PDF字節陣列
在ASP.NET中使用C#從資料庫中檢索PDF文件需要三個步驟:查詢資料庫表的二進位BLOB欄位,使用IronPDF將位元組載入到File()響應將位元組返回到瀏覽器。 IronPDF處理渲染、水印和安全功能,因此您可以專注於資料存取邏輯。
如何安裝IronPDF for ASP.NET?
在撰寫任何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 IDENTITY(1,1) PRIMARY KEY,
// FileName NVARCHAR(255) NOT NULL,
// FileContent VARBINARY(MAX) NOT NULL,
// UploadedAt DATETIME2 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 FileContent 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 FileContent 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 FileName, FileContent 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("FileName"));
var pdfBytes = (byte[])reader["FileContent"];
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 FileName, FileContent FROM PdfDocuments WHERE Id = @Id"
Await Using command As New SqlCommand(query, connection)
command.Parameters.AddWithValue("@Id", id)
Await Using reader As SqlDataReader = Await command.ExecuteReaderAsync()
If Not Await reader.ReadAsync() Then
Return NotFound("Document not found.")
End If
Dim fileName As String = reader.GetString(reader.GetOrdinal("FileName"))
Dim pdfBytes As Byte() = CType(reader("FileContent"), 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.ContentType.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 (FileName, FileContent)
VALUES (@FileName, @FileContent);
SELECT SCOPE_IDENTITY();";
await using var command = new SqlCommand(insertQuery, connection);
command.Parameters.AddWithValue("@FileName", file.FileName);
command.Parameters.AddWithValue("@FileContent", pdfDocument.BinaryData);
var newId = Convert.ToInt32(await command.ExecuteScalarAsync());
return Ok(new { id = newId, fileName = file.FileName });
}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 (FileName, FileContent)
VALUES (@FileName, @FileContent);
SELECT SCOPE_IDENTITY();"
Await Using command As New SqlCommand(insertQuery, connection)
command.Parameters.AddWithValue("@FileName", file.FileName)
command.Parameters.AddWithValue("@FileContent", 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 IDENTITY | 主鍵,自增 |
| FileName | NVARCHAR(255) | 下載標頭的原始檔案名 |
| FileContent | VARBINARY(MAX) | 原始PDF二進位資料(BLOB) |
| ContentType | NVARCHAR(100) | MIME型別,例如 application/pdf |
| FileSizeBytes | BIGINT | 儲存大小以進行配額管理 |
| UploadedAt | DATETIME2 | 審核用的UTC時間戳 |
| UploadedBy | NVARCHAR(100) | 存取控制的使用者身份 |
對於需要SQL Server文件串流的大規模系統,微軟記錄了FILESTREAM功能作為一種選擇,將大型BLOB儲存在文件系統上,同時仍可通過T-SQL查詢。 但是,對於大多數ASP.NET應用程式,提供的文件高達幾百MB,VARBINARY(MAX)行記憶體儲效果良好,並簡化了部署。
如何處理錯誤並優化性能?
在生產環境中進行可靠的PDF檢索要求在每一層上進行錯誤處理——資料庫、IronPDF和HTTP響應。 下表總結了關鍵做法:
| 關注點 | 建議 | 理由 |
|---|---|---|
| 連接處置 | await using語句 | 防止連接池耗盡 |
| PdfDocument處置 | using語句 | 迅速釋放非管理的記憶體 |
| SQL注入 | 只用參數化的查詢 | 防止惡意輸入更改查詢 |
| 檔案型別驗證 | 檢查MIME型別和魔術位元組 | 在儲存之前阻止非PDF上傳 |
| 大文件處理 | 使用FileStreamResult流式響應 | 避免將整個文件載入到伺服器的記憶體中 |
| 快取 | Use IMemoryCache or IDistributedCache | 減少重複的資料庫回合 |
| 非同步操作 | async/await全程使用 | 在磁碟和網路等待期間保持執行緒自由 |
對於連接字串管理,將值儲存在appsettings.json中,切勿在源文件中硬編碼。 在本地開發期間使用ASP.NET Core的內建秘密管理,在生產環境中使用Azure秘鑰保管庫或AWS秘密管理器。 絕不能將連接字串或授權金鑰提交到源控制中。
在提供大型PDF文件時,考慮返回一個由FileStreamResult,而不是將整個位元組陣列載入到記憶體中。 對於非常大的文件——超過100 MB——SQL Server FILESTREAM API允許直接從文件系統塊狀流化。
快取頻繁存取的文件
如果某些PDF文件被重複請求——例如,條款和條件文件或產品目錄——在IMemoryCache中快取位元組陣列可以避免重複的資料庫回合。 在IMemoryCache,然後注入到控制器中,在查詢資料庫之前檢查快取。 設置一個絕對過期,與文件的預期更新頻率相匹配。 當文件更新時,以密鑰移除快取條目,使下一次請求獲取新版。
對於分佈式場景——例如具有多個伺服器實例的負載均衡部署——用靠Redis或SQL Server支持的IMemoryCache。 ASP.NET Core的分佈式快取抽象保持控制器程式碼幾乎不變; 只有Program.cs中的註冊改變。
如何跨平台部署使用IronPDF的PDF檢索?
IronPDF可以在Linux、Windows和macOS上運行,無需單獨的Chromium安裝或任何配置更改。 同一NuGet包針對所有平台,因此無論您部署到:
- 使用IIS的Windows伺服器
- Docker或Kubernetes上的Ubuntu容器
- Azure應用服務(Linux或Windows)
- AWS Elastic Beanstalk
部署到Docker和Linux
對於Docker部署,將IronPDF依賴項新增到您的Dockerfile中。IronPDF Linux文件提供了Debian和Alpine基礎映像所需的精確apt包。 典型的多階段Dockerfile在運行時映像階段中安裝OS依賴項,然後在上面複製已發佈的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方法、僅選擇位元組欄而不是完整實體的投影。
您的下一步該怎麼做?
在ASP.NET Core中使用C#和IronPDF從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擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。
相關文章


