如何使用 ASP.NET Core 和 IronPDF 建立集中式 PDF 生成服務
使用 ASP.NET Core 和 IronPDF 建立生產就緒的 .NET PDF API,集中管理 PDF 生成邏輯,透過 RESTful 端點實現跨應用程式的一致文件創建,支援 HTML 到 PDF 的轉換、合併、浮水印和動態模板處理。
在開發現代應用程式時,.NET 開發人員經常需要建立集中式 PDF 生成服務。無論是產生發票、報表、憑證或合同,擁有專用的 .NET PDF API 都能改善您的 PDF 產生工作流程。 它有什麼作用?它可以為您的桌面和 Web 應用程式提供一致性、可維護性和可擴充性。 管理文件內容、PDF 頁面和PDF 表單欄位變得簡單易行。
在本教程中,您將學習如何使用 ASP.NET Core 和IronPDF (一個強大的 .NET PDF 庫)建立可用於生產的 PDF API。 我們將建立 RESTful 端點,用於從 HTML 產生 PDF、合併文件、新增浮水印,並在您的 Web API 中處理各種實際的 PDF 場景。
為什麼要建立專用的 PDF API?
架構圖顯示客戶端應用程式(Web、桌面、行動)向 PDF 控制器/服務 API 層發送 HTML 內容、URL 或動態數據,該層輸出 PDF 文件。
在深入程式碼之前,讓我們先了解為什麼創建一個專用的 PDF API 是有意義的:
*集中式邏輯*:所有 PDF 產生邏輯都集中在一個地方,簡化了維護和更新。 微服務架構:非常適合服務導向的架構,其中不同的應用程式需要 PDF 功能。 效能最佳化:使用非同步操作和效能技術,更容易擴展和最佳化專用服務,以處理大型 PDF、多頁和動態資料。 語言無關**:任何客戶端應用程式都可以使用 API,而無需考慮程式語言。 *輸出一致性:確保您組織內的所有 PDF 檔案保持一致的佈局、格式和內容。
準備開始建造了嗎? 下載IronPDF 的免費試用版,並依照本教學在 .NET Framework 專案中以程式設計方式建立 PDF 檔案。
IronPDF為何是功能齊全的.NET PDF庫?
IronPDF for .NET 主頁展示了使用 C# 程式碼將 HTML 轉換為 PDF 的範例,並提供了 HTML 渲染、檔案保存和 NuGet 安裝命令等功能。
IronPDF是 .NET 開發人員首選的 PDF 庫,它提供了一套全面的功能,使 Web API 專案中的 PDF 生成變得簡單可靠。 它基於Chrome 渲染引擎構建,只需幾行程式碼即可確保像素級完美的HTML 到 PDF 轉換,同時保持所有樣式、 JavaScript 執行和響應式佈局。
IronPDF 的關鍵特性使其成為 .NET PDF API 開發的理想選擇:
*基於 Chrome 的渲染*:使用 Google Chrome 的引擎進行精確的 HTML 到 PDF 轉換,並完全支援嵌入式圖像和 Web 資源。 功能豐富:支援編輯具有數位簽章、 PDF 表單、註解、加密、壓縮等功能的文件。 建立安全 PDF :使用加密、數位簽章和文件保護來管理敏感內容。 多種輸入格式:使用 HTML、URL、圖像和Office 文件建立 PDF。 進階操作:合併頁面、分割文件、套用浮水印、建立互動式表單以及以程式設計方式操作 PDF。 跨平台支援**:可在Windows 、 Linux 、 macOS 、 Docker和雲端平台上運作。 *效能最佳化:非同步操作、高效的記憶體管理以及帶有渲染延遲選項的快速渲染。
如何設定您的PDF文檔API項目?
我們首先建立一個新的 ASP.NET Core Web API 專案並安裝必要的軟體包。
需要具備哪些先決條件?
- .NET 6.0 SDK或更高版本
- Visual Studio 2022 或 Visual Studio Code *使用 Postman或類似的 API 測試工具來測試您的 PDF REST API
如何建立專案?
首先,讓我們建立一個項目,我們將在其中建立我們的 PDF 生成工具。
dotnet new webapi -n PdfApiService
cd PdfApiServicedotnet new webapi -n PdfApiService
cd PdfApiService如何安裝 IronPDF?
接下來,透過 NuGet 將 IronPDF 新增到您的專案中:
dotnet add package IronPDFdotnet add package IronPDF或者,使用 Visual Studio 中的 NuGet 套件管理器控制台:
Install-Package IronPDF對於進階安裝選項,包括特定於平台的軟體包、 Docker 設定或Linux 配置,請查看IronPDF 安裝文件。
我應該採用哪種專案結構?
良好的 C# 開發需要維護一個乾淨且結構良好的專案資料夾。 例如:
Visual Studio 解決方案資源管理器顯示了 .NET PDF API 服務項目的資料夾結構,其中包含 Controllers、Models 和 Services 目錄。
如何建立您的第一個 PDF 端點?
讓我們建立一個簡單的端點,將 HTML 轉換為 PDF 格式。 首先,建立服務介面和實作:
如何建立 PDF 服務?
首先,將以下內容新增至您的IPdfService.cs檔案:
public interface IPdfService
{
byte[] GeneratePdfFromHtml(string htmlContent);
byte[] GeneratePdfFromUrl(string url);
}public interface IPdfService
{
byte[] GeneratePdfFromHtml(string htmlContent);
byte[] GeneratePdfFromUrl(string url);
}在PdfService.cs檔案中加入以下程式碼:
using IronPdf;
public class PdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public PdfService()
{
_renderer = new ChromePdfRenderer();
// Configure rendering options for optimal PDF generation in .NET
_renderer.RenderingOptions.MarginTop = 20;
_renderer.RenderingOptions.MarginBottom = 20;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GeneratePdfFromHtml(string htmlContent)
{
// Generate PDF from HTML using the .NET PDF API
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
}
public byte[] GeneratePdfFromUrl(string url)
{
// Convert URL to PDF in the REST API
var pdf = _renderer.RenderUrlAsPdf(url);
return pdf.BinaryData;
}
}using IronPdf;
public class PdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public PdfService()
{
_renderer = new ChromePdfRenderer();
// Configure rendering options for optimal PDF generation in .NET
_renderer.RenderingOptions.MarginTop = 20;
_renderer.RenderingOptions.MarginBottom = 20;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GeneratePdfFromHtml(string htmlContent)
{
// Generate PDF from HTML using the .NET PDF API
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
}
public byte[] GeneratePdfFromUrl(string url)
{
// Convert URL to PDF in the REST API
var pdf = _renderer.RenderUrlAsPdf(url);
return pdf.BinaryData;
}
}PdfService負責將 HTML 轉換為 PDF。 此類別使用 IronPDF 的ChromePdfRenderer ,配置頁面邊距和背景渲染等預設值,以獲得專業效果。 如需進階渲染配置,請探索IronPDF 的渲染選項。
當控制器傳遞原始 HTML 時,該服務將其渲染成高品質的 PDF,並返回位元組資料以供下載。 它還可以使用URL 轉 PDF 功能,將整個網頁直接轉換為 PDF。
如何建立控制器?
現在建立 API 的控制器。 這提供了一個可以從 HTML 產生 PDF 文件的端點,並允許您將 PDF 文件下載並保存到您的系統中。
// Controllers/PdfController.cs
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly IPdfService _pdfService;
public PdfController(IPdfService pdfService)
{
_pdfService = pdfService;
}
[HttpPost("html-to-pdf")]
public IActionResult ConvertHtmlToPdf([FromBody] HtmlRequest request)
{
try
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
// Return as downloadable file
return File(pdfBytes, "application/pdf", "document.pdf");
}
catch (Exception ex)
{
return BadRequest($"Error generating PDF: {ex.Message}");
}
}
}// Controllers/PdfController.cs
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly IPdfService _pdfService;
public PdfController(IPdfService pdfService)
{
_pdfService = pdfService;
}
[HttpPost("html-to-pdf")]
public IActionResult ConvertHtmlToPdf([FromBody] HtmlRequest request)
{
try
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
// Return as downloadable file
return File(pdfBytes, "application/pdf", "document.pdf");
}
catch (Exception ex)
{
return BadRequest($"Error generating PDF: {ex.Message}");
}
}
}然後,在HtmlRequest.cs檔案中加入以下程式碼:
// Models/HtmlRequest.cs
public class HtmlRequest
{
public string HtmlContent { get; set; }
public string FileName { get; set; } = "document.pdf";
}// Models/HtmlRequest.cs
public class HtmlRequest
{
public string HtmlContent { get; set; }
public string FileName { get; set; } = "document.pdf";
}這將設定一個 API 端點,用於將 HTML 轉換為可下載的 PDF。 當有人向api/pdf/html-to-pdf發送 HTML 時, PdfController會將轉換委託給該服務。
建立完成後,控制器會將 PDF 檔案作為可下載檔案傳回。該請求使用HtmlRequest模型,其中包含 HTML 程式碼和一個可選的檔案名稱。 這樣一來,客戶就可以輕鬆地發送 HTML 文件並收到精美的 PDF 文件。
如何註冊服務?
更新Program.cs檔案以註冊 PDF 服務:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register PDF service
builder.Services.AddSingleton<IPdfService, PdfService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapControllers();
app.Run();var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register PDF service
builder.Services.AddSingleton<IPdfService, PdfService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapControllers();
app.Run();如何處理不同類型的回覆?
您的 API 應支援根據客戶端需求傳回不同方式的 PDF 檔案:
[HttpPost("generate")]
public IActionResult GeneratePdf([FromBody] PdfRequest request)
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
switch (request.ResponseType?.ToLower())
{
case "base64":
return Ok(new
{
data = Convert.ToBase64String(pdfBytes),
filename = request.FileName
});
case "inline":
return File(pdfBytes, "application/pdf");
default: // download
return File(pdfBytes, "application/pdf", request.FileName);
}
}[HttpPost("generate")]
public IActionResult GeneratePdf([FromBody] PdfRequest request)
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
switch (request.ResponseType?.ToLower())
{
case "base64":
return Ok(new
{
data = Convert.ToBase64String(pdfBytes),
filename = request.FileName
});
case "inline":
return File(pdfBytes, "application/pdf");
default: // download
return File(pdfBytes, "application/pdf", request.FileName);
}
}這增加了一個靈活的PDF生成介面。 GeneratePdf方法不強制下載,而是讓客戶端選擇接收結果的方式:下載、在瀏覽器中內聯顯示,或進行 Base64 編碼以供 API 使用。
PdfRequest模型透過ResponseType選項擴展了HtmlRequest模型。 這使用戶能夠控制 PDF 文件的交付方式,從而使 API 更加靈活。有關在不存取檔案系統的情況下處理記憶體中的 PDF 文件,請參閱IronPDF 的記憶體流文件。
運行程式後,我們會在 Swagger 中看到以下輸出:
Swagger UI 文件顯示了 PdfApiService 端點,其中包含三個用於 PDF 操作的 POST 方法:html-to-pdf、generate 和 url-to-pdf,以及請求架構。
如何實現常見的PDF操作?
讓我們擴展服務,以處理各種 PDF 生成場景:
如何將網址轉換為PDF?
[HttpPost("url-to-pdf")]
public async Task<IActionResult> ConvertUrlToPdf([FromBody] UrlRequest request)
{
try
{
var pdfBytes = await Task.Run(() =>
_pdfService.GeneratePdfFromUrl(request.Url));
return File(pdfBytes, "application/pdf",
$"{request.FileName ?? "website"}.pdf");
}
catch (Exception ex)
{
return BadRequest($"Failed to convert URL: {ex.Message}");
}
}
public class UrlRequest
{
public string Url { get; set; }
public string FileName { get; set; }
}[HttpPost("url-to-pdf")]
public async Task<IActionResult> ConvertUrlToPdf([FromBody] UrlRequest request)
{
try
{
var pdfBytes = await Task.Run(() =>
_pdfService.GeneratePdfFromUrl(request.Url));
return File(pdfBytes, "application/pdf",
$"{request.FileName ?? "website"}.pdf");
}
catch (Exception ex)
{
return BadRequest($"Failed to convert URL: {ex.Message}");
}
}
public class UrlRequest
{
public string Url { get; set; }
public string FileName { get; set; }
}此介面將 URL 轉換為可下載的 PDF 檔案。 當 POST 請求到達/api/pdf/url-to-pdf時,控制器使用_pdfService在後台將 URL 轉換為 PDF 位元組,然後返回以供下載。 如果轉換失敗,它會顯示明確的錯誤訊息。 對於需要身份驗證的網站,請查看IronPDF 的登入文件。
我們來試試使用這個網址"https://www.apple.com/nz並測試 POST 請求。以下是我們得到的輸出:
輸出結果是什麼樣子的?
如何新增自訂浮水印?
public byte[] AddWatermarkFromFile(string filePath, string watermarkText)
{
// Load PDF directly from file
var pdf = PdfDocument.FromFile(filePath);
pdf.ApplyWatermark(
$"<h1 style='color:red;font-size:72px;'>{watermarkText}</h1>",
75,
IronPdf.Editing.VerticalAlignment.Middle,
IronPdf.Editing.HorizontalAlignment.Center
);
return pdf.BinaryData;
}public byte[] AddWatermarkFromFile(string filePath, string watermarkText)
{
// Load PDF directly from file
var pdf = PdfDocument.FromFile(filePath);
pdf.ApplyWatermark(
$"<h1 style='color:red;font-size:72px;'>{watermarkText}</h1>",
75,
IronPdf.Editing.VerticalAlignment.Middle,
IronPdf.Editing.HorizontalAlignment.Center
);
return pdf.BinaryData;
}此操作會手動載入本機檔案進行測試。 您可以進行調整,以便您的 PDF API 產生 PDF,然後輕鬆套用自訂浮水印。 有關進階浮水印選項,包括影像浮水印和自訂定位,請參閱浮水印指南。
水印輸出效果是什麼樣的?
這是一份安全文件,帶有"機密"浮水印,水印以對角線方式顯示在空白頁面上,文件 ID:BA811648DCE1FF2AAA55E7CE 顯示於頂部。
如何使用範本新增動態資料?
在實際應用中,您經常需要使用包含動態資料的範本來產生 PDF 檔案:
[HttpPost("from-template")]
public IActionResult GenerateFromTemplate([FromBody] TemplateRequest request)
{
// Simple template replacement
var html = request.Template;
foreach (var item in request.Data)
{
html = html.Replace($"{{{{{item.Key}}}}}", item.Value);
}
var pdfBytes = _pdfService.GeneratePdfFromHtml(html);
return File(pdfBytes, "application/pdf", request.FileName);
}
public class TemplateRequest
{
public string Template { get; set; }
public Dictionary<string, string> Data { get; set; }
public string FileName { get; set; } = "document.pdf";
}[HttpPost("from-template")]
public IActionResult GenerateFromTemplate([FromBody] TemplateRequest request)
{
// Simple template replacement
var html = request.Template;
foreach (var item in request.Data)
{
html = html.Replace($"{{{{{item.Key}}}}}", item.Value);
}
var pdfBytes = _pdfService.GeneratePdfFromHtml(html);
return File(pdfBytes, "application/pdf", request.FileName);
}
public class TemplateRequest
{
public string Template { get; set; }
public Dictionary<string, string> Data { get; set; }
public string FileName { get; set; } = "document.pdf";
}對於使用 Razor、Handlebars 或其他引擎的高級範本場景,請查看IronPDF 的 HTML 轉 PDF 文件。 您也可以探索 MVC 應用程式的CSHTML 轉 PDF 功能以及 Blazor 應用程式的Razor 轉 PDF 功能。 對於無頭 Razor 渲染,請參閱CSHTML 無頭指南。
如何優化效能?
建立生產級 PDF API 時,效能至關重要。 以下是一些關鍵的最佳化策略:
為什麼要使用非同步操作?
當你的專案涉及 I/O 操作時,請使用非同步編碼。 當您的 PDF 內容來自外部資源時,這一點尤其有用,例如:
- 下載 HTML 頁面 (
RenderUrlAsPdf) - 透過 HTTP 取得圖像、CSS 或字體
- 讀取/寫入檔案到磁碟或雲端存儲
這些操作可能會阻塞線程,但非同步操作可以防止 API 線程空閒等待。 有關完整的非同步 PDF 產生模式,請參閱非同步 PDF 產生指南。
例子:
public async Task<byte[]> GeneratePdfFromHtmlAsync(string htmlContent)
{
return await Task.Run(() =>
{
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
});
}public async Task<byte[]> GeneratePdfFromHtmlAsync(string htmlContent)
{
return await Task.Run(() =>
{
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
});
}我應該配置哪些渲染選項?
配置 IronPDF 以獲得最佳性能:
_renderer.RenderingOptions.EnableJavaScript = false; // If JS not needed
_renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
_renderer.RenderingOptions.RenderDelay = 0; // Remove if no JS
_renderer.RenderingOptions.Timeout = 30; // Set reasonable timeout_renderer.RenderingOptions.EnableJavaScript = false; // If JS not needed
_renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
_renderer.RenderingOptions.RenderDelay = 0; // Remove if no JS
_renderer.RenderingOptions.Timeout = 30; // Set reasonable timeout如何保護您的 PDF API?
對於任何生產環境的API來說,安全性至關重要。 以下是一種簡單的 API 金鑰認證方法:
// Middleware/ApiKeyMiddleware.cs
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string ApiKeyHeader = "X-API-Key";
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(ApiKeyHeader, out var apiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("API Key required");
return;
}
// Validate API key (in production, check against database)
var validApiKey = context.RequestServices
.GetRequiredService<IConfiguration>()["ApiKey"];
if (apiKey != validApiKey)
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Invalid API Key");
return;
}
await _next(context);
}
}
// In Program.cs
app.UseMiddleware<ApiKeyMiddleware>();// Middleware/ApiKeyMiddleware.cs
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string ApiKeyHeader = "X-API-Key";
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(ApiKeyHeader, out var apiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("API Key required");
return;
}
// Validate API key (in production, check against database)
var validApiKey = context.RequestServices
.GetRequiredService<IConfiguration>()["ApiKey"];
if (apiKey != validApiKey)
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Invalid API Key");
return;
}
await _next(context);
}
}
// In Program.cs
app.UseMiddleware<ApiKeyMiddleware>();對於高級身份驗證場景,請考慮:
- JWT 身份驗證- API 身份驗證的行業標準
- OAuth 2.0 - 用於第三方集成
- Azure AD 整合- 企業身份驗證
- API 速率限制- 防止濫用並確保公平使用
- HTTP 標頭- 自訂標頭配置以增強安全性
如何建立一個實際應用的發票產生 API?
讓我們建立一個實用的發票產生端點,以演示完整的實作過程。 本範例展示了生產環境中的 .NET PDF API 如何使用動態資料產生專業發票。
!{--01001100010010010100001001010010010000010101001001011001010111110100011101000101010101 01000101111101010011010101000100000101010010010101000100010101000100010111110101011101001000110 1010101000100100001011111010100000101001001001111010001000101010101010000110101010100101010101011 10101010001010010010010010010000010100110001011111010000100100110001001111101000011010010111111010000110100101110--
首先,在 Models 資料夾中建立一個新檔案。 在這裡,我把我的文件命名為Invoice.cs 。 然後加入以下程式碼:
public class Invoice
{
public string InvoiceNumber { get; set; }
public DateTime Date { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }
public List<InvoiceItem> Items { get; set; }
public decimal Tax { get; set; }
}
public class InvoiceItem
{
public string Description { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Total => Quantity * UnitPrice;
}public class Invoice
{
public string InvoiceNumber { get; set; }
public DateTime Date { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }
public List<InvoiceItem> Items { get; set; }
public decimal Tax { get; set; }
}
public class InvoiceItem
{
public string Description { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Total => Quantity * UnitPrice;
}接下來,為發票產生器建立一個新的服務文件。 在 Services 資料夾中,新增以下程式碼。 我建立了一個名為InvoiceService.cs的檔案。 這段程式碼用於處理發票 PDF 的樣式和佈局:
public class InvoiceService
{
private readonly ChromePdfRenderer _renderer;
public InvoiceService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.MarginTop = 10;
_renderer.RenderingOptions.MarginBottom = 10;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GenerateInvoice(Invoice invoice)
{
var html = BuildInvoiceHtml(invoice);
// Add footer with page numbers
_renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
MaxHeight = 15,
HtmlFragment = "<center><i>{page} of {total-pages}</i></center>",
DrawDividerLine = true
};
var pdf = _renderer.RenderHtmlAsPdf(html);
return pdf.BinaryData;
}
private string BuildInvoiceHtml(Invoice invoice)
{
var subtotal = invoice.Items.Sum(i => i.Total);
var taxAmount = subtotal * (invoice.Tax / 100);
var total = subtotal + taxAmount;
var itemsHtml = string.Join("", invoice.Items.Select(item =>
$@"<tr>
<td>{item.Description}</td>
<td class='text-center'>{item.Quantity}</td>
<td class='text-right'>${item.UnitPrice:F2}</td>
<td class='text-right'>${item.Total:F2}</td>
</tr>"));
return $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; }}
.invoice-header {{
background-color: #f8f9fa;
padding: 20px;
margin-bottom: 20px;
}}
table {{
width: 100%;
border-collapse: collapse;
}}
th, td {{
padding: 10px;
border-bottom: 1px solid #ddd;
}}
th {{
background-color: #007bff;
color: white;
}}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
.total-section {{
margin-top: 20px;
text-align: right;
}}
</style>
</head>
<body>
<div class='invoice-header'>
<h1>Invoice #{invoice.InvoiceNumber}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd}</p>
</div>
<div>
<h3>Bill To:</h3>
<p>{invoice.CustomerName}<br/>{invoice.CustomerAddress}</p>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{itemsHtml}
</tbody>
</table>
<div class='total-section'>
<p>Subtotal: ${subtotal:F2}</p>
<p>Tax ({invoice.Tax}%): ${taxAmount:F2}</p>
<h3>Total: ${total:F2}</h3>
</div>
</body>
</html>";
}
}public class InvoiceService
{
private readonly ChromePdfRenderer _renderer;
public InvoiceService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.MarginTop = 10;
_renderer.RenderingOptions.MarginBottom = 10;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GenerateInvoice(Invoice invoice)
{
var html = BuildInvoiceHtml(invoice);
// Add footer with page numbers
_renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
MaxHeight = 15,
HtmlFragment = "<center><i>{page} of {total-pages}</i></center>",
DrawDividerLine = true
};
var pdf = _renderer.RenderHtmlAsPdf(html);
return pdf.BinaryData;
}
private string BuildInvoiceHtml(Invoice invoice)
{
var subtotal = invoice.Items.Sum(i => i.Total);
var taxAmount = subtotal * (invoice.Tax / 100);
var total = subtotal + taxAmount;
var itemsHtml = string.Join("", invoice.Items.Select(item =>
$@"<tr>
<td>{item.Description}</td>
<td class='text-center'>{item.Quantity}</td>
<td class='text-right'>${item.UnitPrice:F2}</td>
<td class='text-right'>${item.Total:F2}</td>
</tr>"));
return $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; }}
.invoice-header {{
background-color: #f8f9fa;
padding: 20px;
margin-bottom: 20px;
}}
table {{
width: 100%;
border-collapse: collapse;
}}
th, td {{
padding: 10px;
border-bottom: 1px solid #ddd;
}}
th {{
background-color: #007bff;
color: white;
}}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
.total-section {{
margin-top: 20px;
text-align: right;
}}
</style>
</head>
<body>
<div class='invoice-header'>
<h1>Invoice #{invoice.InvoiceNumber}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd}</p>
</div>
<div>
<h3>Bill To:</h3>
<p>{invoice.CustomerName}<br/>{invoice.CustomerAddress}</p>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{itemsHtml}
</tbody>
</table>
<div class='total-section'>
<p>Subtotal: ${subtotal:F2}</p>
<p>Tax ({invoice.Tax}%): ${taxAmount:F2}</p>
<h3>Total: ${total:F2}</h3>
</div>
</body>
</html>";
}
}最後,建立一個新的控制器,用於使用 API 存取和建立發票:
[ApiController]
[Route("api/[controller]")]
public class InvoiceController : ControllerBase
{
private readonly InvoiceService _invoiceService;
public InvoiceController(InvoiceService invoiceService)
{
_invoiceService = invoiceService;
}
[HttpPost("generate")]
public IActionResult GenerateInvoice([FromBody] Invoice invoice)
{
try
{
var pdfBytes = _invoiceService.GenerateInvoice(invoice);
var fileName = $"Invoice_{invoice.InvoiceNumber}.pdf";
return File(pdfBytes, "application/pdf", fileName);
}
catch (Exception ex)
{
return StatusCode(500, $"Error generating invoice: {ex.Message}");
}
}
}[ApiController]
[Route("api/[controller]")]
public class InvoiceController : ControllerBase
{
private readonly InvoiceService _invoiceService;
public InvoiceController(InvoiceService invoiceService)
{
_invoiceService = invoiceService;
}
[HttpPost("generate")]
public IActionResult GenerateInvoice([FromBody] Invoice invoice)
{
try
{
var pdfBytes = _invoiceService.GenerateInvoice(invoice);
var fileName = $"Invoice_{invoice.InvoiceNumber}.pdf";
return File(pdfBytes, "application/pdf", fileName);
}
catch (Exception ex)
{
return StatusCode(500, $"Error generating invoice: {ex.Message}");
}
}
}對於進階發票功能,可以考慮新增條碼、二維碼、頁碼和自訂頁首/頁尾。 您還可以實施PDF/A 合規性以進行長期存檔,或與電子簽名工作流程整合。
發票輸出格式是什麼樣的?
! PDF格式發票文件,發票編號INV-1023,日期為2025年8月22日,包含一項"雜項"項目,總額為495.00美元(含稅)。
容器部署需要考慮哪些因素?
雖然本教學專注於本地開發,但這裡簡要概述如何將 PDF API 容器化:
如何建立基本的 Dockerfile?
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["PdfApiService.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet build -c Release -o /app/build
FROM build AS publish
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# IronPDF requires additional dependencies on Linux
RUN apt-get update && apt-get install -y \
libgdiplus \
libc6-dev \
libx11-dev \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["dotnet", "PdfApiService.dll"]有關 .NET PDF API 的詳細部署指南,請參閱:
IronPDF Docker 文件- 完整的容器化指南
- IronPDF Azure 部署- Azure Functions 和應用程式服務
- IronPDF AWS部署- Lambda和EC2部署
- IronPDF Linux 設定- Linux 特定配置 以遠端容器方式運作- IronPDF 引擎容器化 原生引擎與遠端引擎- 部署架構選項
錯誤處理的最佳實務有哪些?
對於容錯程序,應實現全域錯誤處理程序,以確保錯誤回應的一致性:
// Middleware/ErrorHandlingMiddleware.cs
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandlingMiddleware> _logger;
public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred processing request {Path}", context.Request.Path);
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = ex switch
{
ArgumentNullException => 400,
UnauthorizedAccessException => 401,
_ => 500
};
var response = new
{
error = "An error occurred processing your request",
message = ex.Message,
statusCode = context.Response.StatusCode
};
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}// Middleware/ErrorHandlingMiddleware.cs
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandlingMiddleware> _logger;
public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred processing request {Path}", context.Request.Path);
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = ex switch
{
ArgumentNullException => 400,
UnauthorizedAccessException => 401,
_ => 500
};
var response = new
{
error = "An error occurred processing your request",
message = ex.Message,
statusCode = context.Response.StatusCode
};
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}有關 IronPDF 的具體故障排除方案,請參閱: 快速故障排除指南 工程支援指南 自訂日誌配置 防止記憶體洩漏 效能優化技巧
準備好建置您的生產級 .NET PDF API 了嗎?
現在您已經使用 ASP.NET Core 和 IronPDF 建立了一個強大的 .NET PDF API,可以處理各種文件產生場景。 此 REST API 為您的應用程式中的集中式 PDF 操作提供了堅實的基礎。
重點總結:
- IronPDF 透過基於 Chrome 的渲染,讓 Web API 專案中的 PDF 產生變得簡單。
- 使用 IronPDF 的進階編輯工具輕鬆編輯現有 PDF 檔案。
- RESTful 設計原則確保您的 PDF API 直覺且易於維護。 適當的錯誤處理和安全措施對於生產至關重要。 透過非同步操作和快取進行效能優化,提高了可擴展性。
- 全面支援桌面和 Web 應用程序,並提供可擴展的文件解決方案。
IronPDF 讓開發人員能夠有效率地建立 PDF、保存 PDF 檔案和轉換 HTML,使其成為現代 .NET Framework 應用程式不可或缺的 PDF API。
下一步是什麼?
準備好在生產環境的 .NET PDF API 中整合 IronPDF 了嗎? 接下來,您需要執行以下步驟:
1.開始免費試用- 在您的開發環境中測試 IronPDF 的全部功能。 2.探索進階功能- 查看數位簽章、 PDF 表單、 PDF/A 合規性、元資料管理和其他進階 PDF 功能。 3.自信擴展- 查看滿足您生產 API 需求的許可選項,包括擴展和升級。
立即建立您的 .NET PDF API,並使用 IronPDF 簡化整個應用程式生態系統中的文件產生!
常見問題解答
IronPDF 在 .NET 應用程式中用於什麼用途?
IronPDF 用於在 .NET 應用程式中產生、操作和轉換 PDF,因此非常適合建立集中式 PDF 服務。
如何將 IronPDF 與 ASP.NET Core 整合?
透過安裝 IronPDF NuGet 包,可以將 IronPDF 與 ASP.NET Core 集成,從而建立集中式 PDF 生成服務。
IronPDF在PDF生成方面的主要特點是什麼?
IronPDF 的主要功能包括 HTML 轉 PDF、合併和分割 PDF、新增頁首和頁尾以及擷取文字和影像。
IronPDF 能處理複雜的 PDF 佈局嗎?
是的,IronPDF 可以處理複雜的 PDF 佈局,因為它能夠將 HTML 和 CSS 內容轉換為精確渲染的 PDF 文件。
IronPDF 是否可以自訂 PDF 建立?
是的,IronPDF 允許對 PDF 建立進行自訂,包括設定頁面大小、邊距以及新增浮水印或註解。
IronPDF是否支援PDF安全功能?
IronPDF 支援密碼保護和加密等 PDF 安全功能,以保護產生的 PDF 文件。
IronPDF可以將哪些格式轉換為PDF?
IronPDF 可以將各種格式轉換為 PDF,包括 HTML、URL 和 ASPX 文件,使其能夠靈活應用於不同的用例。
IronPDF 如何處理大規模 PDF 產生?
IronPDF 針對效能進行了最佳化,使其能夠有效地處理 .NET 應用程式中的大規模 PDF 生成任務。
IronPDF 能否用於雲端應用程式?
是的,IronPDF 可用於基於雲端的應用程序,支援在 Azure 和 AWS 等平台上部署,以實現可擴展的 PDF 服務。
IronPDF 支援哪些版本的 .NET?
IronPDF 支援多個 .NET 版本,包括 .NET Core 和 .NET Framework,確保與各種專案相容。







