跳至页脚内容
使用IRONPDF

如何在ASP.NET中使用C#生成PDF

以编程方式生成PDF是现代Web应用程序的关键要求,无论是创建发票、报告、证书还是票据。 如果您是ASP.NET Core .NET开发人员,希望实现具有像素完美渲染和企业功能的PDF生成,您来对地方了。

本综合指南将逐步带您了解专业PDF文件生成,使用IronPDF这一强大的.NET库,使PDF文档的创建变得简单。 我们将探讨从基本设置到高级批处理的所有内容,展示其高效且易于集成的特性。 到最后,您将拥有一个强大的PDF转换器,用于在ASP.NET应用中像专业人士一样生成PDF文档,使用IronPDF。

为什么在ASP.NET Core中生成PDF?

服务器端PDF生成比客户端替代方案提供显著的优势。 当您在服务器上生成PDF时,您确保了所有浏览器和设备的一致输出,消除了对客户端资源的依赖,并更好地控制敏感数据。 常见的HTML到PDF转换业务场景包括:

  • 财务文件:发票、对账单和交易收据
  • 合规报告:监管申报文件和审计文档
  • 用户证书:培训结业证书和Professional认证
  • 活动门票:带QR码的入场券和登机牌
  • 数据导出:分析报告和仪表盘快照

此外,服务器端方式确保PDF在所有浏览器和操作系统中一致。 使其在法律和财务文件方面受到高度认可。

IronPDF如何改变您的PDF生成?

IronPDF是一个在.NET生态系统中脱颖而出的PDF库,其HTML转换器在后台使用完整的Chrome渲染引擎。 这意味着您的PDF文档将完全按照在Google Chrome中的显示效果进行渲染,完全支持现代CSS3、JavaScript执行以及网页字体。 与其他库不同,IronPDF使您能够直接将现有的HTML、CSS和JavaScript知识转化为在ASP.NET Core应用程序中的PDF生成能力。

对开发的关键优势:

  • 基于Chrome的渲染带来像素级准确度,与浏览器中进行HTML到PDF转换任务时所见相匹配(通常仅需几行代码)
  • 全面的HTML5、CSS3和JavaScript支持,包括像Bootstrap这样的现代框架
  • 原生.NET集成无需外部依赖或命令行工具
  • 跨平台兼容性支持.NET 6/7/8、.NET Core,甚至对于旧应用程序支持.NET Framework 4.6.2+
  • 全面的API用于生成后的操作,包括合并、水印和您的PDF页面的数字签名。

NuGet 使用 NuGet 安装

PM >  Install-Package IronPdf

IronPDF 上查看 NuGet 快速安装。超过 1000 万次下载,它正以 C# 改变 PDF 开发。 您也可以下载 DLLWindows 安装程序

设置您的ASP.NET Core项目

让我们创建一个新的ASP.NET Core MVC应用程序,配置用于PDF生成。 我们将构建一个具备适当依赖注入和错误处理的生产就绪设置。 这将是Visual Studio中的一个新.NET项目; 然而,您也可以使用现有项目。

创建项目

我们将创建此项目,并通过运行以下命令为其赋予合适的项目名称:

dotnet new mvc -n PdfGeneratorApp
cd PdfGeneratorApp

安装 IronPDF。

在我们开始在ASP.NET中生成PDF文档之前,通过在NuGet包管理器控制台中运行以下行将IronPDF添加到您的项目中:

Install-Package IronPdf
Install-Package IronPdf.Extensions.Mvc.Core

有关详细的安装选项,包括NuGet包配置Windows安装程序,请参考官方文档。

在Program.cs中配置服务

using IronPdf;
using IronPdf.Extensions.Mvc.Core;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
var builder = WebApplication.CreateBuilder(args);
// Configure IronPDF license (use your license key)
License.LicenseKey = "your-license-key";
// Add MVC services
builder.Services.AddControllersWithViews();
// Register IronPDF services
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
builder.Services.AddSingleton<IRazorViewRenderer, RazorViewRenderer>();
// Configure ChromePdfRenderer as a service
builder.Services.AddSingleton<ChromePdfRenderer>(provider =>
{
    var renderer = new ChromePdfRenderer();
    // Configure rendering options
    renderer.RenderingOptions.MarginTop = 25;
    renderer.RenderingOptions.MarginBottom = 25;
    renderer.RenderingOptions.MarginLeft = 20;
    renderer.RenderingOptions.MarginRight = 20;
    renderer.RenderingOptions.EnableJavaScript = true;
    renderer.RenderingOptions.RenderDelay = 500; // Wait for JS execution
    return renderer;
});
var app = builder.Build();
// Configure middleware pipeline
if (!app.Environment.IsDevelopment())
{
    app.Use例外情况Handler("/Home/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
using IronPdf;
using IronPdf.Extensions.Mvc.Core;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
var builder = WebApplication.CreateBuilder(args);
// Configure IronPDF license (use your license key)
License.LicenseKey = "your-license-key";
// Add MVC services
builder.Services.AddControllersWithViews();
// Register IronPDF services
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
builder.Services.AddSingleton<IRazorViewRenderer, RazorViewRenderer>();
// Configure ChromePdfRenderer as a service
builder.Services.AddSingleton<ChromePdfRenderer>(provider =>
{
    var renderer = new ChromePdfRenderer();
    // Configure rendering options
    renderer.RenderingOptions.MarginTop = 25;
    renderer.RenderingOptions.MarginBottom = 25;
    renderer.RenderingOptions.MarginLeft = 20;
    renderer.RenderingOptions.MarginRight = 20;
    renderer.RenderingOptions.EnableJavaScript = true;
    renderer.RenderingOptions.RenderDelay = 500; // Wait for JS execution
    return renderer;
});
var app = builder.Build();
// Configure middleware pipeline
if (!app.Environment.IsDevelopment())
{
    app.Use例外情况Handler("/Home/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Imports IronPdf
Imports IronPdf.Extensions.Mvc.Core
Imports Microsoft.AspNetCore.Mvc.ViewFeatures
Imports Microsoft.Extensions.DependencyInjection

Dim builder = WebApplication.CreateBuilder(args)

' Configure IronPDF license (use your license key)
License.LicenseKey = "your-license-key"

' Add MVC services
builder.Services.AddControllersWithViews()

' Register IronPDF services
builder.Services.AddSingleton(Of IHttpContextAccessor, HttpContextAccessor)()
builder.Services.AddSingleton(Of ITempDataProvider, CookieTempDataProvider)()
builder.Services.AddSingleton(Of IRazorViewRenderer, RazorViewRenderer)()

' Configure ChromePdfRenderer as a service
builder.Services.AddSingleton(Of ChromePdfRenderer)(
    Function(provider)
        Dim renderer = New ChromePdfRenderer()
        ' Configure rendering options
        renderer.RenderingOptions.MarginTop = 25
        renderer.RenderingOptions.MarginBottom = 25
        renderer.RenderingOptions.MarginLeft = 20
        renderer.RenderingOptions.MarginRight = 20
        renderer.RenderingOptions.EnableJavaScript = True
        renderer.RenderingOptions.RenderDelay = 500 ' Wait for JS execution
        Return renderer
    End Function)

Dim app = builder.Build()

' Configure middleware pipeline
If Not app.Environment.IsDevelopment() Then
    app.UseExceptionHandler("/Home/Error")
    app.UseHsts()
End If

app.UseHttpsRedirection()
app.UseStaticFiles()
app.UseRouting()
app.UseAuthorization()

app.MapControllerRoute(
    name:="default",
    pattern:="{controller=Home}/{action=Index}/{id?}")

app.Run()
$vbLabelText   $csharpLabel

此配置将IronPDF建立为一个单例服务,确保您应用程序的资源使用效率。 您可以进一步修改 `RenderingOptions` 以满足您的具体要求。 此时,您的文件夹结构在Visual Studio的解决方案资源管理器中应如下所示:

从Razor视图生成PDF

在ASP.NET Core中生成新PDF文档的最强大方法涉及利用Razor视图进行PDF转换。 这使您能够利用熟悉的MVC模式、强类型模型和Razor语法,在定制的HTML文件、网页和其他来源中创建动态PDF。 根据微软关于Razor页面的文档,这种方法为以页面为中心的场景提供了最清晰的关注点分离。

创建数据模型

首先,让我们创建一个表示典型业务文档的全面模型:

namespace PdfGeneratorApp.Models
{
    public class InvoiceModel
    {
        public string InvoiceNumber { get; set; }
        public DateTime InvoiceDate { get; set; }
        public DateTime DueDate { get; set; }
        public CompanyInfo Vendor { get; set; }
        public CompanyInfo Customer { get; set; }
        public List<InvoiceItem> Items { get; set; }
        public decimal Subtotal => Items?.Sum(x => x.Total) ?? 0;
        public decimal TaxRate { get; set; }
        public decimal TaxAmount => Subtotal * (TaxRate / 100);
        public decimal Total => Subtotal + TaxAmount;
        public string Notes { get; set; }
        public string PaymentTerms { get; set; }
    }
    public class CompanyInfo
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string ZipCode { get; set; }
        public string Email { get; set; }
        public string Phone { 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;
    }
}
namespace PdfGeneratorApp.Models
{
    public class InvoiceModel
    {
        public string InvoiceNumber { get; set; }
        public DateTime InvoiceDate { get; set; }
        public DateTime DueDate { get; set; }
        public CompanyInfo Vendor { get; set; }
        public CompanyInfo Customer { get; set; }
        public List<InvoiceItem> Items { get; set; }
        public decimal Subtotal => Items?.Sum(x => x.Total) ?? 0;
        public decimal TaxRate { get; set; }
        public decimal TaxAmount => Subtotal * (TaxRate / 100);
        public decimal Total => Subtotal + TaxAmount;
        public string Notes { get; set; }
        public string PaymentTerms { get; set; }
    }
    public class CompanyInfo
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string ZipCode { get; set; }
        public string Email { get; set; }
        public string Phone { 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;
    }
}
Imports System
Imports System.Collections.Generic
Imports System.Linq

Namespace PdfGeneratorApp.Models
    Public Class InvoiceModel
        Public Property InvoiceNumber As String
        Public Property InvoiceDate As DateTime
        Public Property DueDate As DateTime
        Public Property Vendor As CompanyInfo
        Public Property Customer As CompanyInfo
        Public Property Items As List(Of InvoiceItem)
        Public ReadOnly Property Subtotal As Decimal
            Get
                Return If(Items?.Sum(Function(x) x.Total), 0)
            End Get
        End Property
        Public Property TaxRate As Decimal
        Public ReadOnly Property TaxAmount As Decimal
            Get
                Return Subtotal * (TaxRate / 100)
            End Get
        End Property
        Public ReadOnly Property Total As Decimal
            Get
                Return Subtotal + TaxAmount
            End Get
        End Property
        Public Property Notes As String
        Public Property PaymentTerms As String
    End Class

    Public Class CompanyInfo
        Public Property Name As String
        Public Property Address As String
        Public Property City As String
        Public Property State As String
        Public Property ZipCode As String
        Public Property Email As String
        Public Property Phone As String
    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
End Namespace
$vbLabelText   $csharpLabel

构建Razor视图

在Views/Invoice/InvoiceTemplate.cshtml创建一个视图来呈现您的PDF内容:

@model PdfGeneratorApp.Models.InvoiceModel
@{
    Layout = null; // PDFs should not use the site layout
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Invoice @Model.InvoiceNumber</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
        }
        .invoice-container {
            max-width: 800px;
            margin: 0 auto;
            padding: 30px;
        }
        .invoice-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 40px;
            padding-bottom: 20px;
            border-bottom: 2px solid #2c3e50;
        }
        .company-details {
            flex: 1;
        }
        .company-details h1 {
            color: #2c3e50;
            margin-bottom: 10px;
        }
        .invoice-details {
            text-align: right;
        }
        .invoice-details h2 {
            color: #2c3e50;
            font-size: 28px;
            margin-bottom: 10px;
        }
        .invoice-details p {
            margin: 5px 0;
            font-size: 14px;
        }
        .billing-details {
            display: flex;
            justify-content: space-between;
            margin-bottom: 40px;
        }
        .billing-section {
            flex: 1;
        }
        .billing-section h3 {
            color: #2c3e50;
            margin-bottom: 10px;
            font-size: 16px;
            text-transform: uppercase;
        }
        .items-table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 40px;
        }
        .items-table thead {
            background-color: #2c3e50;
            color: white;
        }
        .items-table th,
        .items-table td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        .items-table tbody tr:hover {
            background-color: #f5f5f5;
        }
        .text-right {
            text-align: right;
        }
        .invoice-summary {
            display: flex;
            justify-content: flex-end;
            margin-bottom: 40px;
        }
        .summary-table {
            width: 300px;
        }
        .summary-table tr {
            border-bottom: 1px solid #ddd;
        }
        .summary-table td {
            padding: 8px;
        }
        .summary-table .total-row {
            font-weight: bold;
            font-size: 18px;
            color: #2c3e50;
            border-top: 2px solid #2c3e50;
        }
        .invoice-footer {
            margin-top: 60px;
            padding-top: 20px;
            border-top: 1px solid #ddd;
        }
        .footer-notes {
            margin-bottom: 20px;
        }
        .footer-notes h4 {
            color: #2c3e50;
            margin-bottom: 10px;
        }
        @@media print {
            .invoice-container {
                padding: 0;
            }
        }
    </style>
</head>
<body>
    <div class="invoice-container">
        <div class="invoice-header">
            <div class="company-details">
                <h1>@Model.Vendor.Name</h1>
                <p>@Model.Vendor.Address</p>
                <p>@Model.Vendor.City, @Model.Vendor.State @Model.Vendor.ZipCode</p>
                <p>Email: @Model.Vendor.Email</p>
                <p>Phone: @Model.Vendor.Phone</p>
            </div>
            <div class="invoice-details">
                <h2>INVOICE</h2>
                <p><strong>Invoice #:</strong> @Model.InvoiceNumber</p>
                <p><strong>Date:</strong> @Model.InvoiceDate.ToString("MMM dd, yyyy")</p>
                <p><strong>Due Date:</strong> @Model.DueDate.ToString("MMM dd, yyyy")</p>
            </div>
        </div>
        <div class="billing-details">
            <div class="billing-section">
                <h3>Bill To:</h3>
                <p><strong>@Model.Customer.Name</strong></p>
                <p>@Model.Customer.Address</p>
                <p>@Model.Customer.City, @Model.Customer.State @Model.Customer.ZipCode</p>
                <p>@Model.Customer.Email</p>
            </div>
        </div>
        <table class="items-table">
            <thead>
                <tr>
                    <th>Description</th>
                    <th class="text-right">Quantity</th>
                    <th class="text-right">Unit Price</th>
                    <th class="text-right">Total</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in Model.Items)
                {
                    <tr>
                        <td>@item.Description</td>
                        <td class="text-right">@item.Quantity</td>
                        <td class="text-right">@item.UnitPrice.ToString("C")</td>
                        <td class="text-right">@item.Total.ToString("C")</td>
                    </tr>
                }
            </tbody>
        </table>
        <div class="invoice-summary">
            <table class="summary-table">
                <tr>
                    <td>Subtotal:</td>
                    <td class="text-right">@Model.Subtotal.ToString("C")</td>
                </tr>
                <tr>
                    <td>Tax (@Model.TaxRate%):</td>
                    <td class="text-right">@Model.TaxAmount.ToString("C")</td>
                </tr>
                <tr class="total-row">
                    <td>Total:</td>
                    <td class="text-right">@Model.Total.ToString("C")</td>
                </tr>
            </table>
        </div>
        @if (!string.IsNullOrEmpty(Model.Notes))
        {
            <div class="invoice-footer">
                <div class="footer-notes">
                    <h4>Notes</h4>
                    <p>@Model.Notes</p>
                </div>
            </div>
        }
        @if (!string.IsNullOrEmpty(Model.PaymentTerms))
        {
            <div class="footer-notes">
                <h4>Payment Terms</h4>
                <p>@Model.PaymentTerms</p>
            </div>
        }
    </div>
</body>
</html>
@model PdfGeneratorApp.Models.InvoiceModel
@{
    Layout = null; // PDFs should not use the site layout
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Invoice @Model.InvoiceNumber</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
        }
        .invoice-container {
            max-width: 800px;
            margin: 0 auto;
            padding: 30px;
        }
        .invoice-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 40px;
            padding-bottom: 20px;
            border-bottom: 2px solid #2c3e50;
        }
        .company-details {
            flex: 1;
        }
        .company-details h1 {
            color: #2c3e50;
            margin-bottom: 10px;
        }
        .invoice-details {
            text-align: right;
        }
        .invoice-details h2 {
            color: #2c3e50;
            font-size: 28px;
            margin-bottom: 10px;
        }
        .invoice-details p {
            margin: 5px 0;
            font-size: 14px;
        }
        .billing-details {
            display: flex;
            justify-content: space-between;
            margin-bottom: 40px;
        }
        .billing-section {
            flex: 1;
        }
        .billing-section h3 {
            color: #2c3e50;
            margin-bottom: 10px;
            font-size: 16px;
            text-transform: uppercase;
        }
        .items-table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 40px;
        }
        .items-table thead {
            background-color: #2c3e50;
            color: white;
        }
        .items-table th,
        .items-table td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        .items-table tbody tr:hover {
            background-color: #f5f5f5;
        }
        .text-right {
            text-align: right;
        }
        .invoice-summary {
            display: flex;
            justify-content: flex-end;
            margin-bottom: 40px;
        }
        .summary-table {
            width: 300px;
        }
        .summary-table tr {
            border-bottom: 1px solid #ddd;
        }
        .summary-table td {
            padding: 8px;
        }
        .summary-table .total-row {
            font-weight: bold;
            font-size: 18px;
            color: #2c3e50;
            border-top: 2px solid #2c3e50;
        }
        .invoice-footer {
            margin-top: 60px;
            padding-top: 20px;
            border-top: 1px solid #ddd;
        }
        .footer-notes {
            margin-bottom: 20px;
        }
        .footer-notes h4 {
            color: #2c3e50;
            margin-bottom: 10px;
        }
        @@media print {
            .invoice-container {
                padding: 0;
            }
        }
    </style>
</head>
<body>
    <div class="invoice-container">
        <div class="invoice-header">
            <div class="company-details">
                <h1>@Model.Vendor.Name</h1>
                <p>@Model.Vendor.Address</p>
                <p>@Model.Vendor.City, @Model.Vendor.State @Model.Vendor.ZipCode</p>
                <p>Email: @Model.Vendor.Email</p>
                <p>Phone: @Model.Vendor.Phone</p>
            </div>
            <div class="invoice-details">
                <h2>INVOICE</h2>
                <p><strong>Invoice #:</strong> @Model.InvoiceNumber</p>
                <p><strong>Date:</strong> @Model.InvoiceDate.ToString("MMM dd, yyyy")</p>
                <p><strong>Due Date:</strong> @Model.DueDate.ToString("MMM dd, yyyy")</p>
            </div>
        </div>
        <div class="billing-details">
            <div class="billing-section">
                <h3>Bill To:</h3>
                <p><strong>@Model.Customer.Name</strong></p>
                <p>@Model.Customer.Address</p>
                <p>@Model.Customer.City, @Model.Customer.State @Model.Customer.ZipCode</p>
                <p>@Model.Customer.Email</p>
            </div>
        </div>
        <table class="items-table">
            <thead>
                <tr>
                    <th>Description</th>
                    <th class="text-right">Quantity</th>
                    <th class="text-right">Unit Price</th>
                    <th class="text-right">Total</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in Model.Items)
                {
                    <tr>
                        <td>@item.Description</td>
                        <td class="text-right">@item.Quantity</td>
                        <td class="text-right">@item.UnitPrice.ToString("C")</td>
                        <td class="text-right">@item.Total.ToString("C")</td>
                    </tr>
                }
            </tbody>
        </table>
        <div class="invoice-summary">
            <table class="summary-table">
                <tr>
                    <td>Subtotal:</td>
                    <td class="text-right">@Model.Subtotal.ToString("C")</td>
                </tr>
                <tr>
                    <td>Tax (@Model.TaxRate%):</td>
                    <td class="text-right">@Model.TaxAmount.ToString("C")</td>
                </tr>
                <tr class="total-row">
                    <td>Total:</td>
                    <td class="text-right">@Model.Total.ToString("C")</td>
                </tr>
            </table>
        </div>
        @if (!string.IsNullOrEmpty(Model.Notes))
        {
            <div class="invoice-footer">
                <div class="footer-notes">
                    <h4>Notes</h4>
                    <p>@Model.Notes</p>
                </div>
            </div>
        }
        @if (!string.IsNullOrEmpty(Model.PaymentTerms))
        {
            <div class="footer-notes">
                <h4>Payment Terms</h4>
                <p>@Model.PaymentTerms</p>
            </div>
        }
    </div>
</body>
</html>
$vbLabelText   $csharpLabel

实现具有错误处理的控制器

现在让我们创建一个可生成PDF并具备综合错误处理的强大控制器:

using IronPdf;
using IronPdf.Extensions.Mvc.Core;
using Microsoft.AspNetCore.Mvc;
using PdfGeneratorApp.Models;
using System.Diagnostics;
namespace PdfGeneratorApp.Controllers
{
    public class InvoiceController : Controller
    {
        private readonly ILogger<InvoiceController> _logger;
        private readonly IRazorViewRenderer _viewRenderer;
        private readonly ChromePdfRenderer _pdfRenderer;
        private readonly IWebHostEnvironment _environment;
        public InvoiceController(
            ILogger<InvoiceController> logger,
            IRazorViewRenderer viewRenderer,
            ChromePdfRenderer pdfRenderer,
            IWebHostEnvironment environment)
        {
            _logger = logger;
            _viewRenderer = viewRenderer;
            _pdfRenderer = pdfRenderer;
            _environment = environment;
        }
        [HttpGet]
        public IActionResult Index()
        {
            // Display a form or list of invoices
            return View();
        }
        [HttpGet]
        public async Task<IActionResult> GenerateInvoice(string invoiceNumber)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                // Validate input
                if (string.IsNullOrEmpty(invoiceNumber))
                {
                    _logger.LogWarning("Invoice generation attempted without invoice number");
                    return BadRequest("Invoice number is required");
                }
                // Generate sample data (in production, fetch from database)
                var invoice = CreateSampleInvoice(invoiceNumber);
                // Log the generation attempt
                _logger.LogInformation($"Generating PDF for invoice {invoiceNumber}");
                // Configure PDF rendering options
                _pdfRenderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait;
                _pdfRenderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
                _pdfRenderer.RenderingOptions.PrintHtmlBackgrounds = true;
                _pdfRenderer.RenderingOptions.CreatePdfFormsFromHtml = false;
                // Add custom header with page numbers
                _pdfRenderer.RenderingOptions.TextHeader = new TextHeaderFooter
                {
                    CenterText = $"Invoice {invoice.InvoiceNumber}",
                    DrawDividerLine = true,
                    Font = IronSoftware.Drawing.FontTypes.Helvetica,
                    FontSize = 10
                };
                // Add footer with page numbers
                _pdfRenderer.RenderingOptions.TextFooter = new TextHeaderFooter
                {
                    LeftText = "{date} {time}",
                    RightText = "Page {page} of {total-pages}",
                    DrawDividerLine = true,
                    Font = IronSoftware.Drawing.FontTypes.Helvetica,
                    FontSize = 8
                };
                // Render the view to PDF
                PdfDocument pdf;
                try
                {
                    pdf = _pdfRenderer.RenderRazorViewToPdf(
                        _viewRenderer,
                        "Views/Invoice/InvoiceTemplate.cshtml",
                        invoice);
                }
                catch (例外情况 renderEx)
                {
                    _logger.LogError(renderEx, "Failed to render Razor view to PDF");
                    throw new InvalidOperation例外情况("PDF rendering failed. Please check the template.", renderEx);
                }
                // Apply metadata
                pdf.MetaData.Author = "PdfGeneratorApp";
                pdf.MetaData.Title = $"Invoice {invoice.InvoiceNumber}";
                pdf.MetaData.Subject = $"Invoice for {invoice.Customer.Name}";
                pdf.MetaData.Keywords = "invoice, billing, payment";
                pdf.MetaData.CreationDate = DateTime.UtcNow;
                pdf.MetaData.ModifiedDate = DateTime.UtcNow;
                // Optional: Add password protection
                // pdf.SecuritySettings.UserPassword = "user123";
                // pdf.SecuritySettings.OwnerPassword = "owner456";
                // pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
                // Log performance metrics
                stopwatch.Stop();
                _logger.LogInformation($"PDF generated successfully for invoice {invoiceNumber} in {stopwatch.ElapsedMilliseconds}ms");
                // Return the PDF file
                Response.Headers.Add("Content-Disposition", $"inline; filename=Invoice_{invoiceNumber}.pdf");
                return File(pdf.BinaryData, "application/pdf", $"Invoice_{invoiceNumber}.pdf");
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, $"Error generating PDF for invoice {invoiceNumber}");
                // In development, return detailed error
                if (_environment.IsDevelopment())
                {
                    return StatusCode(500, new
                    {
                        error = "PDF generation failed",
                        message = ex.Message,
                        stackTrace = ex.StackTrace
                    });
                }
                // In production, return generic error
                return StatusCode(500, "An error occurred while generating the PDF");
            }
        }
        private InvoiceModel CreateSampleInvoice(string invoiceNumber)
        {
            return new InvoiceModel
            {
                InvoiceNumber = invoiceNumber,
                InvoiceDate = DateTime.Now,
                DueDate = DateTime.Now.AddDays(30),
                Vendor = new CompanyInfo
                {
                    Name = "Tech 解决方案s Inc.",
                    Address = "123 Business Ave",
                    City = "New York",
                    State = "NY",
                    ZipCode = "10001",
                    Email = "billing@techsolutions.com",
                    Phone = "(555) 123-4567"
                },
                Customer = new CompanyInfo
                {
                    Name = "Acme Corporation",
                    Address = "456 Commerce St",
                    City = "Los Angeles",
                    State = "CA",
                    ZipCode = "90001",
                    Email = "accounts@acmecorp.com",
                    Phone = "(555) 987-6543"
                },
                Items = new List<InvoiceItem>
                {
                    new InvoiceItem
                    {
                        Description = "Software Development Services - 40 hours",
                        Quantity = 40,
                        UnitPrice = 150.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Project Management - 10 hours",
                        Quantity = 10,
                        UnitPrice = 120.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Quality Assurance Testing",
                        Quantity = 1,
                        UnitPrice = 2500.00m
                    }
                },
                TaxRate = 8.875m,
                Notes = "Payment is due within 30 days. Late payments subject to 1.5% monthly interest.",
                PaymentTerms = "Net 30"
            };
        }
    }
}
using IronPdf;
using IronPdf.Extensions.Mvc.Core;
using Microsoft.AspNetCore.Mvc;
using PdfGeneratorApp.Models;
using System.Diagnostics;
namespace PdfGeneratorApp.Controllers
{
    public class InvoiceController : Controller
    {
        private readonly ILogger<InvoiceController> _logger;
        private readonly IRazorViewRenderer _viewRenderer;
        private readonly ChromePdfRenderer _pdfRenderer;
        private readonly IWebHostEnvironment _environment;
        public InvoiceController(
            ILogger<InvoiceController> logger,
            IRazorViewRenderer viewRenderer,
            ChromePdfRenderer pdfRenderer,
            IWebHostEnvironment environment)
        {
            _logger = logger;
            _viewRenderer = viewRenderer;
            _pdfRenderer = pdfRenderer;
            _environment = environment;
        }
        [HttpGet]
        public IActionResult Index()
        {
            // Display a form or list of invoices
            return View();
        }
        [HttpGet]
        public async Task<IActionResult> GenerateInvoice(string invoiceNumber)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                // Validate input
                if (string.IsNullOrEmpty(invoiceNumber))
                {
                    _logger.LogWarning("Invoice generation attempted without invoice number");
                    return BadRequest("Invoice number is required");
                }
                // Generate sample data (in production, fetch from database)
                var invoice = CreateSampleInvoice(invoiceNumber);
                // Log the generation attempt
                _logger.LogInformation($"Generating PDF for invoice {invoiceNumber}");
                // Configure PDF rendering options
                _pdfRenderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait;
                _pdfRenderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
                _pdfRenderer.RenderingOptions.PrintHtmlBackgrounds = true;
                _pdfRenderer.RenderingOptions.CreatePdfFormsFromHtml = false;
                // Add custom header with page numbers
                _pdfRenderer.RenderingOptions.TextHeader = new TextHeaderFooter
                {
                    CenterText = $"Invoice {invoice.InvoiceNumber}",
                    DrawDividerLine = true,
                    Font = IronSoftware.Drawing.FontTypes.Helvetica,
                    FontSize = 10
                };
                // Add footer with page numbers
                _pdfRenderer.RenderingOptions.TextFooter = new TextHeaderFooter
                {
                    LeftText = "{date} {time}",
                    RightText = "Page {page} of {total-pages}",
                    DrawDividerLine = true,
                    Font = IronSoftware.Drawing.FontTypes.Helvetica,
                    FontSize = 8
                };
                // Render the view to PDF
                PdfDocument pdf;
                try
                {
                    pdf = _pdfRenderer.RenderRazorViewToPdf(
                        _viewRenderer,
                        "Views/Invoice/InvoiceTemplate.cshtml",
                        invoice);
                }
                catch (例外情况 renderEx)
                {
                    _logger.LogError(renderEx, "Failed to render Razor view to PDF");
                    throw new InvalidOperation例外情况("PDF rendering failed. Please check the template.", renderEx);
                }
                // Apply metadata
                pdf.MetaData.Author = "PdfGeneratorApp";
                pdf.MetaData.Title = $"Invoice {invoice.InvoiceNumber}";
                pdf.MetaData.Subject = $"Invoice for {invoice.Customer.Name}";
                pdf.MetaData.Keywords = "invoice, billing, payment";
                pdf.MetaData.CreationDate = DateTime.UtcNow;
                pdf.MetaData.ModifiedDate = DateTime.UtcNow;
                // Optional: Add password protection
                // pdf.SecuritySettings.UserPassword = "user123";
                // pdf.SecuritySettings.OwnerPassword = "owner456";
                // pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
                // Log performance metrics
                stopwatch.Stop();
                _logger.LogInformation($"PDF generated successfully for invoice {invoiceNumber} in {stopwatch.ElapsedMilliseconds}ms");
                // Return the PDF file
                Response.Headers.Add("Content-Disposition", $"inline; filename=Invoice_{invoiceNumber}.pdf");
                return File(pdf.BinaryData, "application/pdf", $"Invoice_{invoiceNumber}.pdf");
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, $"Error generating PDF for invoice {invoiceNumber}");
                // In development, return detailed error
                if (_environment.IsDevelopment())
                {
                    return StatusCode(500, new
                    {
                        error = "PDF generation failed",
                        message = ex.Message,
                        stackTrace = ex.StackTrace
                    });
                }
                // In production, return generic error
                return StatusCode(500, "An error occurred while generating the PDF");
            }
        }
        private InvoiceModel CreateSampleInvoice(string invoiceNumber)
        {
            return new InvoiceModel
            {
                InvoiceNumber = invoiceNumber,
                InvoiceDate = DateTime.Now,
                DueDate = DateTime.Now.AddDays(30),
                Vendor = new CompanyInfo
                {
                    Name = "Tech 解决方案s Inc.",
                    Address = "123 Business Ave",
                    City = "New York",
                    State = "NY",
                    ZipCode = "10001",
                    Email = "billing@techsolutions.com",
                    Phone = "(555) 123-4567"
                },
                Customer = new CompanyInfo
                {
                    Name = "Acme Corporation",
                    Address = "456 Commerce St",
                    City = "Los Angeles",
                    State = "CA",
                    ZipCode = "90001",
                    Email = "accounts@acmecorp.com",
                    Phone = "(555) 987-6543"
                },
                Items = new List<InvoiceItem>
                {
                    new InvoiceItem
                    {
                        Description = "Software Development Services - 40 hours",
                        Quantity = 40,
                        UnitPrice = 150.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Project Management - 10 hours",
                        Quantity = 10,
                        UnitPrice = 120.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Quality Assurance Testing",
                        Quantity = 1,
                        UnitPrice = 2500.00m
                    }
                },
                TaxRate = 8.875m,
                Notes = "Payment is due within 30 days. Late payments subject to 1.5% monthly interest.",
                PaymentTerms = "Net 30"
            };
        }
    }
}
Imports IronPdf
Imports IronPdf.Extensions.Mvc.Core
Imports Microsoft.AspNetCore.Mvc
Imports PdfGeneratorApp.Models
Imports System.Diagnostics

Namespace PdfGeneratorApp.Controllers
    Public Class InvoiceController
        Inherits Controller

        Private ReadOnly _logger As ILogger(Of InvoiceController)
        Private ReadOnly _viewRenderer As IRazorViewRenderer
        Private ReadOnly _pdfRenderer As ChromePdfRenderer
        Private ReadOnly _environment As IWebHostEnvironment

        Public Sub New(logger As ILogger(Of InvoiceController),
                       viewRenderer As IRazorViewRenderer,
                       pdfRenderer As ChromePdfRenderer,
                       environment As IWebHostEnvironment)
            _logger = logger
            _viewRenderer = viewRenderer
            _pdfRenderer = pdfRenderer
            _environment = environment
        End Sub

        <HttpGet>
        Public Function Index() As IActionResult
            ' Display a form or list of invoices
            Return View()
        End Function

        <HttpGet>
        Public Async Function GenerateInvoice(invoiceNumber As String) As Task(Of IActionResult)
            Dim stopwatch = Stopwatch.StartNew()
            Try
                ' Validate input
                If String.IsNullOrEmpty(invoiceNumber) Then
                    _logger.LogWarning("Invoice generation attempted without invoice number")
                    Return BadRequest("Invoice number is required")
                End If

                ' Generate sample data (in production, fetch from database)
                Dim invoice = CreateSampleInvoice(invoiceNumber)

                ' Log the generation attempt
                _logger.LogInformation($"Generating PDF for invoice {invoiceNumber}")

                ' Configure PDF rendering options
                _pdfRenderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait
                _pdfRenderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
                _pdfRenderer.RenderingOptions.PrintHtmlBackgrounds = True
                _pdfRenderer.RenderingOptions.CreatePdfFormsFromHtml = False

                ' Add custom header with page numbers
                _pdfRenderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
                    .CenterText = $"Invoice {invoice.InvoiceNumber}",
                    .DrawDividerLine = True,
                    .Font = IronSoftware.Drawing.FontTypes.Helvetica,
                    .FontSize = 10
                }

                ' Add footer with page numbers
                _pdfRenderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
                    .LeftText = "{date} {time}",
                    .RightText = "Page {page} of {total-pages}",
                    .DrawDividerLine = True,
                    .Font = IronSoftware.Drawing.FontTypes.Helvetica,
                    .FontSize = 8
                }

                ' Render the view to PDF
                Dim pdf As PdfDocument
                Try
                    pdf = _pdfRenderer.RenderRazorViewToPdf(
                        _viewRenderer,
                        "Views/Invoice/InvoiceTemplate.cshtml",
                        invoice)
                Catch renderEx As Exception
                    _logger.LogError(renderEx, "Failed to render Razor view to PDF")
                    Throw New InvalidOperationException("PDF rendering failed. Please check the template.", renderEx)
                End Try

                ' Apply metadata
                pdf.MetaData.Author = "PdfGeneratorApp"
                pdf.MetaData.Title = $"Invoice {invoice.InvoiceNumber}"
                pdf.MetaData.Subject = $"Invoice for {invoice.Customer.Name}"
                pdf.MetaData.Keywords = "invoice, billing, payment"
                pdf.MetaData.CreationDate = DateTime.UtcNow
                pdf.MetaData.ModifiedDate = DateTime.UtcNow

                ' Optional: Add password protection
                ' pdf.SecuritySettings.UserPassword = "user123"
                ' pdf.SecuritySettings.OwnerPassword = "owner456"
                ' pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights

                ' Log performance metrics
                stopwatch.Stop()
                _logger.LogInformation($"PDF generated successfully for invoice {invoiceNumber} in {stopwatch.ElapsedMilliseconds}ms")

                ' Return the PDF file
                Response.Headers.Add("Content-Disposition", $"inline; filename=Invoice_{invoiceNumber}.pdf")
                Return File(pdf.BinaryData, "application/pdf", $"Invoice_{invoiceNumber}.pdf")
            Catch ex As Exception
                _logger.LogError(ex, $"Error generating PDF for invoice {invoiceNumber}")

                ' In development, return detailed error
                If _environment.IsDevelopment() Then
                    Return StatusCode(500, New With {
                        .error = "PDF generation failed",
                        .message = ex.Message,
                        .stackTrace = ex.StackTrace
                    })
                End If

                ' In production, return generic error
                Return StatusCode(500, "An error occurred while generating the PDF")
            End Try
        End Function

        Private Function CreateSampleInvoice(invoiceNumber As String) As InvoiceModel
            Return New InvoiceModel With {
                .InvoiceNumber = invoiceNumber,
                .InvoiceDate = DateTime.Now,
                .DueDate = DateTime.Now.AddDays(30),
                .Vendor = New CompanyInfo With {
                    .Name = "Tech Solutions Inc.",
                    .Address = "123 Business Ave",
                    .City = "New York",
                    .State = "NY",
                    .ZipCode = "10001",
                    .Email = "billing@techsolutions.com",
                    .Phone = "(555) 123-4567"
                },
                .Customer = New CompanyInfo With {
                    .Name = "Acme Corporation",
                    .Address = "456 Commerce St",
                    .City = "Los Angeles",
                    .State = "CA",
                    .ZipCode = "90001",
                    .Email = "accounts@acmecorp.com",
                    .Phone = "(555) 987-6543"
                },
                .Items = New List(Of InvoiceItem) From {
                    New InvoiceItem With {
                        .Description = "Software Development Services - 40 hours",
                        .Quantity = 40,
                        .UnitPrice = 150.0D
                    },
                    New InvoiceItem With {
                        .Description = "Project Management - 10 hours",
                        .Quantity = 10,
                        .UnitPrice = 120.0D
                    },
                    New InvoiceItem With {
                        .Description = "Quality Assurance Testing",
                        .Quantity = 1,
                        .UnitPrice = 2500.0D
                    }
                },
                .TaxRate = 8.875D,
                .Notes = "Payment is due within 30 days. Late payments subject to 1.5% monthly interest.",
                .PaymentTerms = "Net 30"
            }
        End Function
    End Class
End Namespace
$vbLabelText   $csharpLabel

代码解释

要测试并运行上述 PDF 生成器,请启动项目并输入以下 URL:https://localhost:[port]/Invoice/GenerateInvoice?invoiceNumber=055 以生成发票。请务必将端口号替换为您托管应用程序的实际端口号。

输出

如何在ASP.NET中使用C#生成PDF:图4 - PDF输出

如何从Web API端点返回PDF以达到最高效率?

对于需要通过RESTful API提供PDF的应用程序,以下是如何实现有效的PDF交付与适当的内存管理。 这种方法在构建微服务时或需要在ASP.NET Core Web API控制器中生成PDF时特别有用:

using Microsoft.AspNetCore.Mvc;
using IronPdf;
using System.IO;
namespace PdfGeneratorApp.Controllers.Api
{
    [ApiController]
    [Route("api/[controller]")]
    public class PdfApiController : ControllerBase
    {
        private readonly ChromePdfRenderer _pdfRenderer;
        private readonly ILogger<PdfApiController> _logger;
        public PdfApiController(
            ChromePdfRenderer pdfRenderer,
            ILogger<PdfApiController> logger)
        {
            _pdfRenderer = pdfRenderer;
            _logger = logger;
        }
        [HttpPost("generate-report")]
        public async Task<IActionResult> GenerateReport([FromBody] ReportRequest request)
        {
            try
            {
                // Validate request
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
                // Build HTML content dynamically
                var htmlContent = BuildReportHtml(request);
                // Generate PDF with memory-efficient streaming
                using var pdfDocument = _pdfRenderer.RenderHtmlAsPdf(htmlContent);
                // Apply compression for smaller file size
                pdfDocument.CompressImages(60); // 60% quality
                // Stream the PDF directly to response
                var stream = new MemoryStream();
                pdfDocument.SaveAs(stream);
                stream.Position = 0;
                _logger.LogInformation($"Report generated for {request.ReportType}");
                return new FileStreamResult(stream, "application/pdf")
                {
                    FileDownloadName = $"Report_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"
                };
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, "Failed to generate report");
                return StatusCode(500, new { error = "Report generation failed" });
            }
        }
        [HttpGet("download/{documentId}")]
        public async Task<IActionResult> DownloadDocument(string documentId)
        {
            try
            {
                // In production, retrieve document from database or storage
                var documentPath = Path.Combine("wwwroot", "documents", $"{documentId}.pdf");
                if (!System.IO.File.Exists(documentPath))
                {
                    return NotFound(new { error = "Document not found" });
                }
                var memory = new MemoryStream();
                using (var stream = new FileStream(documentPath, FileMode.Open))
                {
                    await stream.CopyToAsync(memory);
                }
                memory.Position = 0;
                return File(memory, "application/pdf", $"Document_{documentId}.pdf");
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, $"Failed to download document {documentId}");
                return StatusCode(500, new { error = "Download failed" });
            }
        }
        private string BuildReportHtml(ReportRequest request)
        {
            return $@"
                <!DOCTYPE html>
                <html>
                <head>
                    <style>
                        body {{ 
                            font-family: Arial, sans-serif; 
                            margin: 40px;
                        }}
                        h1 {{ 
                            color: #2c3e50; 
                            border-bottom: 2px solid #3498db;
                            padding-bottom: 10px;
                        }}
                        .report-date {{ 
                            color: #7f8c8d; 
                            font-size: 14px;
                        }}
                        .data-table {{
                            width: 100%;
                            border-collapse: collapse;
                            margin-top: 20px;
                        }}
                        .data-table th, .data-table td {{
                            border: 1px solid #ddd;
                            padding: 12px;
                            text-align: left;
                        }}
                        .data-table th {{
                            background-color: #3498db;
                            color: white;
                        }}
                    </style>
                </head>
                <body>
                    <h1>{request.ReportType} Report</h1>
                    <p class='report-date'>Generated: {DateTime.Now:MMMM dd, yyyy HH:mm}</p>
                    <p>{request.Description}</p>
                    {GenerateDataTable(request.Data)}
                </body>
                </html>";
        }
        private string GenerateDataTable(List<ReportDataItem> data)
        {
            if (data == null || !data.Any())
                return "<p>No data available</p>";
            var table = "<table class='data-table'><thead><tr>";
            // Add headers
            foreach (var prop in typeof(ReportDataItem).GetProperties())
            {
                table += $"<th>{prop.Name}</th>";
            }
            table += "</tr></thead><tbody>";
            // Add data rows
            foreach (var item in data)
            {
                table += "<tr>";
                foreach (var prop in typeof(ReportDataItem).GetProperties())
                {
                    var value = prop.GetValue(item) ?? "";
                    table += $"<td>{value}</td>";
                }
                table += "</tr>";
            }
            table += "</tbody></table>";
            return table;
        }
    }
    public class ReportRequest
    {
        public string ReportType { get; set; }
        public string Description { get; set; }
        public List<ReportDataItem> Data { get; set; }
    }
    public class ReportDataItem
    {
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Value { get; set; }
        public DateTime Date { get; set; }
    }
}
using Microsoft.AspNetCore.Mvc;
using IronPdf;
using System.IO;
namespace PdfGeneratorApp.Controllers.Api
{
    [ApiController]
    [Route("api/[controller]")]
    public class PdfApiController : ControllerBase
    {
        private readonly ChromePdfRenderer _pdfRenderer;
        private readonly ILogger<PdfApiController> _logger;
        public PdfApiController(
            ChromePdfRenderer pdfRenderer,
            ILogger<PdfApiController> logger)
        {
            _pdfRenderer = pdfRenderer;
            _logger = logger;
        }
        [HttpPost("generate-report")]
        public async Task<IActionResult> GenerateReport([FromBody] ReportRequest request)
        {
            try
            {
                // Validate request
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
                // Build HTML content dynamically
                var htmlContent = BuildReportHtml(request);
                // Generate PDF with memory-efficient streaming
                using var pdfDocument = _pdfRenderer.RenderHtmlAsPdf(htmlContent);
                // Apply compression for smaller file size
                pdfDocument.CompressImages(60); // 60% quality
                // Stream the PDF directly to response
                var stream = new MemoryStream();
                pdfDocument.SaveAs(stream);
                stream.Position = 0;
                _logger.LogInformation($"Report generated for {request.ReportType}");
                return new FileStreamResult(stream, "application/pdf")
                {
                    FileDownloadName = $"Report_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"
                };
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, "Failed to generate report");
                return StatusCode(500, new { error = "Report generation failed" });
            }
        }
        [HttpGet("download/{documentId}")]
        public async Task<IActionResult> DownloadDocument(string documentId)
        {
            try
            {
                // In production, retrieve document from database or storage
                var documentPath = Path.Combine("wwwroot", "documents", $"{documentId}.pdf");
                if (!System.IO.File.Exists(documentPath))
                {
                    return NotFound(new { error = "Document not found" });
                }
                var memory = new MemoryStream();
                using (var stream = new FileStream(documentPath, FileMode.Open))
                {
                    await stream.CopyToAsync(memory);
                }
                memory.Position = 0;
                return File(memory, "application/pdf", $"Document_{documentId}.pdf");
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, $"Failed to download document {documentId}");
                return StatusCode(500, new { error = "Download failed" });
            }
        }
        private string BuildReportHtml(ReportRequest request)
        {
            return $@"
                <!DOCTYPE html>
                <html>
                <head>
                    <style>
                        body {{ 
                            font-family: Arial, sans-serif; 
                            margin: 40px;
                        }}
                        h1 {{ 
                            color: #2c3e50; 
                            border-bottom: 2px solid #3498db;
                            padding-bottom: 10px;
                        }}
                        .report-date {{ 
                            color: #7f8c8d; 
                            font-size: 14px;
                        }}
                        .data-table {{
                            width: 100%;
                            border-collapse: collapse;
                            margin-top: 20px;
                        }}
                        .data-table th, .data-table td {{
                            border: 1px solid #ddd;
                            padding: 12px;
                            text-align: left;
                        }}
                        .data-table th {{
                            background-color: #3498db;
                            color: white;
                        }}
                    </style>
                </head>
                <body>
                    <h1>{request.ReportType} Report</h1>
                    <p class='report-date'>Generated: {DateTime.Now:MMMM dd, yyyy HH:mm}</p>
                    <p>{request.Description}</p>
                    {GenerateDataTable(request.Data)}
                </body>
                </html>";
        }
        private string GenerateDataTable(List<ReportDataItem> data)
        {
            if (data == null || !data.Any())
                return "<p>No data available</p>";
            var table = "<table class='data-table'><thead><tr>";
            // Add headers
            foreach (var prop in typeof(ReportDataItem).GetProperties())
            {
                table += $"<th>{prop.Name}</th>";
            }
            table += "</tr></thead><tbody>";
            // Add data rows
            foreach (var item in data)
            {
                table += "<tr>";
                foreach (var prop in typeof(ReportDataItem).GetProperties())
                {
                    var value = prop.GetValue(item) ?? "";
                    table += $"<td>{value}</td>";
                }
                table += "</tr>";
            }
            table += "</tbody></table>";
            return table;
        }
    }
    public class ReportRequest
    {
        public string ReportType { get; set; }
        public string Description { get; set; }
        public List<ReportDataItem> Data { get; set; }
    }
    public class ReportDataItem
    {
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Value { get; set; }
        public DateTime Date { get; set; }
    }
}
Imports Microsoft.AspNetCore.Mvc
Imports IronPdf
Imports System.IO

Namespace PdfGeneratorApp.Controllers.Api

    <ApiController>
    <Route("api/[controller]")>
    Public Class PdfApiController
        Inherits ControllerBase

        Private ReadOnly _pdfRenderer As ChromePdfRenderer
        Private ReadOnly _logger As ILogger(Of PdfApiController)

        Public Sub New(pdfRenderer As ChromePdfRenderer, logger As ILogger(Of PdfApiController))
            _pdfRenderer = pdfRenderer
            _logger = logger
        End Sub

        <HttpPost("generate-report")>
        Public Async Function GenerateReport(<FromBody> request As ReportRequest) As Task(Of IActionResult)
            Try
                ' Validate request
                If Not ModelState.IsValid Then
                    Return BadRequest(ModelState)
                End If

                ' Build HTML content dynamically
                Dim htmlContent = BuildReportHtml(request)

                ' Generate PDF with memory-efficient streaming
                Using pdfDocument = _pdfRenderer.RenderHtmlAsPdf(htmlContent)
                    ' Apply compression for smaller file size
                    pdfDocument.CompressImages(60) ' 60% quality

                    ' Stream the PDF directly to response
                    Dim stream = New MemoryStream()
                    pdfDocument.SaveAs(stream)
                    stream.Position = 0
                    _logger.LogInformation($"Report generated for {request.ReportType}")
                    Return New FileStreamResult(stream, "application/pdf") With {
                        .FileDownloadName = $"Report_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"
                    }
                End Using
            Catch ex As Exception
                _logger.LogError(ex, "Failed to generate report")
                Return StatusCode(500, New With {.error = "Report generation failed"})
            End Try
        End Function

        <HttpGet("download/{documentId}")>
        Public Async Function DownloadDocument(documentId As String) As Task(Of IActionResult)
            Try
                ' In production, retrieve document from database or storage
                Dim documentPath = Path.Combine("wwwroot", "documents", $"{documentId}.pdf")
                If Not System.IO.File.Exists(documentPath) Then
                    Return NotFound(New With {.error = "Document not found"})
                End If

                Dim memory = New MemoryStream()
                Using stream = New FileStream(documentPath, FileMode.Open)
                    Await stream.CopyToAsync(memory)
                End Using
                memory.Position = 0
                Return File(memory, "application/pdf", $"Document_{documentId}.pdf")
            Catch ex As Exception
                _logger.LogError(ex, $"Failed to download document {documentId}")
                Return StatusCode(500, New With {.error = "Download failed"})
            End Try
        End Function

        Private Function BuildReportHtml(request As ReportRequest) As String
            Return $"
                <!DOCTYPE html>
                <html>
                <head>
                    <style>
                        body {{ 
                            font-family: Arial, sans-serif; 
                            margin: 40px;
                        }}
                        h1 {{ 
                            color: #2c3e50; 
                            border-bottom: 2px solid #3498db;
                            padding-bottom: 10px;
                        }}
                        .report-date {{ 
                            color: #7f8c8d; 
                            font-size: 14px;
                        }}
                        .data-table {{
                            width: 100%;
                            border-collapse: collapse;
                            margin-top: 20px;
                        }}
                        .data-table th, .data-table td {{
                            border: 1px solid #ddd;
                            padding: 12px;
                            text-align: left;
                        }}
                        .data-table th {{
                            background-color: #3498db;
                            color: white;
                        }}
                    </style>
                </head>
                <body>
                    <h1>{request.ReportType} Report</h1>
                    <p class='report-date'>Generated: {DateTime.Now:MMMM dd, yyyy HH:mm}</p>
                    <p>{request.Description}</p>
                    {GenerateDataTable(request.Data)}
                </body>
                </html>"
        End Function

        Private Function GenerateDataTable(data As List(Of ReportDataItem)) As String
            If data Is Nothing OrElse Not data.Any() Then
                Return "<p>No data available</p>"
            End If

            Dim table = "<table class='data-table'><thead><tr>"
            ' Add headers
            For Each prop In GetType(ReportDataItem).GetProperties()
                table += $"<th>{prop.Name}</th>"
            Next
            table += "</tr></thead><tbody>"
            ' Add data rows
            For Each item In data
                table += "<tr>"
                For Each prop In GetType(ReportDataItem).GetProperties()
                    Dim value = If(prop.GetValue(item), "")
                    table += $"<td>{value}</td>"
                Next
                table += "</tr>"
            Next
            table += "</tbody></table>"
            Return table
        End Function

    End Class

    Public Class ReportRequest
        Public Property ReportType As String
        Public Property Description As String
        Public Property Data As List(Of ReportDataItem)
    End Class

    Public Class ReportDataItem
        Public Property Name As String
        Public Property Category As String
        Public Property Value As Decimal
        Public Property Date As DateTime
    End Class

End Namespace
$vbLabelText   $csharpLabel

添加专业的页眉、页脚和样式

专业的PDF需要一致的页眉、页脚和样式。 IronPDF提供了简单的基于文本和高级的基于HTML的选项。 通过使用CSS样式来装饰HTML标记,我们可以创建自定义的PDF页眉和页脚。 以下代码片段将探究我们如何在当前项目中使用它:

using IronPdf;
using IronPdf.Extensions.Mvc.Core;
using Microsoft.AspNetCore.Mvc;
using PdfGeneratorApp.Models;
using PdfGeneratorApp.Services;
using System.Diagnostics;
namespace PdfGeneratorApp.Controllers
{
    public class InvoiceController : Controller
    {
        private readonly ILogger<InvoiceController> _logger;
        private readonly IRazorViewRenderer _viewRenderer;
        private readonly ChromePdfRenderer _pdfRenderer;
        private readonly PdfFormattingService _pdfFormattingService;
        private readonly IWebHostEnvironment _environment;
        public InvoiceController(
            ILogger<InvoiceController> logger,
            IRazorViewRenderer viewRenderer,
            ChromePdfRenderer pdfRenderer,
            PdfFormattingService pdfFormattingService,
            IWebHostEnvironment environment)
        {
            _logger = logger;
            _viewRenderer = viewRenderer;
            _pdfRenderer = pdfRenderer;
            _pdfFormattingService = pdfFormattingService;
            _environment = environment;
        }
        [HttpGet]
        public IActionResult Index()
        {
            // Display a form or list of invoices
            return View();
        }
        private void ConfigurePdfRendererOptions(ChromePdfRenderer renderer, InvoiceModel invoice, PdfStylingOptions options)
        {
            // Margins
            renderer.RenderingOptions.MarginTop = options.MarginTop;
            renderer.RenderingOptions.MarginBottom = options.MarginBottom;
            renderer.RenderingOptions.MarginLeft = options.MarginLeft;
            renderer.RenderingOptions.MarginRight = options.MarginRight;
            // Header
            if (options.UseHtmlHeader)
            {
                renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
                {
                    MaxHeight = 50,
                    HtmlFragment = $@"
                <div style='width: 100%; font-size: 12px; font-family: Arial;'>
                    <div style='float: left; width: 50%;'>

                        <img src='https://ironpdf.com/img/products/ironpdf-logo-text-dotnet.svg' height='40' />
                    </div>
                    <div style='float: right; width: 50%; text-align: right;'>
                        <strong>Invoice {invoice.InvoiceNumber}</strong><br/>
                        Generated: {DateTime.Now:yyyy-MM-dd}
                    </div>
                </div>",
                    LoadStylesAndCSSFromMainHtmlDocument = true
                };
            }
            else
            {
                renderer.RenderingOptions.TextHeader = new TextHeaderFooter
                {
                    CenterText = options.HeaderText,
                    Font = IronSoftware.Drawing.FontTypes.Arial,
                    FontSize = 12,
                    DrawDividerLine = true
                };
            }
            // Footer
            renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
            {
                MaxHeight = 30,
                HtmlFragment = @"
            <div style='width: 100%; font-size: 10px; color: #666;'>
                <div style='float: left; width: 33%;'>
                    © 2025 Your Company
                </div>
                <div style='float: center; width: 33%; text-align: center;'>
                    yourwebsite.com
                </div>
                <div style='float: right; width: 33%; text-align: right;'>
                    Page {page} of {total-pages}
                </div>
            </div>"
            };
            // Optional: Add watermark here (IronPDF supports adding after PDF is generated, so keep it as-is)
            // Margins, paper size etc., can also be set here if needed
            renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait;
            renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
            renderer.RenderingOptions.PrintHtmlBackgrounds = true;
        }
        [HttpGet]
        public async Task<IActionResult> GenerateInvoice(string invoiceNumber)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                // Validate input
                if (string.IsNullOrEmpty(invoiceNumber))
                {
                    _logger.LogWarning("Invoice generation attempted without invoice number");
                    return BadRequest("Invoice number is required");
                }
                // Generate sample data (in production, fetch from database)
                var invoice = CreateSampleInvoice(invoiceNumber);
                // Log the generation attempt
                _logger.LogInformation($"Generating PDF for invoice {invoiceNumber}");
                // Configure PDF rendering options
                _pdfRenderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait;
                _pdfRenderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
                _pdfRenderer.RenderingOptions.PrintHtmlBackgrounds = true;
                _pdfRenderer.RenderingOptions.CreatePdfFormsFromHtml = false;
                var options = new PdfStylingOptions
                {
                    MarginTop = 25,
                    MarginBottom = 25,
                    MarginLeft = 20,
                    MarginRight = 20,
                    UseHtmlHeader = true,
                    HeaderText = $"Invoice {invoice.InvoiceNumber}",
                    AddWatermark = false,
                    ForcePageBreaks = false
                };
                // Apply the styling to the renderer BEFORE rendering PDF
                ConfigurePdfRendererOptions(_pdfRenderer, invoice, options);
                // Render the view to PDF
                PdfDocument pdf;
                try
                {
                    pdf = _pdfRenderer.RenderRazorViewToPdf(
                        _viewRenderer,
                        "Views/Invoice/InvoiceTemplate.cshtml",
                        invoice);
                }
                catch (例外情况 renderEx)
                {
                    _logger.LogError(renderEx, "Failed to render Razor view to PDF");
                    throw new InvalidOperation例外情况("PDF rendering failed. Please check the template.", renderEx);
                }
                // Apply metadata
                pdf.MetaData.Author = "PdfGeneratorApp";
                pdf.MetaData.Title = $"Invoice {invoice.InvoiceNumber}";
                pdf.MetaData.Subject = $"Invoice for {invoice.Customer.Name}";
                pdf.MetaData.Keywords = "invoice, billing, payment";
                pdf.MetaData.CreationDate = DateTime.UtcNow;
                pdf.MetaData.ModifiedDate = DateTime.UtcNow;
                // Optional: Add password protection
                // pdf.SecuritySettings.UserPassword = "user123";
                // pdf.SecuritySettings.OwnerPassword = "owner456";
                // pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
                // Log performance metrics
                stopwatch.Stop();
                _logger.LogInformation($"PDF generated successfully for invoice {invoiceNumber} in {stopwatch.ElapsedMilliseconds}ms");
                // Return the PDF file
                Response.Headers.Add("Content-Disposition", $"inline; filename=Invoice_{invoiceNumber}.pdf");
                return File(pdf.BinaryData, "application/pdf", $"Invoice_{invoiceNumber}.pdf");
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, $"Error generating PDF for invoice {invoiceNumber}");
                // In development, return detailed error
                if (_environment.IsDevelopment())
                {
                    return StatusCode(500, new
                    {
                        error = "PDF generation failed",
                        message = ex.Message,
                        stackTrace = ex.StackTrace
                    });
                }
                // In production, return generic error
                return StatusCode(500, "An error occurred while generating the PDF");
            }
        }
        private InvoiceModel CreateSampleInvoice(string invoiceNumber)
        {
            return new InvoiceModel
            {
                InvoiceNumber = invoiceNumber,
                InvoiceDate = DateTime.Now,
                DueDate = DateTime.Now.AddDays(30),
                Vendor = new CompanyInfo
                {
                    Name = "Tech 解决方案s Inc.",
                    Address = "123 Business Ave",
                    City = "New York",
                    State = "NY",
                    ZipCode = "10001",
                    Email = "billing@techsolutions.com",
                    Phone = "(555) 123-4567"
                },
                Customer = new CompanyInfo
                {
                    Name = "Acme Corporation",
                    Address = "456 Commerce St",
                    City = "Los Angeles",
                    State = "CA",
                    ZipCode = "90001",
                    Email = "accounts@acmecorp.com",
                    Phone = "(555) 987-6543"
                },
                Items = new List<InvoiceItem>
                {
                    new InvoiceItem
                    {
                        Description = "Software Development Services - 40 hours",
                        Quantity = 40,
                        UnitPrice = 150.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Project Management - 10 hours",
                        Quantity = 10,
                        UnitPrice = 120.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Quality Assurance Testing",
                        Quantity = 1,
                        UnitPrice = 2500.00m
                    }
                },
                TaxRate = 8.875m,
                Notes = "Payment is due within 30 days. Late payments subject to 1.5% monthly interest.",
                PaymentTerms = "Net 30"
            };
        }
    }
}
using IronPdf;
using IronPdf.Extensions.Mvc.Core;
using Microsoft.AspNetCore.Mvc;
using PdfGeneratorApp.Models;
using PdfGeneratorApp.Services;
using System.Diagnostics;
namespace PdfGeneratorApp.Controllers
{
    public class InvoiceController : Controller
    {
        private readonly ILogger<InvoiceController> _logger;
        private readonly IRazorViewRenderer _viewRenderer;
        private readonly ChromePdfRenderer _pdfRenderer;
        private readonly PdfFormattingService _pdfFormattingService;
        private readonly IWebHostEnvironment _environment;
        public InvoiceController(
            ILogger<InvoiceController> logger,
            IRazorViewRenderer viewRenderer,
            ChromePdfRenderer pdfRenderer,
            PdfFormattingService pdfFormattingService,
            IWebHostEnvironment environment)
        {
            _logger = logger;
            _viewRenderer = viewRenderer;
            _pdfRenderer = pdfRenderer;
            _pdfFormattingService = pdfFormattingService;
            _environment = environment;
        }
        [HttpGet]
        public IActionResult Index()
        {
            // Display a form or list of invoices
            return View();
        }
        private void ConfigurePdfRendererOptions(ChromePdfRenderer renderer, InvoiceModel invoice, PdfStylingOptions options)
        {
            // Margins
            renderer.RenderingOptions.MarginTop = options.MarginTop;
            renderer.RenderingOptions.MarginBottom = options.MarginBottom;
            renderer.RenderingOptions.MarginLeft = options.MarginLeft;
            renderer.RenderingOptions.MarginRight = options.MarginRight;
            // Header
            if (options.UseHtmlHeader)
            {
                renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
                {
                    MaxHeight = 50,
                    HtmlFragment = $@"
                <div style='width: 100%; font-size: 12px; font-family: Arial;'>
                    <div style='float: left; width: 50%;'>

                        <img src='https://ironpdf.com/img/products/ironpdf-logo-text-dotnet.svg' height='40' />
                    </div>
                    <div style='float: right; width: 50%; text-align: right;'>
                        <strong>Invoice {invoice.InvoiceNumber}</strong><br/>
                        Generated: {DateTime.Now:yyyy-MM-dd}
                    </div>
                </div>",
                    LoadStylesAndCSSFromMainHtmlDocument = true
                };
            }
            else
            {
                renderer.RenderingOptions.TextHeader = new TextHeaderFooter
                {
                    CenterText = options.HeaderText,
                    Font = IronSoftware.Drawing.FontTypes.Arial,
                    FontSize = 12,
                    DrawDividerLine = true
                };
            }
            // Footer
            renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
            {
                MaxHeight = 30,
                HtmlFragment = @"
            <div style='width: 100%; font-size: 10px; color: #666;'>
                <div style='float: left; width: 33%;'>
                    © 2025 Your Company
                </div>
                <div style='float: center; width: 33%; text-align: center;'>
                    yourwebsite.com
                </div>
                <div style='float: right; width: 33%; text-align: right;'>
                    Page {page} of {total-pages}
                </div>
            </div>"
            };
            // Optional: Add watermark here (IronPDF supports adding after PDF is generated, so keep it as-is)
            // Margins, paper size etc., can also be set here if needed
            renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait;
            renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
            renderer.RenderingOptions.PrintHtmlBackgrounds = true;
        }
        [HttpGet]
        public async Task<IActionResult> GenerateInvoice(string invoiceNumber)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                // Validate input
                if (string.IsNullOrEmpty(invoiceNumber))
                {
                    _logger.LogWarning("Invoice generation attempted without invoice number");
                    return BadRequest("Invoice number is required");
                }
                // Generate sample data (in production, fetch from database)
                var invoice = CreateSampleInvoice(invoiceNumber);
                // Log the generation attempt
                _logger.LogInformation($"Generating PDF for invoice {invoiceNumber}");
                // Configure PDF rendering options
                _pdfRenderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait;
                _pdfRenderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
                _pdfRenderer.RenderingOptions.PrintHtmlBackgrounds = true;
                _pdfRenderer.RenderingOptions.CreatePdfFormsFromHtml = false;
                var options = new PdfStylingOptions
                {
                    MarginTop = 25,
                    MarginBottom = 25,
                    MarginLeft = 20,
                    MarginRight = 20,
                    UseHtmlHeader = true,
                    HeaderText = $"Invoice {invoice.InvoiceNumber}",
                    AddWatermark = false,
                    ForcePageBreaks = false
                };
                // Apply the styling to the renderer BEFORE rendering PDF
                ConfigurePdfRendererOptions(_pdfRenderer, invoice, options);
                // Render the view to PDF
                PdfDocument pdf;
                try
                {
                    pdf = _pdfRenderer.RenderRazorViewToPdf(
                        _viewRenderer,
                        "Views/Invoice/InvoiceTemplate.cshtml",
                        invoice);
                }
                catch (例外情况 renderEx)
                {
                    _logger.LogError(renderEx, "Failed to render Razor view to PDF");
                    throw new InvalidOperation例外情况("PDF rendering failed. Please check the template.", renderEx);
                }
                // Apply metadata
                pdf.MetaData.Author = "PdfGeneratorApp";
                pdf.MetaData.Title = $"Invoice {invoice.InvoiceNumber}";
                pdf.MetaData.Subject = $"Invoice for {invoice.Customer.Name}";
                pdf.MetaData.Keywords = "invoice, billing, payment";
                pdf.MetaData.CreationDate = DateTime.UtcNow;
                pdf.MetaData.ModifiedDate = DateTime.UtcNow;
                // Optional: Add password protection
                // pdf.SecuritySettings.UserPassword = "user123";
                // pdf.SecuritySettings.OwnerPassword = "owner456";
                // pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
                // Log performance metrics
                stopwatch.Stop();
                _logger.LogInformation($"PDF generated successfully for invoice {invoiceNumber} in {stopwatch.ElapsedMilliseconds}ms");
                // Return the PDF file
                Response.Headers.Add("Content-Disposition", $"inline; filename=Invoice_{invoiceNumber}.pdf");
                return File(pdf.BinaryData, "application/pdf", $"Invoice_{invoiceNumber}.pdf");
            }
            catch (例外情况 ex)
            {
                _logger.LogError(ex, $"Error generating PDF for invoice {invoiceNumber}");
                // In development, return detailed error
                if (_environment.IsDevelopment())
                {
                    return StatusCode(500, new
                    {
                        error = "PDF generation failed",
                        message = ex.Message,
                        stackTrace = ex.StackTrace
                    });
                }
                // In production, return generic error
                return StatusCode(500, "An error occurred while generating the PDF");
            }
        }
        private InvoiceModel CreateSampleInvoice(string invoiceNumber)
        {
            return new InvoiceModel
            {
                InvoiceNumber = invoiceNumber,
                InvoiceDate = DateTime.Now,
                DueDate = DateTime.Now.AddDays(30),
                Vendor = new CompanyInfo
                {
                    Name = "Tech 解决方案s Inc.",
                    Address = "123 Business Ave",
                    City = "New York",
                    State = "NY",
                    ZipCode = "10001",
                    Email = "billing@techsolutions.com",
                    Phone = "(555) 123-4567"
                },
                Customer = new CompanyInfo
                {
                    Name = "Acme Corporation",
                    Address = "456 Commerce St",
                    City = "Los Angeles",
                    State = "CA",
                    ZipCode = "90001",
                    Email = "accounts@acmecorp.com",
                    Phone = "(555) 987-6543"
                },
                Items = new List<InvoiceItem>
                {
                    new InvoiceItem
                    {
                        Description = "Software Development Services - 40 hours",
                        Quantity = 40,
                        UnitPrice = 150.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Project Management - 10 hours",
                        Quantity = 10,
                        UnitPrice = 120.00m
                    },
                    new InvoiceItem
                    {
                        Description = "Quality Assurance Testing",
                        Quantity = 1,
                        UnitPrice = 2500.00m
                    }
                },
                TaxRate = 8.875m,
                Notes = "Payment is due within 30 days. Late payments subject to 1.5% monthly interest.",
                PaymentTerms = "Net 30"
            };
        }
    }
}
Imports IronPdf
Imports IronPdf.Extensions.Mvc.Core
Imports Microsoft.AspNetCore.Mvc
Imports PdfGeneratorApp.Models
Imports PdfGeneratorApp.Services
Imports System.Diagnostics

Namespace PdfGeneratorApp.Controllers

    Public Class InvoiceController
        Inherits Controller

        Private ReadOnly _logger As ILogger(Of InvoiceController)
        Private ReadOnly _viewRenderer As IRazorViewRenderer
        Private ReadOnly _pdfRenderer As ChromePdfRenderer
        Private ReadOnly _pdfFormattingService As PdfFormattingService
        Private ReadOnly _environment As IWebHostEnvironment

        Public Sub New(logger As ILogger(Of InvoiceController),
                       viewRenderer As IRazorViewRenderer,
                       pdfRenderer As ChromePdfRenderer,
                       pdfFormattingService As PdfFormattingService,
                       environment As IWebHostEnvironment)
            _logger = logger
            _viewRenderer = viewRenderer
            _pdfRenderer = pdfRenderer
            _pdfFormattingService = pdfFormattingService
            _environment = environment
        End Sub

        <HttpGet>
        Public Function Index() As IActionResult
            ' Display a form or list of invoices
            Return View()
        End Function

        Private Sub ConfigurePdfRendererOptions(renderer As ChromePdfRenderer, invoice As InvoiceModel, options As PdfStylingOptions)
            ' Margins
            renderer.RenderingOptions.MarginTop = options.MarginTop
            renderer.RenderingOptions.MarginBottom = options.MarginBottom
            renderer.RenderingOptions.MarginLeft = options.MarginLeft
            renderer.RenderingOptions.MarginRight = options.MarginRight

            ' Header
            If options.UseHtmlHeader Then
                renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
                    .MaxHeight = 50,
                    .HtmlFragment = $"
                <div style='width: 100%; font-size: 12px; font-family: Arial;'>
                    <div style='float: left; width: 50%;'>
                        <img src='https://ironpdf.com/img/products/ironpdf-logo-text-dotnet.svg' height='40' />
                    </div>
                    <div style='float: right; width: 50%; text-align: right;'>
                        <strong>Invoice {invoice.InvoiceNumber}</strong><br/>
                        Generated: {DateTime.Now:yyyy-MM-dd}
                    </div>
                </div>",
                    .LoadStylesAndCSSFromMainHtmlDocument = True
                }
            Else
                renderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
                    .CenterText = options.HeaderText,
                    .Font = IronSoftware.Drawing.FontTypes.Arial,
                    .FontSize = 12,
                    .DrawDividerLine = True
                }
            End If

            ' Footer
            renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
                .MaxHeight = 30,
                .HtmlFragment = "
            <div style='width: 100%; font-size: 10px; color: #666;'>
                <div style='float: left; width: 33%;'>
                    © 2025 Your Company
                </div>
                <div style='float: center; width: 33%; text-align: center;'>
                    yourwebsite.com
                </div>
                <div style='float: right; width: 33%; text-align: right;'>
                    Page {page} of {total-pages}
                </div>
            </div>"
            }

            ' Optional: Add watermark here (IronPDF supports adding after PDF is generated, so keep it as-is)
            ' Margins, paper size etc., can also be set here if needed
            renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait
            renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
            renderer.RenderingOptions.PrintHtmlBackgrounds = True
        End Sub

        <HttpGet>
        Public Async Function GenerateInvoice(invoiceNumber As String) As Task(Of IActionResult)
            Dim stopwatch = Stopwatch.StartNew()
            Try
                ' Validate input
                If String.IsNullOrEmpty(invoiceNumber) Then
                    _logger.LogWarning("Invoice generation attempted without invoice number")
                    Return BadRequest("Invoice number is required")
                End If

                ' Generate sample data (in production, fetch from database)
                Dim invoice = CreateSampleInvoice(invoiceNumber)

                ' Log the generation attempt
                _logger.LogInformation($"Generating PDF for invoice {invoiceNumber}")

                ' Configure PDF rendering options
                _pdfRenderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Portrait
                _pdfRenderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
                _pdfRenderer.RenderingOptions.PrintHtmlBackgrounds = True
                _pdfRenderer.RenderingOptions.CreatePdfFormsFromHtml = False

                Dim options = New PdfStylingOptions With {
                    .MarginTop = 25,
                    .MarginBottom = 25,
                    .MarginLeft = 20,
                    .MarginRight = 20,
                    .UseHtmlHeader = True,
                    .HeaderText = $"Invoice {invoice.InvoiceNumber}",
                    .AddWatermark = False,
                    .ForcePageBreaks = False
                }

                ' Apply the styling to the renderer BEFORE rendering PDF
                ConfigurePdfRendererOptions(_pdfRenderer, invoice, options)

                ' Render the view to PDF
                Dim pdf As PdfDocument
                Try
                    pdf = _pdfRenderer.RenderRazorViewToPdf(
                        _viewRenderer,
                        "Views/Invoice/InvoiceTemplate.cshtml",
                        invoice)
                Catch renderEx As Exception
                    _logger.LogError(renderEx, "Failed to render Razor view to PDF")
                    Throw New InvalidOperationException("PDF rendering failed. Please check the template.", renderEx)
                End Try

                ' Apply metadata
                pdf.MetaData.Author = "PdfGeneratorApp"
                pdf.MetaData.Title = $"Invoice {invoice.InvoiceNumber}"
                pdf.MetaData.Subject = $"Invoice for {invoice.Customer.Name}"
                pdf.MetaData.Keywords = "invoice, billing, payment"
                pdf.MetaData.CreationDate = DateTime.UtcNow
                pdf.MetaData.ModifiedDate = DateTime.UtcNow

                ' Optional: Add password protection
                ' pdf.SecuritySettings.UserPassword = "user123"
                ' pdf.SecuritySettings.OwnerPassword = "owner456"
                ' pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights

                ' Log performance metrics
                stopwatch.Stop()
                _logger.LogInformation($"PDF generated successfully for invoice {invoiceNumber} in {stopwatch.ElapsedMilliseconds}ms")

                ' Return the PDF file
                Response.Headers.Add("Content-Disposition", $"inline; filename=Invoice_{invoiceNumber}.pdf")
                Return File(pdf.BinaryData, "application/pdf", $"Invoice_{invoiceNumber}.pdf")
            Catch ex As Exception
                _logger.LogError(ex, $"Error generating PDF for invoice {invoiceNumber}")

                ' In development, return detailed error
                If _environment.IsDevelopment() Then
                    Return StatusCode(500, New With {
                        .error = "PDF generation failed",
                        .message = ex.Message,
                        .stackTrace = ex.StackTrace
                    })
                End If

                ' In production, return generic error
                Return StatusCode(500, "An error occurred while generating the PDF")
            End Try
        End Function

        Private Function CreateSampleInvoice(invoiceNumber As String) As InvoiceModel
            Return New InvoiceModel With {
                .InvoiceNumber = invoiceNumber,
                .InvoiceDate = DateTime.Now,
                .DueDate = DateTime.Now.AddDays(30),
                .Vendor = New CompanyInfo With {
                    .Name = "Tech Solutions Inc.",
                    .Address = "123 Business Ave",
                    .City = "New York",
                    .State = "NY",
                    .ZipCode = "10001",
                    .Email = "billing@techsolutions.com",
                    .Phone = "(555) 123-4567"
                },
                .Customer = New CompanyInfo With {
                    .Name = "Acme Corporation",
                    .Address = "456 Commerce St",
                    .City = "Los Angeles",
                    .State = "CA",
                    .ZipCode = "90001",
                    .Email = "accounts@acmecorp.com",
                    .Phone = "(555) 987-6543"
                },
                .Items = New List(Of InvoiceItem) From {
                    New InvoiceItem With {
                        .Description = "Software Development Services - 40 hours",
                        .Quantity = 40,
                        .UnitPrice = 150.0D
                    },
                    New InvoiceItem With {
                        .Description = "Project Management - 10 hours",
                        .Quantity = 10,
                        .UnitPrice = 120.0D
                    },
                    New InvoiceItem With {
                        .Description = "Quality Assurance Testing",
                        .Quantity = 1,
                        .UnitPrice = 2500.0D
                    }
                },
                .TaxRate = 8.875D,
                .Notes = "Payment is due within 30 days. Late payments subject to 1.5% monthly interest.",
                .PaymentTerms = "Net 30"
            }
        End Function

    End Class

End Namespace
$vbLabelText   $csharpLabel

代码解释

您可以看到基本页眉和样式页眉之间的简要差异。 使用IronPDF,您甚至可以为您的发票添加定制的HTML页眉和页脚,以进一步美化并完全个性化。
有关添加页眉和页脚的详细信息,请参阅本操作指南

输出

如何在ASP.NET中使用C#生成PDF:图5 - 样式化的PDF输出

如何实施高性能的批量PDF处理?

需要生成数百或数千个PDF? 以下是如何通过并行处理来实现最佳性能,同时高效管理内存。 下载我们完整的工作示例,看它在实际中的运用。

对于需要高效生成多个PDF的应用程序,这里有一个使用异步和多线程技术的优化批处理实现。 此方法遵循微软的并行编程最佳实践,旨在通过 C# 在 .NET Core 中生成 PDF 时实现最佳性能:

using System.Collections.Concurrent;
using System.Diagnostics;
public class BatchPdfProcessor
{
    private readonly ChromePdfRenderer _renderer;
    private readonly ILogger<BatchPdfProcessor> _logger;
    private readonly SemaphoreSlim _semaphore;
    public BatchPdfProcessor(
        ChromePdfRenderer renderer,
        ILogger<BatchPdfProcessor> logger)
    {
        _renderer = renderer;
        _logger = logger;
        // Limit concurrent PDF generation to prevent memory exhaustion
        _semaphore = new SemaphoreSlim(Environment.ProcessorCount);
    }
    public async Task<BatchProcessingResult> ProcessBatchAsync(
        List<BatchPdfRequest> requests,
        IProgress<BatchProgressReport> progress = null)
    {
        var result = new BatchProcessingResult
        {
            StartTime = DateTime.UtcNow,
            TotalRequests = requests.Count
        };
        var successfulPdfs = new ConcurrentBag<GeneratedPdf>();
        var errors = new ConcurrentBag<ProcessingError>();
        var stopwatch = Stopwatch.StartNew();
        // Process PDFs in parallel with controlled concurrency
        var tasks = requests.Select(async (request, index) =>
        {
            await _semaphore.WaitAsync();
            try
            {
                var taskStopwatch = Stopwatch.StartNew();
                // Generate PDF
                var pdf = await GeneratePdfAsync(request);
                taskStopwatch.Stop();
                successfulPdfs.Add(new GeneratedPdf
                {
                    Id = request.Id,
                    FileName = request.FileName,
                    Data = pdf.BinaryData,
                    GenerationTime = taskStopwatch.ElapsedMilliseconds,
                    PageCount = pdf.PageCount
                });
                // Report progress
                progress?.Report(new BatchProgressReport
                {
                    ProcessedCount = successfulPdfs.Count + errors.Count,
                    TotalCount = requests.Count,
                    CurrentFile = request.FileName
                });
                _logger.LogDebug($"Generated PDF {request.Id} in {taskStopwatch.ElapsedMilliseconds}ms");
            }
            catch (例外情况 ex)
            {
                errors.Add(new ProcessingError
                {
                    RequestId = request.Id,
                    FileName = request.FileName,
                    Error = ex.Message,
                    StackTrace = ex.StackTrace
                });
                _logger.LogError(ex, $"Failed to generate PDF for request {request.Id}");
            }
            finally
            {
                _semaphore.Release();
            }
        });
        await Task.WhenAll(tasks);
        stopwatch.Stop();
        // Compile results
        result.EndTime = DateTime.UtcNow;
        result.TotalProcessingTime = stopwatch.ElapsedMilliseconds;
        result.SuccessfulPdfs = successfulPdfs.ToList();
        result.Errors = errors.ToList();
        result.SuccessCount = successfulPdfs.Count;
        result.ErrorCount = errors.Count;
        result.AverageGenerationTime = successfulPdfs.Any() 
            ? successfulPdfs.Average(p => p.GenerationTime) 
            : 0;
        result.TotalPages = successfulPdfs.Sum(p => p.PageCount);
        result.TotalSizeBytes = successfulPdfs.Sum(p => p.Data.Length);
        // Log summary
        _logger.LogInformation($"Batch processing completed: {result.SuccessCount} successful, " +
                             $"{result.ErrorCount} errors, {result.TotalProcessingTime}ms total time");
        // Clean up memory after large batch
        if (requests.Count > 100)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
        return result;
    }
    private async Task<PdfDocument> GeneratePdfAsync(BatchPdfRequest request)
    {
        return await Task.Run(() =>
        {
            // Configure renderer for this specific request
            var localRenderer = new ChromePdfRenderer();
            localRenderer.RenderingOptions.PaperSize = request.PaperSize;
            localRenderer.RenderingOptions.MarginTop = request.MarginTop;
            localRenderer.RenderingOptions.MarginBottom = request.MarginBottom;
            // Generate PDF
            var pdf = localRenderer.RenderHtmlAsPdf(request.HtmlContent);
            // Apply compression if requested
            if (request.CompressImages)
            {
                pdf.CompressImages(request.CompressionQuality);
            }
            return pdf;
        });
    }
}
public class BatchPdfRequest
{
    public string Id { get; set; }
    public string FileName { get; set; }
    public string HtmlContent { get; set; }
    public IronPdf.Rendering.PdfPaperSize PaperSize { get; set; } = IronPdf.Rendering.PdfPaperSize.A4;
    public int MarginTop { get; set; } = 25;
    public int MarginBottom { get; set; } = 25;
    public bool CompressImages { get; set; } = true;
    public int CompressionQuality { get; set; } = 80;
}
public class BatchProcessingResult
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
    public long TotalProcessingTime { get; set; }
    public int TotalRequests { get; set; }
    public int SuccessCount { get; set; }
    public int ErrorCount { get; set; }
    public double AverageGenerationTime { get; set; }
    public int TotalPages { get; set; }
    public long TotalSizeBytes { get; set; }
    public List<GeneratedPdf> SuccessfulPdfs { get; set; }
    public List<ProcessingError> Errors { get; set; }
}
public class GeneratedPdf
{
    public string Id { get; set; }
    public string FileName { get; set; }
    public byte[] Data { get; set; }
    public long GenerationTime { get; set; }
    public int PageCount { get; set; }
}
public class ProcessingError
{
    public string RequestId { get; set; }
    public string FileName { get; set; }
    public string Error { get; set; }
    public string StackTrace { get; set; }
}
public class BatchProgressReport
{
    public int ProcessedCount { get; set; }
    public int TotalCount { get; set; }
    public string CurrentFile { get; set; }
    public double PercentComplete => (double)ProcessedCount / TotalCount * 100;
}
using System.Collections.Concurrent;
using System.Diagnostics;
public class BatchPdfProcessor
{
    private readonly ChromePdfRenderer _renderer;
    private readonly ILogger<BatchPdfProcessor> _logger;
    private readonly SemaphoreSlim _semaphore;
    public BatchPdfProcessor(
        ChromePdfRenderer renderer,
        ILogger<BatchPdfProcessor> logger)
    {
        _renderer = renderer;
        _logger = logger;
        // Limit concurrent PDF generation to prevent memory exhaustion
        _semaphore = new SemaphoreSlim(Environment.ProcessorCount);
    }
    public async Task<BatchProcessingResult> ProcessBatchAsync(
        List<BatchPdfRequest> requests,
        IProgress<BatchProgressReport> progress = null)
    {
        var result = new BatchProcessingResult
        {
            StartTime = DateTime.UtcNow,
            TotalRequests = requests.Count
        };
        var successfulPdfs = new ConcurrentBag<GeneratedPdf>();
        var errors = new ConcurrentBag<ProcessingError>();
        var stopwatch = Stopwatch.StartNew();
        // Process PDFs in parallel with controlled concurrency
        var tasks = requests.Select(async (request, index) =>
        {
            await _semaphore.WaitAsync();
            try
            {
                var taskStopwatch = Stopwatch.StartNew();
                // Generate PDF
                var pdf = await GeneratePdfAsync(request);
                taskStopwatch.Stop();
                successfulPdfs.Add(new GeneratedPdf
                {
                    Id = request.Id,
                    FileName = request.FileName,
                    Data = pdf.BinaryData,
                    GenerationTime = taskStopwatch.ElapsedMilliseconds,
                    PageCount = pdf.PageCount
                });
                // Report progress
                progress?.Report(new BatchProgressReport
                {
                    ProcessedCount = successfulPdfs.Count + errors.Count,
                    TotalCount = requests.Count,
                    CurrentFile = request.FileName
                });
                _logger.LogDebug($"Generated PDF {request.Id} in {taskStopwatch.ElapsedMilliseconds}ms");
            }
            catch (例外情况 ex)
            {
                errors.Add(new ProcessingError
                {
                    RequestId = request.Id,
                    FileName = request.FileName,
                    Error = ex.Message,
                    StackTrace = ex.StackTrace
                });
                _logger.LogError(ex, $"Failed to generate PDF for request {request.Id}");
            }
            finally
            {
                _semaphore.Release();
            }
        });
        await Task.WhenAll(tasks);
        stopwatch.Stop();
        // Compile results
        result.EndTime = DateTime.UtcNow;
        result.TotalProcessingTime = stopwatch.ElapsedMilliseconds;
        result.SuccessfulPdfs = successfulPdfs.ToList();
        result.Errors = errors.ToList();
        result.SuccessCount = successfulPdfs.Count;
        result.ErrorCount = errors.Count;
        result.AverageGenerationTime = successfulPdfs.Any() 
            ? successfulPdfs.Average(p => p.GenerationTime) 
            : 0;
        result.TotalPages = successfulPdfs.Sum(p => p.PageCount);
        result.TotalSizeBytes = successfulPdfs.Sum(p => p.Data.Length);
        // Log summary
        _logger.LogInformation($"Batch processing completed: {result.SuccessCount} successful, " +
                             $"{result.ErrorCount} errors, {result.TotalProcessingTime}ms total time");
        // Clean up memory after large batch
        if (requests.Count > 100)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
        return result;
    }
    private async Task<PdfDocument> GeneratePdfAsync(BatchPdfRequest request)
    {
        return await Task.Run(() =>
        {
            // Configure renderer for this specific request
            var localRenderer = new ChromePdfRenderer();
            localRenderer.RenderingOptions.PaperSize = request.PaperSize;
            localRenderer.RenderingOptions.MarginTop = request.MarginTop;
            localRenderer.RenderingOptions.MarginBottom = request.MarginBottom;
            // Generate PDF
            var pdf = localRenderer.RenderHtmlAsPdf(request.HtmlContent);
            // Apply compression if requested
            if (request.CompressImages)
            {
                pdf.CompressImages(request.CompressionQuality);
            }
            return pdf;
        });
    }
}
public class BatchPdfRequest
{
    public string Id { get; set; }
    public string FileName { get; set; }
    public string HtmlContent { get; set; }
    public IronPdf.Rendering.PdfPaperSize PaperSize { get; set; } = IronPdf.Rendering.PdfPaperSize.A4;
    public int MarginTop { get; set; } = 25;
    public int MarginBottom { get; set; } = 25;
    public bool CompressImages { get; set; } = true;
    public int CompressionQuality { get; set; } = 80;
}
public class BatchProcessingResult
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
    public long TotalProcessingTime { get; set; }
    public int TotalRequests { get; set; }
    public int SuccessCount { get; set; }
    public int ErrorCount { get; set; }
    public double AverageGenerationTime { get; set; }
    public int TotalPages { get; set; }
    public long TotalSizeBytes { get; set; }
    public List<GeneratedPdf> SuccessfulPdfs { get; set; }
    public List<ProcessingError> Errors { get; set; }
}
public class GeneratedPdf
{
    public string Id { get; set; }
    public string FileName { get; set; }
    public byte[] Data { get; set; }
    public long GenerationTime { get; set; }
    public int PageCount { get; set; }
}
public class ProcessingError
{
    public string RequestId { get; set; }
    public string FileName { get; set; }
    public string Error { get; set; }
    public string StackTrace { get; set; }
}
public class BatchProgressReport
{
    public int ProcessedCount { get; set; }
    public int TotalCount { get; set; }
    public string CurrentFile { get; set; }
    public double PercentComplete => (double)ProcessedCount / TotalCount * 100;
}
Imports System.Collections.Concurrent
Imports System.Diagnostics

Public Class BatchPdfProcessor
    Private ReadOnly _renderer As ChromePdfRenderer
    Private ReadOnly _logger As ILogger(Of BatchPdfProcessor)
    Private ReadOnly _semaphore As SemaphoreSlim

    Public Sub New(renderer As ChromePdfRenderer, logger As ILogger(Of BatchPdfProcessor))
        _renderer = renderer
        _logger = logger
        ' Limit concurrent PDF generation to prevent memory exhaustion
        _semaphore = New SemaphoreSlim(Environment.ProcessorCount)
    End Sub

    Public Async Function ProcessBatchAsync(requests As List(Of BatchPdfRequest), Optional progress As IProgress(Of BatchProgressReport) = Nothing) As Task(Of BatchProcessingResult)
        Dim result As New BatchProcessingResult With {
            .StartTime = DateTime.UtcNow,
            .TotalRequests = requests.Count
        }
        Dim successfulPdfs As New ConcurrentBag(Of GeneratedPdf)()
        Dim errors As New ConcurrentBag(Of ProcessingError)()
        Dim stopwatch As Stopwatch = Stopwatch.StartNew()

        ' Process PDFs in parallel with controlled concurrency
        Dim tasks = requests.Select(Async Function(request, index)
                                        Await _semaphore.WaitAsync()
                                        Try
                                            Dim taskStopwatch As Stopwatch = Stopwatch.StartNew()
                                            ' Generate PDF
                                            Dim pdf = Await GeneratePdfAsync(request)
                                            taskStopwatch.Stop()
                                            successfulPdfs.Add(New GeneratedPdf With {
                                                .Id = request.Id,
                                                .FileName = request.FileName,
                                                .Data = pdf.BinaryData,
                                                .GenerationTime = taskStopwatch.ElapsedMilliseconds,
                                                .PageCount = pdf.PageCount
                                            })
                                            ' Report progress
                                            If progress IsNot Nothing Then
                                                progress.Report(New BatchProgressReport With {
                                                    .ProcessedCount = successfulPdfs.Count + errors.Count,
                                                    .TotalCount = requests.Count,
                                                    .CurrentFile = request.FileName
                                                })
                                            End If
                                            _logger.LogDebug($"Generated PDF {request.Id} in {taskStopwatch.ElapsedMilliseconds}ms")
                                        Catch ex As Exception
                                            errors.Add(New ProcessingError With {
                                                .RequestId = request.Id,
                                                .FileName = request.FileName,
                                                .Error = ex.Message,
                                                .StackTrace = ex.StackTrace
                                            })
                                            _logger.LogError(ex, $"Failed to generate PDF for request {request.Id}")
                                        Finally
                                            _semaphore.Release()
                                        End Try
                                    End Function)

        Await Task.WhenAll(tasks)
        stopwatch.Stop()

        ' Compile results
        result.EndTime = DateTime.UtcNow
        result.TotalProcessingTime = stopwatch.ElapsedMilliseconds
        result.SuccessfulPdfs = successfulPdfs.ToList()
        result.Errors = errors.ToList()
        result.SuccessCount = successfulPdfs.Count
        result.ErrorCount = errors.Count
        result.AverageGenerationTime = If(successfulPdfs.Any(), successfulPdfs.Average(Function(p) p.GenerationTime), 0)
        result.TotalPages = successfulPdfs.Sum(Function(p) p.PageCount)
        result.TotalSizeBytes = successfulPdfs.Sum(Function(p) p.Data.Length)

        ' Log summary
        _logger.LogInformation($"Batch processing completed: {result.SuccessCount} successful, {result.ErrorCount} errors, {result.TotalProcessingTime}ms total time")

        ' Clean up memory after large batch
        If requests.Count > 100 Then
            GC.Collect()
            GC.WaitForPendingFinalizers()
            GC.Collect()
        End If

        Return result
    End Function

    Private Async Function GeneratePdfAsync(request As BatchPdfRequest) As Task(Of PdfDocument)
        Return Await Task.Run(Function()
                                  ' Configure renderer for this specific request
                                  Dim localRenderer As New ChromePdfRenderer()
                                  localRenderer.RenderingOptions.PaperSize = request.PaperSize
                                  localRenderer.RenderingOptions.MarginTop = request.MarginTop
                                  localRenderer.RenderingOptions.MarginBottom = request.MarginBottom
                                  ' Generate PDF
                                  Dim pdf = localRenderer.RenderHtmlAsPdf(request.HtmlContent)
                                  ' Apply compression if requested
                                  If request.CompressImages Then
                                      pdf.CompressImages(request.CompressionQuality)
                                  End If
                                  Return pdf
                              End Function)
    End Function
End Class

Public Class BatchPdfRequest
    Public Property Id As String
    Public Property FileName As String
    Public Property HtmlContent As String
    Public Property PaperSize As IronPdf.Rendering.PdfPaperSize = IronPdf.Rendering.PdfPaperSize.A4
    Public Property MarginTop As Integer = 25
    Public Property MarginBottom As Integer = 25
    Public Property CompressImages As Boolean = True
    Public Property CompressionQuality As Integer = 80
End Class

Public Class BatchProcessingResult
    Public Property StartTime As DateTime
    Public Property EndTime As DateTime
    Public Property TotalProcessingTime As Long
    Public Property TotalRequests As Integer
    Public Property SuccessCount As Integer
    Public Property ErrorCount As Integer
    Public Property AverageGenerationTime As Double
    Public Property TotalPages As Integer
    Public Property TotalSizeBytes As Long
    Public Property SuccessfulPdfs As List(Of GeneratedPdf)
    Public Property Errors As List(Of ProcessingError)
End Class

Public Class GeneratedPdf
    Public Property Id As String
    Public Property FileName As String
    Public Property Data As Byte()
    Public Property GenerationTime As Long
    Public Property PageCount As Integer
End Class

Public Class ProcessingError
    Public Property RequestId As String
    Public Property FileName As String
    Public Property Error As String
    Public Property StackTrace As String
End Class

Public Class BatchProgressReport
    Public Property ProcessedCount As Integer
    Public Property TotalCount As Integer
    Public Property CurrentFile As String
    Public ReadOnly Property PercentComplete As Double
        Get
            Return CDbl(ProcessedCount) / TotalCount * 100
        End Get
    End Property
End Class
$vbLabelText   $csharpLabel

实际医疗报告示例

这是一个生成符合HIPAA标准的医疗报告的具体实现:

public class MedicalReportGenerator
{
    private readonly ChromePdfRenderer _renderer;
    private readonly ILogger<MedicalReportGenerator> _logger;
    public MedicalReportGenerator(
        ChromePdfRenderer renderer,
        ILogger<MedicalReportGenerator> logger)
    {
        _renderer = renderer;
        _logger = logger;
    }
    public async Task<PdfDocument> GeneratePatientReport(PatientReportModel model)
    {
        var stopwatch = Stopwatch.StartNew();
        // Configure for medical document standards
        _renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
        _renderer.RenderingOptions.MarginTop = 50;
        _renderer.RenderingOptions.MarginBottom = 40;
        // HIPAA-compliant header
        _renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
        {
            Height = 45,
            HtmlFragment = $@"
                <div style='width: 100%; font-size: 10px;'>
                    <div style='float: left;'>
                        <strong>CONFIDENTIAL MEDICAL RECORD</strong><br/>
                        Patient: {model.PatientName} | MRN: {model.MedicalRecordNumber}
                    </div>
                    <div style='float: right; text-align: right;'>
                        Generated: {{date}} {{time}}<br/>
                        Provider: {model.ProviderName}
                    </div>
                </div>"
        };
        // Generate report HTML
        var html = GenerateMedicalReportHtml(model);
        // Create PDF with encryption for HIPAA compliance
        var pdf = _renderer.RenderHtmlAsPdf(html);
        // Apply 256-bit AES encryption
        pdf.SecuritySettings.UserPassword = GenerateSecurePassword();
        pdf.SecuritySettings.OwnerPassword = GenerateOwnerPassword();
        pdf.SecuritySettings.AllowUserCopyPasteContent = false;
        pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
        pdf.SecuritySettings.AllowUserFormData = false;
        pdf.SecuritySettings.AllowUserAnnotations = false;
        // Add audit metadata
        pdf.MetaData.Author = model.ProviderName;
        pdf.MetaData.Title = $"Medical Report - {model.PatientName}";
        pdf.MetaData.Keywords = "medical,confidential,hipaa";
        pdf.MetaData.CustomProperties.Add("ReportType", model.ReportType);
        pdf.MetaData.CustomProperties.Add("GeneratedBy", model.UserId);
        pdf.MetaData.CustomProperties.Add("Timestamp", DateTime.UtcNow.ToString("O"));
        stopwatch.Stop();
        _logger.LogInformation($"Medical report generated in {stopwatch.ElapsedMilliseconds}ms for patient {model.MedicalRecordNumber}");
        return pdf;
    }
    private string GenerateMedicalReportHtml(PatientReportModel model)
    {
        // Generate comprehensive medical report HTML
        // This would typically use a Razor view in production
        return $@"
            <!DOCTYPE html>
            <html>
            <head>
                <style>
                    body {{ font-family: 'Segoe UI', Arial, sans-serif; margin: 0; padding: 20px; }}
                    .header {{ background: #f0f4f8; padding: 20px; margin-bottom: 30px; }}
                    .patient-info {{ display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 30px; }}
                    .section {{ margin-bottom: 30px; }}
                    .section h2 {{ color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }}
                    .vital-signs {{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }}
                    .vital-box {{ background: #ecf0f1; padding: 15px; border-radius: 5px; }}
                    .medication-table {{ width: 100%; border-collapse: collapse; }}
                    .medication-table th, .medication-table td {{ border: 1px solid #ddd; padding: 10px; text-align: left; }}
                    .medication-table th {{ background: #3498db; color: white; }}
                    .alert {{ background: #e74c3c; color: white; padding: 10px; border-radius: 5px; margin-bottom: 20px; }}
                </style>
            </head>
            <body>
                <div class='header'>
                    <h1>Patient Medical Report</h1>
                    <p>Report Date: {DateTime.Now:MMMM dd, yyyy}</p>
                </div>
                {(model.HasAllergies ? "<div class='alert'>⚠ PATIENT HAS KNOWN ALLERGIES - SEE ALLERGY SECTION</div>" : "")}
                <div class='patient-info'>
                    <div>
                        <strong>Patient Name:</strong> {model.PatientName}<br/>
                        <strong>Date of Birth:</strong> {model.DateOfBirth:MM/dd/yyyy}<br/>
                        <strong>Age:</strong> {model.Age} years<br/>
                        <strong>Gender:</strong> {model.Gender}
                    </div>
                    <div>
                        <strong>MRN:</strong> {model.MedicalRecordNumber}<br/>
                        <strong>Admission Date:</strong> {model.AdmissionDate:MM/dd/yyyy}<br/>
                        <strong>Provider:</strong> {model.ProviderName}<br/>
                        <strong>Department:</strong> {model.Department}
                    </div>
                </div>
                <div class='section'>
                    <h2>Vital Signs</h2>
                    <div class='vital-signs'>
                        <div class='vital-box'>
                            <strong>Blood Pressure</strong><br/>
                            {model.BloodPressure}
                        </div>
                        <div class='vital-box'>
                            <strong>Heart Rate</strong><br/>
                            {model.HeartRate} bpm
                        </div>
                        <div class='vital-box'>
                            <strong>Temperature</strong><br/>
                            {model.Temperature}°F
                        </div>
                        <div class='vital-box'>
                            <strong>Respiratory Rate</strong><br/>
                            {model.RespiratoryRate} /min
                        </div>
                        <div class='vital-box'>
                            <strong>O2 Saturation</strong><br/>
                            {model.OxygenSaturation}%
                        </div>
                        <div class='vital-box'>
                            <strong>Weight</strong><br/>
                            {model.Weight} lbs
                        </div>
                    </div>
                </div>
                <div class='section'>
                    <h2>Current Medications</h2>
                    <table class='medication-table'>
                        <thead>
                            <tr>
                                <th>Medication</th>
                                <th>Dosage</th>
                                <th>Frequency</th>
                                <th>Route</th>
                                <th>Start Date</th>
                            </tr>
                        </thead>
                        <tbody>
                            {string.Join("", model.Medications.Select(m => $@"
                                <tr>
                                    <td>{m.Name}</td>
                                    <td>{m.Dosage}</td>
                                    <td>{m.Frequency}</td>
                                    <td>{m.Route}</td>
                                    <td>{m.StartDate:MM/dd/yyyy}</td>
                                </tr>
                            "))}
                        </tbody>
                    </table>
                </div>
                <div class='section'>
                    <h2>Clinical Notes</h2>
                    <p>{model.ClinicalNotes}</p>
                </div>
                <div class='section'>
                    <h2>Treatment Plan</h2>
                    <p>{model.TreatmentPlan}</p>
                </div>
            </body>
            </html>";
    }
    private string GenerateSecurePassword()
    {
        // Generate cryptographically secure password
        using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
        var bytes = new byte[32];
        rng.GetBytes(bytes);
        return Convert.ToBase64String(bytes);
    }
    private string GenerateOwnerPassword()
    {
        // In production, retrieve from secure configuration
        return "SecureOwnerPassword123!";
    }
}
public class PatientReportModel
{
    public string PatientName { get; set; }
    public string MedicalRecordNumber { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
    public DateTime AdmissionDate { get; set; }
    public string ProviderName { get; set; }
    public string Department { get; set; }
    public string ReportType { get; set; }
    public string UserId { get; set; }
    // Vital Signs
    public string BloodPressure { get; set; }
    public int HeartRate { get; set; }
    public decimal Temperature { get; set; }
    public int RespiratoryRate { get; set; }
    public int OxygenSaturation { get; set; }
    public decimal Weight { get; set; }
    // Medical Information
    public bool HasAllergies { get; set; }
    public List<Medication> Medications { get; set; }
    public string ClinicalNotes { get; set; }
    public string TreatmentPlan { get; set; }
}
public class Medication
{
    public string Name { get; set; }
    public string Dosage { get; set; }
    public string Frequency { get; set; }
    public string Route { get; set; }
    public DateTime StartDate { get; set; }
}
public class MedicalReportGenerator
{
    private readonly ChromePdfRenderer _renderer;
    private readonly ILogger<MedicalReportGenerator> _logger;
    public MedicalReportGenerator(
        ChromePdfRenderer renderer,
        ILogger<MedicalReportGenerator> logger)
    {
        _renderer = renderer;
        _logger = logger;
    }
    public async Task<PdfDocument> GeneratePatientReport(PatientReportModel model)
    {
        var stopwatch = Stopwatch.StartNew();
        // Configure for medical document standards
        _renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
        _renderer.RenderingOptions.MarginTop = 50;
        _renderer.RenderingOptions.MarginBottom = 40;
        // HIPAA-compliant header
        _renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
        {
            Height = 45,
            HtmlFragment = $@"
                <div style='width: 100%; font-size: 10px;'>
                    <div style='float: left;'>
                        <strong>CONFIDENTIAL MEDICAL RECORD</strong><br/>
                        Patient: {model.PatientName} | MRN: {model.MedicalRecordNumber}
                    </div>
                    <div style='float: right; text-align: right;'>
                        Generated: {{date}} {{time}}<br/>
                        Provider: {model.ProviderName}
                    </div>
                </div>"
        };
        // Generate report HTML
        var html = GenerateMedicalReportHtml(model);
        // Create PDF with encryption for HIPAA compliance
        var pdf = _renderer.RenderHtmlAsPdf(html);
        // Apply 256-bit AES encryption
        pdf.SecuritySettings.UserPassword = GenerateSecurePassword();
        pdf.SecuritySettings.OwnerPassword = GenerateOwnerPassword();
        pdf.SecuritySettings.AllowUserCopyPasteContent = false;
        pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
        pdf.SecuritySettings.AllowUserFormData = false;
        pdf.SecuritySettings.AllowUserAnnotations = false;
        // Add audit metadata
        pdf.MetaData.Author = model.ProviderName;
        pdf.MetaData.Title = $"Medical Report - {model.PatientName}";
        pdf.MetaData.Keywords = "medical,confidential,hipaa";
        pdf.MetaData.CustomProperties.Add("ReportType", model.ReportType);
        pdf.MetaData.CustomProperties.Add("GeneratedBy", model.UserId);
        pdf.MetaData.CustomProperties.Add("Timestamp", DateTime.UtcNow.ToString("O"));
        stopwatch.Stop();
        _logger.LogInformation($"Medical report generated in {stopwatch.ElapsedMilliseconds}ms for patient {model.MedicalRecordNumber}");
        return pdf;
    }
    private string GenerateMedicalReportHtml(PatientReportModel model)
    {
        // Generate comprehensive medical report HTML
        // This would typically use a Razor view in production
        return $@"
            <!DOCTYPE html>
            <html>
            <head>
                <style>
                    body {{ font-family: 'Segoe UI', Arial, sans-serif; margin: 0; padding: 20px; }}
                    .header {{ background: #f0f4f8; padding: 20px; margin-bottom: 30px; }}
                    .patient-info {{ display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 30px; }}
                    .section {{ margin-bottom: 30px; }}
                    .section h2 {{ color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }}
                    .vital-signs {{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }}
                    .vital-box {{ background: #ecf0f1; padding: 15px; border-radius: 5px; }}
                    .medication-table {{ width: 100%; border-collapse: collapse; }}
                    .medication-table th, .medication-table td {{ border: 1px solid #ddd; padding: 10px; text-align: left; }}
                    .medication-table th {{ background: #3498db; color: white; }}
                    .alert {{ background: #e74c3c; color: white; padding: 10px; border-radius: 5px; margin-bottom: 20px; }}
                </style>
            </head>
            <body>
                <div class='header'>
                    <h1>Patient Medical Report</h1>
                    <p>Report Date: {DateTime.Now:MMMM dd, yyyy}</p>
                </div>
                {(model.HasAllergies ? "<div class='alert'>⚠ PATIENT HAS KNOWN ALLERGIES - SEE ALLERGY SECTION</div>" : "")}
                <div class='patient-info'>
                    <div>
                        <strong>Patient Name:</strong> {model.PatientName}<br/>
                        <strong>Date of Birth:</strong> {model.DateOfBirth:MM/dd/yyyy}<br/>
                        <strong>Age:</strong> {model.Age} years<br/>
                        <strong>Gender:</strong> {model.Gender}
                    </div>
                    <div>
                        <strong>MRN:</strong> {model.MedicalRecordNumber}<br/>
                        <strong>Admission Date:</strong> {model.AdmissionDate:MM/dd/yyyy}<br/>
                        <strong>Provider:</strong> {model.ProviderName}<br/>
                        <strong>Department:</strong> {model.Department}
                    </div>
                </div>
                <div class='section'>
                    <h2>Vital Signs</h2>
                    <div class='vital-signs'>
                        <div class='vital-box'>
                            <strong>Blood Pressure</strong><br/>
                            {model.BloodPressure}
                        </div>
                        <div class='vital-box'>
                            <strong>Heart Rate</strong><br/>
                            {model.HeartRate} bpm
                        </div>
                        <div class='vital-box'>
                            <strong>Temperature</strong><br/>
                            {model.Temperature}°F
                        </div>
                        <div class='vital-box'>
                            <strong>Respiratory Rate</strong><br/>
                            {model.RespiratoryRate} /min
                        </div>
                        <div class='vital-box'>
                            <strong>O2 Saturation</strong><br/>
                            {model.OxygenSaturation}%
                        </div>
                        <div class='vital-box'>
                            <strong>Weight</strong><br/>
                            {model.Weight} lbs
                        </div>
                    </div>
                </div>
                <div class='section'>
                    <h2>Current Medications</h2>
                    <table class='medication-table'>
                        <thead>
                            <tr>
                                <th>Medication</th>
                                <th>Dosage</th>
                                <th>Frequency</th>
                                <th>Route</th>
                                <th>Start Date</th>
                            </tr>
                        </thead>
                        <tbody>
                            {string.Join("", model.Medications.Select(m => $@"
                                <tr>
                                    <td>{m.Name}</td>
                                    <td>{m.Dosage}</td>
                                    <td>{m.Frequency}</td>
                                    <td>{m.Route}</td>
                                    <td>{m.StartDate:MM/dd/yyyy}</td>
                                </tr>
                            "))}
                        </tbody>
                    </table>
                </div>
                <div class='section'>
                    <h2>Clinical Notes</h2>
                    <p>{model.ClinicalNotes}</p>
                </div>
                <div class='section'>
                    <h2>Treatment Plan</h2>
                    <p>{model.TreatmentPlan}</p>
                </div>
            </body>
            </html>";
    }
    private string GenerateSecurePassword()
    {
        // Generate cryptographically secure password
        using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
        var bytes = new byte[32];
        rng.GetBytes(bytes);
        return Convert.ToBase64String(bytes);
    }
    private string GenerateOwnerPassword()
    {
        // In production, retrieve from secure configuration
        return "SecureOwnerPassword123!";
    }
}
public class PatientReportModel
{
    public string PatientName { get; set; }
    public string MedicalRecordNumber { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
    public DateTime AdmissionDate { get; set; }
    public string ProviderName { get; set; }
    public string Department { get; set; }
    public string ReportType { get; set; }
    public string UserId { get; set; }
    // Vital Signs
    public string BloodPressure { get; set; }
    public int HeartRate { get; set; }
    public decimal Temperature { get; set; }
    public int RespiratoryRate { get; set; }
    public int OxygenSaturation { get; set; }
    public decimal Weight { get; set; }
    // Medical Information
    public bool HasAllergies { get; set; }
    public List<Medication> Medications { get; set; }
    public string ClinicalNotes { get; set; }
    public string TreatmentPlan { get; set; }
}
public class Medication
{
    public string Name { get; set; }
    public string Dosage { get; set; }
    public string Frequency { get; set; }
    public string Route { get; set; }
    public DateTime StartDate { get; set; }
}
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Threading.Tasks
Imports IronPdf
Imports IronPdf.Rendering
Imports Microsoft.Extensions.Logging

Public Class MedicalReportGenerator
    Private ReadOnly _renderer As ChromePdfRenderer
    Private ReadOnly _logger As ILogger(Of MedicalReportGenerator)

    Public Sub New(renderer As ChromePdfRenderer, logger As ILogger(Of MedicalReportGenerator))
        _renderer = renderer
        _logger = logger
    End Sub

    Public Async Function GeneratePatientReport(model As PatientReportModel) As Task(Of PdfDocument)
        Dim stopwatch = Stopwatch.StartNew()
        ' Configure for medical document standards
        _renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
        _renderer.RenderingOptions.MarginTop = 50
        _renderer.RenderingOptions.MarginBottom = 40
        ' HIPAA-compliant header
        _renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
            .Height = 45,
            .HtmlFragment = $"
                <div style='width: 100%; font-size: 10px;'>
                    <div style='float: left;'>
                        <strong>CONFIDENTIAL MEDICAL RECORD</strong><br/>
                        Patient: {model.PatientName} | MRN: {model.MedicalRecordNumber}
                    </div>
                    <div style='float: right; text-align: right;'>
                        Generated: {{date}} {{time}}<br/>
                        Provider: {model.ProviderName}
                    </div>
                </div>"
        }
        ' Generate report HTML
        Dim html = GenerateMedicalReportHtml(model)
        ' Create PDF with encryption for HIPAA compliance
        Dim pdf = _renderer.RenderHtmlAsPdf(html)
        ' Apply 256-bit AES encryption
        pdf.SecuritySettings.UserPassword = GenerateSecurePassword()
        pdf.SecuritySettings.OwnerPassword = GenerateOwnerPassword()
        pdf.SecuritySettings.AllowUserCopyPasteContent = False
        pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint
        pdf.SecuritySettings.AllowUserFormData = False
        pdf.SecuritySettings.AllowUserAnnotations = False
        ' Add audit metadata
        pdf.MetaData.Author = model.ProviderName
        pdf.MetaData.Title = $"Medical Report - {model.PatientName}"
        pdf.MetaData.Keywords = "medical,confidential,hipaa"
        pdf.MetaData.CustomProperties.Add("ReportType", model.ReportType)
        pdf.MetaData.CustomProperties.Add("GeneratedBy", model.UserId)
        pdf.MetaData.CustomProperties.Add("Timestamp", DateTime.UtcNow.ToString("O"))
        stopwatch.Stop()
        _logger.LogInformation($"Medical report generated in {stopwatch.ElapsedMilliseconds}ms for patient {model.MedicalRecordNumber}")
        Return pdf
    End Function

    Private Function GenerateMedicalReportHtml(model As PatientReportModel) As String
        ' Generate comprehensive medical report HTML
        ' This would typically use a Razor view in production
        Return $"
            <!DOCTYPE html>
            <html>
            <head>
                <style>
                    body {{ font-family: 'Segoe UI', Arial, sans-serif; margin: 0; padding: 20px; }}
                    .header {{ background: #f0f4f8; padding: 20px; margin-bottom: 30px; }}
                    .patient-info {{ display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 30px; }}
                    .section {{ margin-bottom: 30px; }}
                    .section h2 {{ color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }}
                    .vital-signs {{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; }}
                    .vital-box {{ background: #ecf0f1; padding: 15px; border-radius: 5px; }}
                    .medication-table {{ width: 100%; border-collapse: collapse; }}
                    .medication-table th, .medication-table td {{ border: 1px solid #ddd; padding: 10px; text-align: left; }}
                    .medication-table th {{ background: #3498db; color: white; }}
                    .alert {{ background: #e74c3c; color: white; padding: 10px; border-radius: 5px; margin-bottom: 20px; }}
                </style>
            </head>
            <body>
                <div class='header'>
                    <h1>Patient Medical Report</h1>
                    <p>Report Date: {DateTime.Now:MMMM dd, yyyy}</p>
                </div>
                {(If(model.HasAllergies, "<div class='alert'>⚠ PATIENT HAS KNOWN ALLERGIES - SEE ALLERGY SECTION</div>", ""))}
                <div class='patient-info'>
                    <div>
                        <strong>Patient Name:</strong> {model.PatientName}<br/>
                        <strong>Date of Birth:</strong> {model.DateOfBirth:MM/dd/yyyy}<br/>
                        <strong>Age:</strong> {model.Age} years<br/>
                        <strong>Gender:</strong> {model.Gender}
                    </div>
                    <div>
                        <strong>MRN:</strong> {model.MedicalRecordNumber}<br/>
                        <strong>Admission Date:</strong> {model.AdmissionDate:MM/dd/yyyy}<br/>
                        <strong>Provider:</strong> {model.ProviderName}<br/>
                        <strong>Department:</strong> {model.Department}
                    </div>
                </div>
                <div class='section'>
                    <h2>Vital Signs</h2>
                    <div class='vital-signs'>
                        <div class='vital-box'>
                            <strong>Blood Pressure</strong><br/>
                            {model.BloodPressure}
                        </div>
                        <div class='vital-box'>
                            <strong>Heart Rate</strong><br/>
                            {model.HeartRate} bpm
                        </div>
                        <div class='vital-box'>
                            <strong>Temperature</strong><br/>
                            {model.Temperature}°F
                        </div>
                        <div class='vital-box'>
                            <strong>Respiratory Rate</strong><br/>
                            {model.RespiratoryRate} /min
                        </div>
                        <div class='vital-box'>
                            <strong>O2 Saturation</strong><br/>
                            {model.OxygenSaturation}%
                        </div>
                        <div class='vital-box'>
                            <strong>Weight</strong><br/>
                            {model.Weight} lbs
                        </div>
                    </div>
                </div>
                <div class='section'>
                    <h2>Current Medications</h2>
                    <table class='medication-table'>
                        <thead>
                            <tr>
                                <th>Medication</th>
                                <th>Dosage</th>
                                <th>Frequency</th>
                                <th>Route</th>
                                <th>Start Date</th>
                            </tr>
                        </thead>
                        <tbody>
                            {String.Join("", model.Medications.Select(Function(m) $"
                                <tr>
                                    <td>{m.Name}</td>
                                    <td>{m.Dosage}</td>
                                    <td>{m.Frequency}</td>
                                    <td>{m.Route}</td>
                                    <td>{m.StartDate:MM/dd/yyyy}</td>
                                </tr>
                            "))}
                        </tbody>
                    </table>
                </div>
                <div class='section'>
                    <h2>Clinical Notes</h2>
                    <p>{model.ClinicalNotes}</p>
                </div>
                <div class='section'>
                    <h2>Treatment Plan</h2>
                    <p>{model.TreatmentPlan}</p>
                </div>
            </body>
            </html>"
    End Function

    Private Function GenerateSecurePassword() As String
        ' Generate cryptographically secure password
        Using rng = System.Security.Cryptography.RandomNumberGenerator.Create()
            Dim bytes = New Byte(31) {}
            rng.GetBytes(bytes)
            Return Convert.ToBase64String(bytes)
        End Using
    End Function

    Private Function GenerateOwnerPassword() As String
        ' In production, retrieve from secure configuration
        Return "SecureOwnerPassword123!"
    End Function
End Class

Public Class PatientReportModel
    Public Property PatientName As String
    Public Property MedicalRecordNumber As String
    Public Property DateOfBirth As DateTime
    Public Property Age As Integer
    Public Property Gender As String
    Public Property AdmissionDate As DateTime
    Public Property ProviderName As String
    Public Property Department As String
    Public Property ReportType As String
    Public Property UserId As String
    ' Vital Signs
    Public Property BloodPressure As String
    Public Property HeartRate As Integer
    Public Property Temperature As Decimal
    Public Property RespiratoryRate As Integer
    Public Property OxygenSaturation As Integer
    Public Property Weight As Decimal
    ' Medical Information
    Public Property HasAllergies As Boolean
    Public Property Medications As List(Of Medication)
    Public Property ClinicalNotes As String
    Public Property TreatmentPlan As String
End Class

Public Class Medication
    Public Property Name As String
    Public Property Dosage As String
    Public Property Frequency As String
    Public Property Route As String
    Public Property StartDate As DateTime
End Class
$vbLabelText   $csharpLabel

安全考虑

在生产环境中生成PDF或处理敏感信息时,安全性至关重要。 IronPDF提供了多种安全功能:

应用安全设置

using System.Text.RegularExpressions;
namespace PdfGeneratorApp.Utilities
{
    public static class PdfSecurityHelper
    {
        public static void ApplySecuritySettings(PdfDocument pdf, SecurityLevel level)
        {
            switch (level)
            {
                case SecurityLevel.Low:
                    // Basic protection
                    pdf.SecuritySettings.AllowUserCopyPasteContent = true;
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
                    break;
                case SecurityLevel.Medium:
                    // Restricted copying
                    pdf.SecuritySettings.UserPassword = GeneratePassword(8);
                    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.PrintLowQuality;
                    break;
                case SecurityLevel.High:
                    // Maximum security
                    pdf.SecuritySettings.UserPassword = GeneratePassword(16);
                    pdf.SecuritySettings.OwnerPassword = GeneratePassword(16);
                    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
                    pdf.SecuritySettings.AllowUserAnnotations = false;
                    pdf.SecuritySettings.AllowUserFormData = false;
                    break;
            }
        }
    public enum SecurityLevel
    {
        Low,
        Medium,
        High
    }
}
using System.Text.RegularExpressions;
namespace PdfGeneratorApp.Utilities
{
    public static class PdfSecurityHelper
    {
        public static void ApplySecuritySettings(PdfDocument pdf, SecurityLevel level)
        {
            switch (level)
            {
                case SecurityLevel.Low:
                    // Basic protection
                    pdf.SecuritySettings.AllowUserCopyPasteContent = true;
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
                    break;
                case SecurityLevel.Medium:
                    // Restricted copying
                    pdf.SecuritySettings.UserPassword = GeneratePassword(8);
                    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.PrintLowQuality;
                    break;
                case SecurityLevel.High:
                    // Maximum security
                    pdf.SecuritySettings.UserPassword = GeneratePassword(16);
                    pdf.SecuritySettings.OwnerPassword = GeneratePassword(16);
                    pdf.SecuritySettings.AllowUserCopyPasteContent = false;
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint;
                    pdf.SecuritySettings.AllowUserAnnotations = false;
                    pdf.SecuritySettings.AllowUserFormData = false;
                    break;
            }
        }
    public enum SecurityLevel
    {
        Low,
        Medium,
        High
    }
}
Imports System.Text.RegularExpressions

Namespace PdfGeneratorApp.Utilities

    Public Module PdfSecurityHelper

        Public Sub ApplySecuritySettings(pdf As PdfDocument, level As SecurityLevel)
            Select Case level
                Case SecurityLevel.Low
                    ' Basic protection
                    pdf.SecuritySettings.AllowUserCopyPasteContent = True
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights
                Case SecurityLevel.Medium
                    ' Restricted copying
                    pdf.SecuritySettings.UserPassword = GeneratePassword(8)
                    pdf.SecuritySettings.AllowUserCopyPasteContent = False
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.PrintLowQuality
                Case SecurityLevel.High
                    ' Maximum security
                    pdf.SecuritySettings.UserPassword = GeneratePassword(16)
                    pdf.SecuritySettings.OwnerPassword = GeneratePassword(16)
                    pdf.SecuritySettings.AllowUserCopyPasteContent = False
                    pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.NoPrint
                    pdf.SecuritySettings.AllowUserAnnotations = False
                    pdf.SecuritySettings.AllowUserFormData = False
            End Select
        End Sub

        Public Enum SecurityLevel
            Low
            Medium
            High
        End Enum

    End Module

End Namespace
$vbLabelText   $csharpLabel

在上面的辅助类中,我们使用 SecurityLevel 枚举来设置 PDF 的不同安全选项。 例如,低级 SecurityLevel 应用基本保护,但仍然允许 FullPrintRights 通过将属性 AllowUserCopyPasteContent 设置为 true 从 PDF 复制和粘贴。 这些设置通过调整IronPDF的PDF类属性来启用。 有关安全属性和选项的完整列表,请参阅操作指南

错误处理和故障排除

在ASP.NET Core中生成PDF的常见问题及其解决方案已在开发者社区中进行了广泛讨论。 以下是最常见挑战的经过验证的解决方案:

内存管理

有关处理IronPDF中的内存泄漏的详细指南,请遵循以下模式:

public class PdfMemoryManager : IDisposable
{
    private readonly List<PdfDocument> _openDocuments = new();
    private readonly ILogger<PdfMemoryManager> _logger;
    private bool _disposed;
    public PdfMemoryManager(ILogger<PdfMemoryManager> logger)
    {
        _logger = logger;
    }
    public PdfDocument CreateDocument(ChromePdfRenderer renderer, string html)
    {
        try
        {
            var pdf = renderer.RenderHtmlAsPdf(html);
            _openDocuments.Add(pdf);
            return pdf;
        }
        catch (OutOfMemory例外情况 ex)
        {
            _logger.LogError(ex, "Out of memory while generating PDF");
            // Force garbage collection
            CleanupMemory();
            // Retry with reduced quality
            renderer.RenderingOptions.JpegQuality = 50;
            var pdf = renderer.RenderHtmlAsPdf(html);
            _openDocuments.Add(pdf);
            return pdf;
        }
    }
    private void CleanupMemory()
    {
        // Dispose all open documents
        foreach (var doc in _openDocuments)
        {
            doc?.Dispose();
        }
        _openDocuments.Clear();
        // Force garbage collection
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        _logger.LogInformation("Memory cleanup performed");
    }
    public void Dispose()
    {
        if (!_disposed)
        {
            CleanupMemory();
            _disposed = true;
        }
    }
}
public class PdfMemoryManager : IDisposable
{
    private readonly List<PdfDocument> _openDocuments = new();
    private readonly ILogger<PdfMemoryManager> _logger;
    private bool _disposed;
    public PdfMemoryManager(ILogger<PdfMemoryManager> logger)
    {
        _logger = logger;
    }
    public PdfDocument CreateDocument(ChromePdfRenderer renderer, string html)
    {
        try
        {
            var pdf = renderer.RenderHtmlAsPdf(html);
            _openDocuments.Add(pdf);
            return pdf;
        }
        catch (OutOfMemory例外情况 ex)
        {
            _logger.LogError(ex, "Out of memory while generating PDF");
            // Force garbage collection
            CleanupMemory();
            // Retry with reduced quality
            renderer.RenderingOptions.JpegQuality = 50;
            var pdf = renderer.RenderHtmlAsPdf(html);
            _openDocuments.Add(pdf);
            return pdf;
        }
    }
    private void CleanupMemory()
    {
        // Dispose all open documents
        foreach (var doc in _openDocuments)
        {
            doc?.Dispose();
        }
        _openDocuments.Clear();
        // Force garbage collection
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        _logger.LogInformation("Memory cleanup performed");
    }
    public void Dispose()
    {
        if (!_disposed)
        {
            CleanupMemory();
            _disposed = true;
        }
    }
}
Imports System
Imports System.Collections.Generic

Public Class PdfMemoryManager
    Implements IDisposable

    Private ReadOnly _openDocuments As New List(Of PdfDocument)()
    Private ReadOnly _logger As ILogger(Of PdfMemoryManager)
    Private _disposed As Boolean

    Public Sub New(logger As ILogger(Of PdfMemoryManager))
        _logger = logger
    End Sub

    Public Function CreateDocument(renderer As ChromePdfRenderer, html As String) As PdfDocument
        Try
            Dim pdf = renderer.RenderHtmlAsPdf(html)
            _openDocuments.Add(pdf)
            Return pdf
        Catch ex As OutOfMemoryException
            _logger.LogError(ex, "Out of memory while generating PDF")
            ' Force garbage collection
            CleanupMemory()
            ' Retry with reduced quality
            renderer.RenderingOptions.JpegQuality = 50
            Dim pdf = renderer.RenderHtmlAsPdf(html)
            _openDocuments.Add(pdf)
            Return pdf
        End Try
    End Function

    Private Sub CleanupMemory()
        ' Dispose all open documents
        For Each doc In _openDocuments
            doc?.Dispose()
        Next
        _openDocuments.Clear()
        ' Force garbage collection
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()
        _logger.LogInformation("Memory cleanup performed")
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        If Not _disposed Then
            CleanupMemory()
            _disposed = True
        End If
    End Sub
End Class
$vbLabelText   $csharpLabel

字体渲染问题

public class FontTroubleshooter
{
    public static void EnsureFontsAvailable(ChromePdfRenderer renderer)
    {
        // Embed fonts in the PDF
        renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
        // Use web-safe fonts as fallback
        var fontFallback = @"
            <style>
                body {
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                }
                @font-face {
                    font-family: 'CustomFont';
                    src: url('data:font/woff2;base64,YOUR_BASE64_FONT_HERE') format('woff2');
                }
            </style>";
        // Add to HTML head
        renderer.RenderingOptions.CustomCssUrl = "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap";
    }
}
public class FontTroubleshooter
{
    public static void EnsureFontsAvailable(ChromePdfRenderer renderer)
    {
        // Embed fonts in the PDF
        renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
        // Use web-safe fonts as fallback
        var fontFallback = @"
            <style>
                body {
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                }
                @font-face {
                    font-family: 'CustomFont';
                    src: url('data:font/woff2;base64,YOUR_BASE64_FONT_HERE') format('woff2');
                }
            </style>";
        // Add to HTML head
        renderer.RenderingOptions.CustomCssUrl = "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap";
    }
}
Public Class FontTroubleshooter
    Public Shared Sub EnsureFontsAvailable(renderer As ChromePdfRenderer)
        ' Embed fonts in the PDF
        renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
        ' Use web-safe fonts as fallback
        Dim fontFallback As String = "
            <style>
                body {
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                }
                @font-face {
                    font-family: 'CustomFont';
                    src: url('data:font/woff2;base64,YOUR_BASE64_FONT_HERE') format('woff2');
                }
            </style>"
        ' Add to HTML head
        renderer.RenderingOptions.CustomCssUrl = "https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap"
    End Sub
End Class
$vbLabelText   $csharpLabel

常见异常和解决方案

例外情况

原因

解决方案

IronPdf.例外情况s.IronPdfNative例外情况

Chrome 引擎初始化失败

确保已安装 Visual C++ Redistributables

System.UnauthorizedAccess例外情况

权限不足

授予临时文件夹的写入权限

System.Timeout例外情况

JavaScript 运行时间太长

增加 RenderDelay 或禁用 JavaScript

System.OutOfMemory例外情况

大型 PDF 或批量处理

实施分页或降低图像质量

IronPdf.例外情况s.IronPdfLicensing例外情况

许可证无效或过期

验证配置中的许可证密钥

调试技巧

使用IronPDF,您可以轻松调试并记录应用程序运行的所有进程,以搜索并验证任何输入和输出。 要启用日志记录,请将 `EnableDebugging` 设置为 true,并通过为 LogFilePath 属性赋值来指定日志的文件路径。 这是一个快速代码片段,展示如何做到这一点。

public class PdfDebugger
{
    private readonly ILogger<PdfDebugger> _logger;
    public PdfDebugger(ILogger<PdfDebugger> logger)
    {
        _logger = logger;
    }
    public void EnableDebugging(ChromePdfRenderer renderer)
    {
        // Enable detailed logging
        IronPdf.Logging.Logger.EnableDebugging = true;
        IronPdf.Logging.Logger.LogFilePath = "IronPdf.log";
        IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;
        // Log rendering settings
        _logger.LogDebug($"Paper Size: {renderer.RenderingOptions.PaperSize}");
        _logger.LogDebug($"Margins: T{renderer.RenderingOptions.MarginTop} " +
                         $"B{renderer.RenderingOptions.MarginBottom} " +
                         $"L{renderer.RenderingOptions.MarginLeft} " +
                         $"R{renderer.RenderingOptions.MarginRight}");
        _logger.LogDebug($"JavaScript Enabled: {renderer.RenderingOptions.EnableJavaScript}");
        _logger.LogDebug($"Render Delay: {renderer.RenderingOptions.RenderDelay}ms");
    }
    public void SaveDebugHtml(string html, string fileName)
    {
        // Save HTML for inspection
        var debugPath = Path.Combine("debug", $"{fileName}_{DateTime.Now:yyyyMMdd_HHmmss}.html");
        Directory.CreateDirectory("debug");
        File.WriteAllText(debugPath, html);
        _logger.LogDebug($"Debug HTML saved to: {debugPath}");
    }
}
public class PdfDebugger
{
    private readonly ILogger<PdfDebugger> _logger;
    public PdfDebugger(ILogger<PdfDebugger> logger)
    {
        _logger = logger;
    }
    public void EnableDebugging(ChromePdfRenderer renderer)
    {
        // Enable detailed logging
        IronPdf.Logging.Logger.EnableDebugging = true;
        IronPdf.Logging.Logger.LogFilePath = "IronPdf.log";
        IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;
        // Log rendering settings
        _logger.LogDebug($"Paper Size: {renderer.RenderingOptions.PaperSize}");
        _logger.LogDebug($"Margins: T{renderer.RenderingOptions.MarginTop} " +
                         $"B{renderer.RenderingOptions.MarginBottom} " +
                         $"L{renderer.RenderingOptions.MarginLeft} " +
                         $"R{renderer.RenderingOptions.MarginRight}");
        _logger.LogDebug($"JavaScript Enabled: {renderer.RenderingOptions.EnableJavaScript}");
        _logger.LogDebug($"Render Delay: {renderer.RenderingOptions.RenderDelay}ms");
    }
    public void SaveDebugHtml(string html, string fileName)
    {
        // Save HTML for inspection
        var debugPath = Path.Combine("debug", $"{fileName}_{DateTime.Now:yyyyMMdd_HHmmss}.html");
        Directory.CreateDirectory("debug");
        File.WriteAllText(debugPath, html);
        _logger.LogDebug($"Debug HTML saved to: {debugPath}");
    }
}
Imports System
Imports System.IO
Imports Microsoft.Extensions.Logging

Public Class PdfDebugger
    Private ReadOnly _logger As ILogger(Of PdfDebugger)

    Public Sub New(logger As ILogger(Of PdfDebugger))
        _logger = logger
    End Sub

    Public Sub EnableDebugging(renderer As ChromePdfRenderer)
        ' Enable detailed logging
        IronPdf.Logging.Logger.EnableDebugging = True
        IronPdf.Logging.Logger.LogFilePath = "IronPdf.log"
        IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All
        ' Log rendering settings
        _logger.LogDebug($"Paper Size: {renderer.RenderingOptions.PaperSize}")
        _logger.LogDebug($"Margins: T{renderer.RenderingOptions.MarginTop} " &
                         $"B{renderer.RenderingOptions.MarginBottom} " &
                         $"L{renderer.RenderingOptions.MarginLeft} " &
                         $"R{renderer.RenderingOptions.MarginRight}")
        _logger.LogDebug($"JavaScript Enabled: {renderer.RenderingOptions.EnableJavaScript}")
        _logger.LogDebug($"Render Delay: {renderer.RenderingOptions.RenderDelay}ms")
    End Sub

    Public Sub SaveDebugHtml(html As String, fileName As String)
        ' Save HTML for inspection
        Dim debugPath = Path.Combine("debug", $"{fileName}_{DateTime.Now:yyyyMMdd_HHmmss}.html")
        Directory.CreateDirectory("debug")
        File.WriteAllText(debugPath, html)
        _logger.LogDebug($"Debug HTML saved to: {debugPath}")
    End Sub
End Class
$vbLabelText   $csharpLabel

本地部署最佳实践

IIS配置

为了部署到IIS,确保正确配置:


<configuration>
  <system.webServer>

    <applicationPool>
      <processModel enable32BitAppOnWin64="false" />
    </applicationPool>

    <httpRuntime executionTimeout="300" maxRequestLength="51200" />

    <system.web>
      <compilation tempDirectory="~/App_Data/Temp/" />
    </system.web>
  </system.webServer>
</configuration>

<configuration>
  <system.webServer>

    <applicationPool>
      <processModel enable32BitAppOnWin64="false" />
    </applicationPool>

    <httpRuntime executionTimeout="300" maxRequestLength="51200" />

    <system.web>
      <compilation tempDirectory="~/App_Data/Temp/" />
    </system.web>
  </system.webServer>
</configuration>
XML

必要组件

确保在您的部署服务器上安装了以下组件:

  1. .NET运行时 - 版本6.0或更高
  2. Visual C++ Redistributables - 2015-2022(x64)
  3. Windows Server - 建议2012 R2或更高版本

文件系统权限

# Grant IIS_IUSRS write access to temp folder
icacls "C:\inetpub\wwwroot\YourApp\App_Data\Temp" /grant "IIS_IUSRS:(OI)(CI)M" /T
# Grant access to IronPDF cache folder
icacls "C:\Windows\Temp\IronPdf" /grant "IIS_IUSRS:(OI)(CI)M" /T
# Grant IIS_IUSRS write access to temp folder
icacls "C:\inetpub\wwwroot\YourApp\App_Data\Temp" /grant "IIS_IUSRS:(OI)(CI)M" /T
# Grant access to IronPDF cache folder
icacls "C:\Windows\Temp\IronPdf" /grant "IIS_IUSRS:(OI)(CI)M" /T
SHELL

性能调优

// Startup.cs or Program.cs
public void ConfigureServices(IServiceCollection services)
{
    // Configure IronPDF for production
    services.AddSingleton<ChromePdfRenderer>(provider =>
    {
        var renderer = new ChromePdfRenderer();
        // Production optimizations
        renderer.RenderingOptions.RenderDelay = 50; // Minimize delay
        renderer.RenderingOptions.Timeout = 120; // 2 minutes max
        renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
        // Enable caching for static resources
        Installation.ChromeGpuMode = IronPdf.Engines.Chrome.ChromeGpuModes.Disabled;
        Installation.LinuxAndDockerDependenciesAutoConfig = false;
        return renderer;
    });
    // Configure memory cache for generated PDFs
    services.AddMemoryCache(options =>
    {
        options.SizeLimit = 100_000_000; // 100 MB cache
    });
}
// Startup.cs or Program.cs
public void ConfigureServices(IServiceCollection services)
{
    // Configure IronPDF for production
    services.AddSingleton<ChromePdfRenderer>(provider =>
    {
        var renderer = new ChromePdfRenderer();
        // Production optimizations
        renderer.RenderingOptions.RenderDelay = 50; // Minimize delay
        renderer.RenderingOptions.Timeout = 120; // 2 minutes max
        renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
        // Enable caching for static resources
        Installation.ChromeGpuMode = IronPdf.Engines.Chrome.ChromeGpuModes.Disabled;
        Installation.LinuxAndDockerDependenciesAutoConfig = false;
        return renderer;
    });
    // Configure memory cache for generated PDFs
    services.AddMemoryCache(options =>
    {
        options.SizeLimit = 100_000_000; // 100 MB cache
    });
}
Imports IronPdf
Imports Microsoft.Extensions.DependencyInjection

Public Sub ConfigureServices(services As IServiceCollection)
    ' Configure IronPDF for production
    services.AddSingleton(Of ChromePdfRenderer)(Function(provider)
                                                    Dim renderer = New ChromePdfRenderer()
                                                    ' Production optimizations
                                                    renderer.RenderingOptions.RenderDelay = 50 ' Minimize delay
                                                    renderer.RenderingOptions.Timeout = 120 ' 2 minutes max
                                                    renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
                                                    ' Enable caching for static resources
                                                    Installation.ChromeGpuMode = IronPdf.Engines.Chrome.ChromeGpuModes.Disabled
                                                    Installation.LinuxAndDockerDependenciesAutoConfig = False
                                                    Return renderer
                                                End Function)
    ' Configure memory cache for generated PDFs
    services.AddMemoryCache(Sub(options)
                                options.SizeLimit = 100000000 ' 100 MB cache
                            End Sub)
End Sub
$vbLabelText   $csharpLabel

最佳实践总结

  1. 始终处置PdfDocument对象以防止内存泄漏
  2. 重用ChromePdfRenderer实例以更好地提高性能
  3. 实施详细日志记录的适当错误处理
  4. 在PDF生成之前清理所有用户输入
  5. 使用 async/await 模式以更好地扩展性
  6. 为JavaScript渲染配置适当的超时
  7. 压缩图像以减小文件大小
  8. 在内容静态时缓存生成的PDF
  9. 在批处理期间监控内存使用
  10. 在部署之前用生产级数据卷进行测试

今天改变您的ASP.NET应用程序

现在,您对使用IronPDF在ASP.NET Core中生成PDF有了全面了解。 从基本的Razor视图转换到具有性能优化的高级批处理处理,您具备实现与Chrome中所见完全一致的专业PDF生成的能力。

您解锁的关键成就:

  • 像素级完美渲染使用IronPDF的Chrome引擎,消除了在从HTML页面、网页等生成PDF时的格式意外
  • 生产就绪模板使用Razor视图提供熟悉的、可维护的PDF生成
  • 企业级错误处理和内存管理以确保可靠的大规模操作
  • 优化的批量处理通过并行生成,处理成千上万的文档
  • 专业的安全特性利用256位加密保护敏感文档

马上开始创建专业的PDF

立即开始使用 IronPDF。
green arrow pointer

准备好在ASP.NET Core应用程序中实施PDF生成了吗? 今下载IronPDF的免费试用版,体验30天无水印、无限制的专业PDF生成。 凭借全面的文档响应的工程支持和30天的退款保证,您可以自信地建立生产就绪的PDF解决方案。

为您的旅程提供的重要资源

用企业级PDF生成改变您的ASP.NET Core应用程序,按预期工作,今天开始使用IronPDF构建!

常见问题解答

IronPDF在ASP.NET应用程序中的主要用途是什么?

IronPDF 主要用于生成、编辑和提取 PDF 文档中的内容,因此是 ASP.NET 应用程序中创建发票、报告、证书或票据的重要工具。

IronPDF如何确保像素完美的PDF渲染?

IronPDF通过使用高级渲染引擎和企业功能来确保像素完美的渲染,以准确地将HTML、图像或其他文档格式转换为高质量PDF。

IronPDF可以集成到ASP.NET Core应用程序中吗?

是的,IronPDF 可以与 ASP.NET Core 应用程序无缝集成,为开发人员提供一个强大的库来高效地处理各种 PDF 任务。

使用 IronPDF 进行 PDF 生成有哪些好处?

使用IronPDF进行PDF生成的好处包括易用性、高质量渲染、对复杂文档功能的支持以及在应用程序中自动化PDF任务的能力。

IronPDF支持编辑现有的PDF文档吗?

是的,IronPDF支持编辑现有的PDF文档,允许开发人员通过编程方式修改内容、添加注释和更新PDF元数据。

IronPDF适合创建企业级PDF文档吗?

IronPDF非常适合创建企业级PDF文档,因其强大的功能,包括复杂文档结构的支持和加密、数字签名等安全特性。

IronPDF可以将哪些文件格式转换为PDF?

IronPDF可以将各种文件格式转换为PDF,包括HTML、图像和其他文档类型,确保与不同数据源的灵活性和兼容性。

IronPDF如何处理PDF内容提取?

IronPDF通过提供API来提取文本、图像和元数据,从而轻松从PDF文档中检索和操作数据。

IronPDF可以用于自动化PDF文档工作流吗?

是的,IronPDF可以用于自动化PDF文档工作流,简化Web应用程序中PDF文件的批量生成、转换和分发等流程。

IronPDF为开发人员提供什么样的支持?

IronPDF为开发人员提供广泛的支持,包括详细的文档、示例代码和响应迅速的客户服务,以协助集成和故障排除。

IronPDF 是否立即支持 .NET 10?

IronPDF 为 .NET 10 提供预发布支持,并且已经符合预计于 2025 年 11 月发布的 .NET 10 版本。开发人员可以在 .NET 10 项目中使用 IronPDF,无需任何特殊配置。

Curtis Chau
技术作家

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

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我