使用IRONPDF 如何使用ASP.NET Core和IronPDF构建一个集中式的PDF生成服务 Curtis Chau 已更新:2026年2月10日 下载 IronPDF NuGet 下载 DLL 下载 Windows 安装程序 免费试用 LLM副本 LLM副本 将页面复制为 Markdown 格式,用于 LLMs 在 ChatGPT 中打开 向 ChatGPT 咨询此页面 在双子座打开 向 Gemini 询问此页面 在 Grok 中打开 向 Grok 询问此页面 打开困惑 向 Perplexity 询问有关此页面的信息 分享 在 Facebook 上分享 分享到 X(Twitter) 在 LinkedIn 上分享 复制链接 电子邮件文章 使用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? 在深入研究代码之前,让我们了解为什么创建一个专门的PDF API是有意义的: 集中化逻辑:所有PDF生成逻辑都集中在一个地方,简化了维护和更新。 微服务架构:适用于需要PDF功能的面向服务的架构中的多种应用程序。 性能优化:使用异步操作和性能技术,便于扩展和优化专用服务以处理大型PDF、多页和动态数据。 语言无关:任何客户端应用程序都可以使用API,无论编程语言如何。 一致输出:确保您组织中的所有PDF保持一致的布局、格式和内容。 准备好开始构建了吗? 下载IronPDF的免费试用版,并按此教程一起编程实现.NET Framework项目中的PDF文件创建。 是什么让IronPDF成为完整的.NET PDF库? 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 PdfApiService dotnet new webapi -n PdfApiService cd PdfApiService SHELL 如何安装IronPDF? 接下来,通过NuGet将IronPDF添加到您的项目中: dotnet add package IronPDF dotnet add package IronPDF SHELL 或者,在Visual Studio中使用NuGet包管理器控制台: Install-Package IronPDF 有关高级安装选项,包括特定平台包、Docker设置或Linux配置,请查看<IronPDF安装文档。 我应该使用什么项目结构? 良好的C#开发需要维护一个干净且结构良好的项目文件夹。 例如: 如何创建您的第一个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); } Public Interface IPdfService Function GeneratePdfFromHtml(htmlContent As String) As Byte() Function GeneratePdfFromUrl(url As String) As Byte() End Interface $vbLabelText $csharpLabel 在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; } } Imports IronPdf Public Class PdfService Implements IPdfService Private ReadOnly _renderer As ChromePdfRenderer Public Sub New() _renderer = New ChromePdfRenderer() ' Configure rendering options for optimal PDF generation in .NET _renderer.RenderingOptions.MarginTop = 20 _renderer.RenderingOptions.MarginBottom = 20 _renderer.RenderingOptions.PrintHtmlBackgrounds = True End Sub Public Function GeneratePdfFromHtml(htmlContent As String) As Byte() ' Generate PDF from HTML using the .NET PDF API Dim pdf = _renderer.RenderHtmlAsPdf(htmlContent) Return pdf.BinaryData End Function Public Function GeneratePdfFromUrl(url As String) As Byte() ' Convert URL to PDF in the REST API Dim pdf = _renderer.RenderUrlAsPdf(url) Return pdf.BinaryData End Function End Class $vbLabelText $csharpLabel 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}"); } } } Imports Microsoft.AspNetCore.Mvc <ApiController> <Route("api/[controller]")> Public Class PdfController Inherits ControllerBase Private ReadOnly _pdfService As IPdfService Public Sub New(pdfService As IPdfService) _pdfService = pdfService End Sub <HttpPost("html-to-pdf")> Public Function ConvertHtmlToPdf(<FromBody> request As HtmlRequest) As IActionResult Try Dim pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent) ' Return as downloadable file Return File(pdfBytes, "application/pdf", "document.pdf") Catch ex As Exception Return BadRequest($"Error generating PDF: {ex.Message}") End Try End Function End Class $vbLabelText $csharpLabel 然后,在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"; } ' Models/HtmlRequest.vb Public Class HtmlRequest Public Property HtmlContent As String Public Property FileName As String = "document.pdf" End Class $vbLabelText $csharpLabel 这将设置一个将HTML转换为可下载PDF的API端点。 当有人将HTML发送到PdfController将转换委托给服务。 创建后,控制器将PDF作为可下载文件返回。请求使用包含HTML和可选文件名的HtmlRequest模型。 这使得客户端可以轻松发送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(); Imports Microsoft.AspNetCore.Builder Imports Microsoft.Extensions.DependencyInjection Dim builder = WebApplication.CreateBuilder(args) builder.Services.AddControllers() builder.Services.AddEndpointsApiExplorer() builder.Services.AddSwaggerGen() ' Register PDF service builder.Services.AddSingleton(Of IPdfService, PdfService)() Dim app = builder.Build() If app.Environment.IsDevelopment() Then app.UseSwagger() app.UseSwaggerUI() End If app.UseHttpsRedirection() app.MapControllers() app.Run() $vbLabelText $csharpLabel 如何处理不同的响应类型? 您的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); } } Imports Microsoft.AspNetCore.Mvc <HttpPost("generate")> Public Function GeneratePdf(<FromBody> request As PdfRequest) As IActionResult Dim pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent) Select Case request.ResponseType?.ToLower() Case "base64" Return Ok(New With { .data = Convert.ToBase64String(pdfBytes), .filename = request.FileName }) Case "inline" Return File(pdfBytes, "application/pdf") Case Else ' download Return File(pdfBytes, "application/pdf", request.FileName) End Select End Function $vbLabelText $csharpLabel 这添加了一个灵活的PDF生成端点。 GeneratePdf方法不强制下载,而是让客户端选择如何接收结果:作为下载、浏览器内联,或< a href="Base64编码" target="_blank">https://ironpdf.com/troubleshooting/convert-pdf-to-base64/">Base64编码以供API使用。 ResponseType选项。 这为用户提供了对PDF交付的控制,使API更加多功能。有关在没有文件系统访问的情况下在内存中处理PDF,请参见IronPDF的内存流文档。 当我们运行我们的程序时,我们将在Swagger上看到以下输出: 如何实现常见的PDF操作? 让我们扩展我们的服务以处理各种PDF生成场景: 如何将URL转换为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; } } Imports System.Threading.Tasks Imports Microsoft.AspNetCore.Mvc <HttpPost("url-to-pdf")> Public Async Function ConvertUrlToPdf(<FromBody> request As UrlRequest) As Task(Of IActionResult) Try Dim pdfBytes = Await Task.Run(Function() _pdfService.GeneratePdfFromUrl(request.Url)) Return File(pdfBytes, "application/pdf", $"{If(request.FileName, "website")}.pdf") Catch ex As Exception Return BadRequest($"Failed to convert URL: {ex.Message}") End Try End Function Public Class UrlRequest Public Property Url As String Public Property FileName As String End Class $vbLabelText $csharpLabel 此端点将URL转换为可下载的PDF。 当POST请求到达_pdfService在后台将URL转换为PDF字节,然后返回以供下载。 如果转换失败,它将返回一个清晰的错误消息。 对于需要身份验证的网站,请查看IronPDF的登录文档。 让我们尝试使用URL "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; } Imports IronPdf Public Function AddWatermarkFromFile(filePath As String, watermarkText As String) As Byte() ' Load PDF directly from file Dim 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 End Function $vbLabelText $csharpLabel 这手动加载一个本地文件以进行测试。 您可以调整此设置,使您的PDF API生成PDF,然后轻松应用自定义水印。 有关高级水印选项,包括图像水印和自定义定位,请参见水印指南。 水印输出是什么样的? 如何使用模板添加动态数据? 对于真实世界的应用程序,您通常需要从模板生成带有动态数据的PDFs: [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"; } Imports Microsoft.AspNetCore.Mvc <HttpPost("from-template")> Public Function GenerateFromTemplate(<FromBody> request As TemplateRequest) As IActionResult ' Simple template replacement Dim html As String = request.Template For Each item In request.Data html = html.Replace($"{{{{{item.Key}}}}}", item.Value) Next Dim pdfBytes As Byte() = _pdfService.GeneratePdfFromHtml(html) Return File(pdfBytes, "application/pdf", request.FileName) End Function Public Class TemplateRequest Public Property Template As String Public Property Data As Dictionary(Of String, String) Public Property FileName As String = "document.pdf" End Class $vbLabelText $csharpLabel 对于使用Razor、Handlebars或其他引擎的高级模板场景,请参阅<IronPDF的HTML到PDF文档。 您还可以探索CSHTML到PDF转换用于MVC应用程序和Razor到PDF用于Blazor应用程序。 关于无头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; }); } Imports System.Threading.Tasks Public Async Function GeneratePdfFromHtmlAsync(htmlContent As String) As Task(Of Byte()) Return Await Task.Run(Function() Dim pdf = _renderer.RenderHtmlAsPdf(htmlContent) Return pdf.BinaryData End Function) End Function $vbLabelText $csharpLabel 对于并行PDF生成场景,探索多线程和并行处理技术。 我应该配置哪些渲染选项? 配置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 $vbLabelText $csharpLabel 有关综合渲染配置选项,包括视口设置、自定义纸张尺寸和页面方向,请参见渲染选项文档。 如何保护您的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>(); Imports Microsoft.AspNetCore.Http Imports Microsoft.Extensions.Configuration Imports System.Threading.Tasks ' Middleware/ApiKeyMiddleware.vb Public Class ApiKeyMiddleware Private ReadOnly _next As RequestDelegate Private Const ApiKeyHeader As String = "X-API-Key" Public Sub New(next As RequestDelegate) _next = next End Sub Public Async Function InvokeAsync(context As HttpContext) As Task Dim apiKey As String = Nothing If Not context.Request.Headers.TryGetValue(ApiKeyHeader, apiKey) Then context.Response.StatusCode = 401 Await context.Response.WriteAsync("API Key required") Return End If ' Validate API key (in production, check against database) Dim validApiKey As String = context.RequestServices.GetRequiredService(Of IConfiguration)()("ApiKey") If apiKey <> validApiKey Then context.Response.StatusCode = 403 Await context.Response.WriteAsync("Invalid API Key") Return End If Await _next(context) End Function End Class ' In Program.vb app.UseMiddleware(Of ApiKeyMiddleware)() $vbLabelText $csharpLabel 对于高级身份验证场景,请考虑: JWT认证 - API认证的行业标准 OAuth 2.0 - 用于第三方集成 Azure AD集成 - 企业身份验证 API速率限制 - 防止滥用并确保公平使用 HTTP Headers - 自定义头配置增强安全性 对于PDF特定的安全性,实现密码保护、数字签名和PDF清理以移除可能具有恶意的内容。 如何构建一个实际的发票生成API? 让我们建立一个实用的发票生成端点,展示完整的实现。 此示例展示了生产.NET PDF API如何使用动态数据生成专业发票。 立即开始使用 IronPDF。 免费开始 首先,在您的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; } Public Class Invoice Public Property InvoiceNumber As String Public Property [Date] As DateTime Public Property CustomerName As String Public Property CustomerAddress As String Public Property Items As List(Of InvoiceItem) Public Property Tax As Decimal End Class Public Class InvoiceItem Public Property Description As String Public Property Quantity As Integer Public Property UnitPrice As Decimal Public ReadOnly Property Total As Decimal Get Return Quantity * UnitPrice End Get End Property End Class $vbLabelText $csharpLabel 接下来,为发票生成器创建一个新的服务文件。 在您的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>"; } } Imports System Imports System.Linq Public Class InvoiceService Private ReadOnly _renderer As ChromePdfRenderer Public Sub New() _renderer = New ChromePdfRenderer() _renderer.RenderingOptions.MarginTop = 10 _renderer.RenderingOptions.MarginBottom = 10 _renderer.RenderingOptions.PrintHtmlBackgrounds = True End Sub Public Function GenerateInvoice(invoice As Invoice) As Byte() Dim html = BuildInvoiceHtml(invoice) ' Add footer with page numbers _renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With { .MaxHeight = 15, .HtmlFragment = "<center><i>{page} of {total-pages}</i></center>", .DrawDividerLine = True } Dim pdf = _renderer.RenderHtmlAsPdf(html) Return pdf.BinaryData End Function Private Function BuildInvoiceHtml(invoice As Invoice) As String Dim subtotal = invoice.Items.Sum(Function(i) i.Total) Dim taxAmount = subtotal * (invoice.Tax / 100) Dim total = subtotal + taxAmount Dim itemsHtml = String.Join("", invoice.Items.Select(Function(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>" End Function End Class $vbLabelText $csharpLabel 最后创建一个新的控制器,通过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}"); } } } Imports Microsoft.AspNetCore.Mvc <ApiController> <Route("api/[controller]")> Public Class InvoiceController Inherits ControllerBase Private ReadOnly _invoiceService As InvoiceService Public Sub New(invoiceService As InvoiceService) _invoiceService = invoiceService End Sub <HttpPost("generate")> Public Function GenerateInvoice(<FromBody> invoice As Invoice) As IActionResult Try Dim pdfBytes = _invoiceService.GenerateInvoice(invoice) Dim fileName = $"Invoice_{invoice.InvoiceNumber}.pdf" Return File(pdfBytes, "application/pdf", fileName) Catch ex As Exception Return StatusCode(500, $"Error generating invoice: {ex.Message}") End Try End Function End Class $vbLabelText $csharpLabel 有关高级发票功能,请考虑添加条形码、QR码、页码和自定义页眉/页脚。 您还可以为长期存档实现PDF/A合规性或与电子签名流程集成。 发票输出是什么样的? 容器部署的注意事项是什么? 虽然本教程侧重于本地开发,但这里是关于将您的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和App Service IronPDF AWS部署 - Lambda和EC2部署 IronPDF Linux设置 - Linux特定配置 作为远程容器运行 - IronPDF引擎容器化 本地 vs 远程引擎 - 部署架构选项 错误处理的最佳实践是什么? 对于容错程序,实施全局错误处理程序以获得一致的错误响应: // 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)); } } ' Middleware/ErrorHandlingMiddleware.vb Public Class ErrorHandlingMiddleware Private ReadOnly _next As RequestDelegate Private ReadOnly _logger As ILogger(Of ErrorHandlingMiddleware) Public Sub New(ByVal [next] As RequestDelegate, ByVal logger As ILogger(Of ErrorHandlingMiddleware)) _next = [next] _logger = logger End Sub Public Async Function InvokeAsync(ByVal context As HttpContext) As Task Try Await _next(context) Catch ex As Exception _logger.LogError(ex, "An error occurred processing request {Path}", context.Request.Path) Await HandleExceptionAsync(context, ex) End Try End Function Private Shared Async Function HandleExceptionAsync(ByVal context As HttpContext, ByVal ex As Exception) As Task context.Response.ContentType = "application/json" context.Response.StatusCode = If(TypeOf ex Is ArgumentNullException, 400, If(TypeOf ex Is UnauthorizedAccessException, 401, 500)) Dim response = New With { .error = "An error occurred processing your request", .message = ex.Message, .statusCode = context.Response.StatusCode } Await context.Response.WriteAsync(JsonSerializer.Serialize(response)) End Function End Class $vbLabelText $csharpLabel 对于特定的IronPDF故障排除场景,请参考: 快速故障排除指南 工程支持指南 自定义日志记录配置 内存泄漏预防 性能优化提示 准备好构建您的生产.NET PDF API了吗? 您现在已经使用ASP.NET Core和IronPDF构建了一个强大的.NET PDF API,可以处理各种文档生成场景。 这个REST API为您的应用程序提供集中化PDF操作的坚实基础。 关键要点: IronPDF 使Web API项目中的PDF生成变得简单,通过基于Chrome的渲染。 使用IronPDF的高级编辑工具轻松编辑现有PDF。 RESTful 设计原则确保您的 PDF API 直观易用且易于维护。 适当的错误处理和安全措施对于生产至关重要。 通过异步操作和缓存进行性能优化,提高可扩展性。 支持桌面和Web应用程序的完整支持,通过可扩展的文档解决方案。 IronPDF让开发者创建PDF,保存PDF文件,并高效转换HTML,使其成为现代.NET Framework应用程序的关键PDF API。 下一步是什么? 准备好在您的生产.NET PDF API中实施IronPDF了吗? 以下是您的下一步操作: 1.开始免费试用- 在您的开发环境中测试 IronPDF 的全部功能。 探索高级功能 - 查看数字签名、PDF表单、PDF/A合规性、元数据管理和其他高级PDF功能。 自信扩展 - 查看许可选项以满足您生产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 能够将 HTML 和 CSS 内容转换为准确渲染的 PDF 文档,因此可以处理复杂的 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 for .NET 支持哪些版本? IronPDF 支持多个 .NET 版本,包括 .NET Core 和 .NET Framework,确保与各种项目兼容。 Curtis Chau 立即与工程团队聊天 技术作家 Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。 相关文章 已更新2026年3月1日 如何在.NET中使用IronPDF创建PDF文件(C#教程) 发现为开发人员创建PDF文件的有效方法。提升您的编码技能并简化您的项目。立即阅读文章! 阅读更多 已更新2026年2月27日 如何在C#中合并PDF文件 使用IronPDF合并PDF VB NET。学习使用简单的VB.NET代码将多个PDF文件合并为一个文档。包括逐步示例。 阅读更多 已更新2026年3月1日 面向 .NET 10 开发人员的 C# PDFWriter 教程 使用这份逐步指南了解如何高效地使用C# PDFWriter创建PDF。阅读文章提升您的技能! 阅读更多 如何用OCR.net和IronPDF在C#中构建一个PDF OCR工作流程使用 IronPDF 在 .NET Core 中构...