IRONSOFTWAREHOME

Generate Reports in C# Like Crystal Reports (.NET 10)

Curtis Chau
Curtis Chau
Updated: 2026年6月4日

HTML-to-PDF報表生成 在 C# .NET 中使用IronPDF取代Crystal Reports的專有.rpt設計工具,使用標準的HTML、CSS和Razor模板,讓.NET開發者可以運用他們已有的網頁開發技能來構建資料驅動的業務報告。 這包括了對動態表格的完整支持,JavaScript驅動的圖表,條件格式化,多文件批次處理,以及跨平台部署至任何運行.NET的環境。

精讀:快速入門指南

本教程涵蓋了在C# .NET中用HTML-to-PDF報告生成來取代Crystal Reports,從基本模板到批次處理和排程生成。

  • 適合人士:替換Crystal Reports 或從頭開始構建新報告系統的.NET開發者。
  • 您將構建:三個完整的報告實現(銷售發票、員工名錄、庫存報告),以及Chart.js視覺化圖表、品牌化的頁眉頁腳、目錄生成、子報告合併和并行批次處理。
  • 運行環境: .NET 10,.NET 8 LTS,.NET Framework 4.6.2+ 和 .NET Standard 2.0。無需Windows專用COM依賴。
  • 何時使用此方法: 當Crystal Reports缺乏.NET Core支持、Windows鎖定,或複雜的授權成為瓶頸時。
  • 技術上為何重要: HTML/CSS在各平台上渲染結果一致,與CI/CD整合,並執行圖表的JavaScript,而不需要專有的設計器或按文件計費。

要跟著程式碼範例進行,通過NuGet (Install-Package IronPdf) 安裝IronPdf。 只需幾行程式碼即可生成您的第一份報告:

  1. 1Install IronPDF with NuGet Package Manager

    PM > Install-Package IronPdf

  2. 2複製並運行這段程式碼片段。

    // Install-Package IronPdf
    var pdf = new IronPdf.ChromePdfRenderer()
        .RenderHtmlAsPdf("<h1>Sales Report</h1><table><tr><td>Q1</td><td>$50,000</td></tr></table>")
        .SaveAs("sales-report.pdf");
    C#
  3. 3部署以在您的實時環境中測試

    今天就開始在您的專案中使用IronPDF,透過免費試用
    arrow pointer

在您購買或註冊30天試用版IronPDF後,在應用程式的開始處新增您的授權金鑰。

IronPdf.License.LicenseKey = "KEY";

Start using IronPDF in your project today with a free trial.

第一步:
arrow pointer
NuGet使用NuGet安裝

PM > Install-Package IronPdf

Install IronPDF by running the command above in the NuGet Package Manager Console, or search for the package in the NuGet Package Manager.
目錄

C# Report Generator: HTML Templates to PDF

HTML-to-PDF的生成依賴於線性架構管道。應用程式使用標準資料模型而不是專有文件格式來填充Razor視圖或HTML模板。 結果的HTML字串然後傳遞給渲染引擎如IronPdf,該引擎將視覺輸出捕獲為PDF文件。 這種方法使報告設計與託管環境解耦,允許完全相同的程式碼在任何支持.NET的平台上運行。

此工作流程與標準網頁開發相似。 前端開發人員使用CSS建立布局,並立即在任何瀏覽器中預覽。 後端開發人員然後使用C#綁定資料。 這種分工允許團隊為报告使用他們現有的版本控制、程式碼審查和持續部署過程,就像他們處理應用程式的其他部分一樣。

HTML提供了Crystal Reports無法實現的功能:交互式圖表、響應式表格以及一致品牌的共享樣式。

為何在.NET應用程式中替換Crystal Reports

從Crystal Reports遷移並不是因為一個巨大的問題或SAP的突然放棄,而是因為多個摩擦點累積,使該平臺在新項目中的使用更加難以合理化,且在現有解決方案的維護中更加困難。 識別這些痛點能夠明確為何許多團隊在尋找替代方案,以及在評估替代選項時最重要的標準。

無.NET 8和.NET Core支持

Crystal Reports不支持.NET Core或.NET 5-10。SAP在論壇上表示,他們不打算新增支持。 SDK使用的是COM元件,這與跨平台的.NET不相容。 支持現代.NET將需要完全重寫,SAP已經拒絕這樣做。

因此,在當前.NET版本上構建新應用程式的團隊無法使用Crystal Reports。 以.NET 8或.NET 10標準化的組織無法整合它。 對於現有應用程式,升級到現代.NET運行時需要先替換報表系統。

複雜的授權和隱藏成本

Crystal Reports的授權區分設計師許可、運行時許可、伺服器部署和嵌入式使用。 規則因桌面、網頁和終端服務不同而異。 某一設置中的合規可能在另一設置中需要額外的許可。 如果在部署後出現了差距,將會出現意外的成本。許多組織認為與其承擔不確定性,不如轉向具有更清晰授權的解決方案。

Windows專用平台鎖定

Crystal Reports只能在Windows上運行,使用傳統的.NET Framework。 您無法將這些應用程式部署到Linux容器、Linux上的Azure應用服務、AWS Lambda或Google Cloud Run。 隨著組織的容器化、平台無關和無伺服器系統的使用,這些限制變得愈加重要。

構建微服務的開發團隊面臨額外挑戰。 如果九個服務運行在輕量級Linux容器中,但其中一個因Crystal Reports需要Windows,則部署更複雜。 您需要Windows容器映像、與Windows相容的託管以及單獨的部署設置。 報告服務成為例外,阻礙標準化。

Set Up a C# Report Generator in .NET 10

開始使用IronPDF很簡單。 通過NuGet像其他.NET依賴項一樣安裝程式庫。 沒有額外的軟體需要下載或是生產伺服器的單獨運行時安裝程式。

選擇模板方案:Razor、HTML或混合

IronPDF支援三種不同的方法來構建報表模板。 每種方法根據團隊組成、專案要求和長期維護考慮提供特定的優勢。

Razor視圖 為已在.NET生態系統中工作的團隊提供最豐富的開發體驗。 在Visual Studio和VS Code中,強型別模型具有完整的IntelliSense支持、編譯時檢查以及C#語言的全功能---如迴圈、條件判斷、空值處理和字串格式化。 Razor的語法對於那些建立了ASP.NET Core應用程式的人來說非常熟悉,無需學習其他生態系統的模板引擎。 模板與其他原始碼檔案一起存在於專案中,參加重構操作,並作為正常構建過程的一部分進行編譯。

純HTML與字元插值 對於較簡單的報告或偏好與.NET程式碼完全分離的團隊效果良好。 HTML模板可以儲存為嵌入式資源,編譯到程式集、部署在應用程式旁邊的外部文件,甚至在運行時從資料庫或內容管理系統中檢索。基本的資料綁定使用string.Replace()來處理單一值,或像Scriban或Fluid等輕量級模板庫來處理更進階的場景。 這一方法最大限度地提高了可攜性,允許設計師在不安裝任何.NET工具的情況下,僅使用文字編輯器和網頁瀏覽器進行預覽來編輯模板。

混合方法 將兩種技術結合起來,以滿足需要靈活性的場景。 例如,Razor視圖可能會被渲染以生成主要HTML結構,然後進行後處理,以進行不適合清洗到視圖模型中的動態元素的附加字串替換。 或者,由非開發人員設計的HTML模板可以被調入,並使用Razor部分視圖來渲染僅包含複雜資料驅動的部分,然後將所有內容組合起來。 HTML-to-PDF的轉換對HTML來源不具有依賴性,允許根據每個報告的需求混合使用不同的方法。

鑒於這些選擇,本教程主要集中於Razor視圖,因為它們在型別安全性、可維護性和功能豐富性中為典型業務報告場景提供了最佳平衡。 如果未來的需求包括使用純HTML模板,這些技能可以直接轉移,因為兩種方法都生成HTML字串。

Build a Data-Driven PDF Report in C#

本節演示了一個完整的從頭到尾的銷售發票報告的建立過程。 範例涵蓋了所有報告使用的基本模式:定義結構資料的模型,建立將資料轉化為格式化HTML的Razor模板,渲染該模板為HTML字串,並將HTML轉換為準備查看、電子郵件或存檔的PDF文件。

建立HTML/CSS報告模板

第一步是定義資料模型。 真實的發票需要客戶資訊、帶有描述和定價的行項、計算的總計、稅務處理和公司品牌元素。 模型類應該結構化以反映這些分組:

// Invoice data model with customer, company, and line item details
public class InvoiceModel
{
    public string InvoiceNumber { get; set; } = string.Empty;
    public DateTime InvoiceDate { get; set; }
    public DateTime DueDate { get; set; }

    public CompanyInfo Company { get; set; } = new();
    public CustomerInfo Customer { get; set; } = new();
    public List<LineItem> Items { get; set; } = new();

    // Computed totals - business logic stays in the model
    public decimal Subtotal => Items.Sum(x => x.Total);
    public decimal TaxRate { get; set; } = 0.08m;
    public decimal TaxAmount => Subtotal * TaxRate;
    public decimal GrandTotal => Subtotal + TaxAmount;
}

// Company details for invoice header
public class CompanyInfo
{
    public string Name { get; set; } = string.Empty;
    public string Address { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;
    public string Phone { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
    public string LogoPath { get; set; } = string.Empty;
}

// Customer billing information
public class CustomerInfo
{
    public string Name { get; set; } = string.Empty;
    public string Address { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

// Individual invoice line item
public class LineItem
{
    public string Description { get; set; } = string.Empty;
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal Total => Quantity * UnitPrice;
}

在模型中包括了GrandTotal的計算屬性。 這些計算屬於模型而不是模板中,保持Razor視圖專注於展示,而模型處理業務邏輯。 這種分離使單元測試變得簡單,可以在不渲染任何HTML的情況下驗證計算。

現在建立將這個模型轉換為專業格式發票的Razor視圖。將其保存在您的Views文件夾中,命名為InvoiceTemplate.cshtml:

@model InvoiceModel
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        /* Reset and base styles */
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: 'Segoe UI', Arial, sans-serif; font-size: 12px; color: #333; line-height: 1.5; }
        .invoice-container { max-width: 800px; margin: 0 auto; padding: 40px; }

        /* Header with company info and invoice title */
        .header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 40px; padding-bottom: 20px; border-bottom: 2px solid #3498db; }
        .company-info h1 { font-size: 24px; color: #2c3e50; margin-bottom: 10px; }
        .company-info p { color: #7f8c8d; font-size: 11px; }
        .invoice-title { text-align: right; }
        .invoice-title h2 { font-size: 32px; color: #3498db; margin-bottom: 10px; }
        .invoice-title p { font-size: 12px; color: #7f8c8d; }

        /* Address blocks */
        .addresses { display: flex; justify-content: space-between; margin-bottom: 30px; }
        .address-block { width: 45%; }
        .address-block h3 { font-size: 11px; text-transform: uppercase; color: #95a5a6; margin-bottom: 8px; letter-spacing: 1px; }
        .address-block p { font-size: 12px; }

        /* Line items table */
        .items-table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }
        .items-table th { background-color: #3498db; color: white; padding: 12px; text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }
        .items-table th:last-child, .items-table td:last-child { text-align: right; }
        .items-table td { padding: 12px; border-bottom: 1px solid #ecf0f1; }
        .items-table tr:nth-child(even) { background-color: #f9f9f9; }

        /* Totals section */
        .totals { float: right; width: 300px; }
        .totals-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #ecf0f1; }
        .totals-row.grand-total { border-bottom: none; border-top: 2px solid #3498db; font-size: 16px; font-weight: bold; color: #2c3e50; padding-top: 12px; }

        /* Footer */
        .footer { clear: both; margin-top: 60px; padding-top: 20px; border-top: 1px solid #ecf0f1; text-align: center; color: #95a5a6; font-size: 10px; }
    </style>
</head>
<body>
    <div class="invoice-container">
        <!-- Company header and invoice details -->
        <div class="header">
            <div class="company-info">
                <h1>@Model.Company.Name</h1>
                <p>@Model.Company.Address</p>
                <p>@Model.Company.City</p>
                <p>@Model.Company.Phone | @Model.Company.Email</p>
            </div>
            <div class="invoice-title">
                <h2>INVOICE</h2>
                <p>Invoice #: @Model.InvoiceNumber</p>
                <p>Date: @Model.InvoiceDate.ToString("MMMM dd, yyyy")</p>
                <p>Due Date: @Model.DueDate.ToString("MMMM dd, yyyy")</p>
            </div>
        </div>

        <!-- Bill to address -->
        <div class="addresses">
            <div class="address-block">
                <h3>Bill To</h3>
                <p>@Model.Customer.Name</p>
                <p>@Model.Customer.Address</p>
                <p>@Model.Customer.City</p>
                <p>@Model.Customer.Email</p>
            </div>
        </div>

        <!-- Line items table -->
        <table class="items-table">
            <thead>
                <tr><th>Description</th><th>Quantity</th><th>Unit Price</th><th>Total</th></tr>
            </thead>
            <tbody>
                @foreach (var item in Model.Items)
                {
                    <tr>
                        <td>@item.Description</td>
                        <td>@item.Quantity</td>
                        <td>@item.UnitPrice.ToString("C")</td>
                        <td>@item.Total.ToString("C")</td>
                    </tr>
                }
            </tbody>
        </table>

        <!-- Totals -->
        <div class="totals">
            <div class="totals-row"><span>Subtotal:</span><span>@Model.Subtotal.ToString("C")</span></div>
            <div class="totals-row"><span>Tax (@(Model.TaxRate * 100)%):</span><span>@Model.TaxAmount.ToString("C")</span></div>
            <div class="totals-row grand-total"><span>Total Due:</span><span>@Model.GrandTotal.ToString("C")</span></div>
        </div>

        <!-- Footer message -->
        <div class="footer">
            <p>Thank you for your business!</p>
            <p>Payment is due within 30 days. Please include invoice number with your payment.</p>
        </div>
    </div>
</body>
</html>
HTML

此模板中嵌入的CSS處理所有視覺樣式,例如顏色、字體、間距和表格格式。 IronPDF還支持現代CSS功能,例如彈性框、網格布局和CSS變數。 渲染的PDF與Chrome的列印預覽完全匹配,這使除錯變得簡單:如果PDF中的某些內容看起來不對,打開HTML在瀏覽器中使用開發人員工具檢查和調整樣式。

綁定資料到模板

有了模型和模板之後,渲染PDF需要通過IronPDF的ChromePdfRenderer將它們連接起來。 關鍵步驟是將Razor視圖轉換為HTML字串,然後將該字串傳遞給渲染器:

using IronPdf;

// Service class for generating invoice PDFs from Razor views
public class InvoiceReportService
{
    private readonly IRazorViewEngine _razorViewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;

    public InvoiceReportService(
        IRazorViewEngine razorViewEngine,
        ITempDataProvider tempDataProvider,
        IServiceProvider serviceProvider)
    {
        _razorViewEngine = razorViewEngine;
        _tempDataProvider = tempDataProvider;
        _serviceProvider = serviceProvider;
    }

    // Generate PDF from invoice model
    public async Task<byte[]> GenerateInvoicePdfAsync(InvoiceModel invoice)
    {
        // Render Razor view to HTML string
        string html = await RenderViewToStringAsync("InvoiceTemplate", invoice);

        // Configure PDF renderer with margins and paper size
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;

        // Convert HTML to PDF and return bytes
        var pdfDocument = renderer.RenderHtmlAsPdf(html);
        return pdfDocument.BinaryData;
    }

    // Helper method to render a Razor view to string
    private async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
    {
        var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
        var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

        using var stringWriter = new StringWriter();
        var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);

        if (!viewResult.Success)
            throw new InvalidOperationException($"View '{viewName}' not found.");

        var viewDictionary = new ViewDataDictionary<TModel>(
            new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model };

        var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary,
            new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
            stringWriter, new HtmlHelperOptions());

        await viewResult.View.RenderAsync(viewContext);
        return stringWriter.ToString();
    }
}

對於較簡單的場景,當您不需要完整的ASP.NET Core MVC設置,例如在控制台應用程式或背景服務中時,您可以僅使用帶有插值的HTML字串和StringBuilder來處理動態部分。

範例輸出

新增頁眉、頁腳和頁碼

專業報告通常在所有頁面上包含一致的頁眉和頁腳,顯示公司品牌、文件標題、生成日期和頁碼。 IronPDF提供了兩種方法來實現這些元素:基於文字的頁眉適合需要最少格式化的簡單內容,而HTML頁眉可對帶有標誌和自定義佈局的全風格進行完全控制。

基於文字的頁眉對於基本資訊的效果良好並且渲染速度更快,因為它們不需要額外的HTML解析:

using IronPdf;
using IronSoftware.Drawing;

// Configure text-based headers and footers
var renderer = new ChromePdfRenderer();

// Set starting page number
renderer.RenderingOptions.FirstPageNumber = 1;

// Add centered header with divider line
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
    CenterText = "CONFIDENTIAL - Internal Use Only",
    DrawDividerLine = true,
    Font = FontTypes.Arial,
    FontSize = 10
};

// Add footer with date on left, page numbers on right
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
    LeftText = "{date} {time}",
    RightText = "Page {page} of {total-pages}",
    DrawDividerLine = true,
    Font = FontTypes.Arial,
    FontSize = 9
};

// Set margins to accommodate header/footer
renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 20;

可用的合併域包括{pdf-title}表示文件標題。 這些佔位符在渲染期間會自動替換。

對於帶有標誌、定制字體或複雜多列格式的頁眉,使用支持完整CSS樣式的HTML頁眉:

using IronPdf;
using System;

var renderer = new ChromePdfRenderer();

// Configure HTML header with logo and custom layout
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    MaxHeight = 30,
    HtmlFragment = @"
<div style='display: flex; justify-content: space-between; align-items: center;
            width: 100%; font-family: Arial; font-size: 10px; color: #666;'>
    <img src='logo.png' style='height: 25px;'>
    <span>Company Name Inc.</span>
    <span>Invoice Report</span>
</div>",
    BaseUrl = new Uri(@"C:\assets\images\").AbsoluteUri
};

// Configure HTML footer with page info and generation date
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    MaxHeight = 20,
    HtmlFragment = @"
<div style='text-align: center; font-size: 9px; color: #999;
            border-top: 1px solid #ddd; padding-top: 5px;'>
    Page {page} of {total-pages} | Generated on {date}
</div>",
    DrawDividerLine = false
};

範例輸出

建立動態表格和重複區段

報告通常需要顯示跨多頁的資料集合。 Razor的迴圈結構自然地處理此情況,通過迭代集合生成每個項目的表格行或卡片元素。

這是一個完整的員工名錄範例,展示了按部門分組的資料展示:

// Employee directory data models
public class EmployeeDirectoryModel
{
    public List<Department> Departments { get; set; } = new();
    public DateTime GeneratedDate { get; set; } = DateTime.Now;
}

// Department grouping with manager info
public class Department
{
    public string Name { get; set; } = string.Empty;
    public string ManagerName { get; set; } = string.Empty;
    public List<Employee> Employees { get; set; } = new();
}

// Individual employee details
public class Employee
{
    public string Name { get; set; } = string.Empty;
    public string Title { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
    public string Phone { get; set; } = string.Empty;
    public string PhotoUrl { get; set; } = string.Empty;
    public DateTime HireDate { get; set; }
}

使用在部門類上的CSS屬性page-break-inside: avoid 告訴PDF渲染器儘量將部門區段保留在同一頁上。 如果某一部門的內容會導致頁面中段分隔,渲染器會將整個區段移到下一頁。 使用選擇器.department:not(:first-child) 和 page-break-before: always強制第一個部門之後的每個部門以新頁開始,創造整個名錄的乾淨區段分隔。

範例輸出

Advanced C# Report Generation With IronPDF

業務報告通常需要超出靜態表格和文字的能力。 圖表可視化在表格式中理解起來繁瑣的趨勢。 條件格式化使需要行動的項目一目了然。 子報告將來自多個來源的資料結合到一致的文件中。 本節涵蓋了如何使用IronPDF的Chromium渲染引擎實現這些功能。

將圖表新增到PDF報告中

由於JavaScript在渲染過程中執行,您可以使用任何客戶端的圖表庫直接在報告中生成可視化圖表。 圖表作為頁面的一部分被光柵化,並在最終PDF中顯示,與螢幕上的顯示完全相同。 Chart.js為最常見報告需求提供了出色的簡單性、能力和文件平衡。

從CDN中包含Chart.js,使用從您的C#模型中序列化出的資料來配置圖表:

@model SalesReportModel

<!-- Include Chart.js library from CDN -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<!-- Canvas element for chart rendering -->
<canvas id="salesChart"></canvas>

<script>
    // Initialize bar chart with data from C# model
    const ctx = document.getElementById('salesChart').getContext('2d');
    new Chart(ctx, {
        type: 'bar',
        data: {
            // Serialize model data to JavaScript arrays
            labels: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.MonthLabels)),
            datasets: [{
                label: 'Monthly Sales',
                data: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.MonthlySales)),
                backgroundColor: 'rgba(52, 152, 219, 0.7)'
            }]
        }
    });
</script>
HTML

在渲染包含JavaScript生成內容的頁面時,配置渲染器以等待腳本完成執行再抓取頁面:

using IronPdf;

string html = "<h1>Report</h1>";

// Configure renderer to wait for JavaScript execution
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.WaitFor.JavaScript(500); // Wait 500ms for JS to complete
var pdf = renderer.RenderHtmlAsPdf(html);

範例輸出

應用條件格式化和業務邏輯

存貨報告得益於立即吸引注意需要行動的項目的可視指標。 條件格式化使例外情況在視覺上顯而易見,而不是強迫使用者掃描數百行以尋找問題。 使用Razor的內聯表達式根據資料值應用CSS類:

<!-- Iterate through inventory items sorted by quantity -->
@foreach (var item in Model.Items.OrderBy(x => x.Quantity))
{
    // Apply CSS class based on stock level thresholds
    var rowClass = item.Quantity <= Model.CriticalStockThreshold ? "stock-critical" :
                   item.Quantity <= Model.LowStockThreshold ? "stock-low" : "";

    <tr class="@rowClass">
        <td>@item.SKU</td>
        <td>@item.ProductName</td>
        <td class="text-right">
            <!-- Badge styling for critical stock items -->
            <span class="quantity-badge @(item.Quantity <= 5 ? "badge-critical" : "badge-ok")">
                @item.Quantity
            </span>
        </td>
    </tr>
}
HTML

範例輸出

建立子報告和分段

要將獨立生成的報告合併為一個文件,使用IronPDF的合併功能:

using IronPdf;

// Combine multiple reports into a single PDF document
public byte[] GenerateCombinedReport(SalesReportModel sales, InventoryReportModel inventory)
{
    var renderer = new ChromePdfRenderer();

    // Render each report section separately
    var salesPdf = renderer.RenderHtmlAsPdf(RenderSalesReport(sales));
    var inventoryPdf = renderer.RenderHtmlAsPdf(RenderInventoryReport(inventory));

    // Merge PDFs into one document
    var combined = PdfDocument.Merge(salesPdf, inventoryPdf);
    return combined.BinaryData;
}

範例輸出

生成目錄

IronPDF可以基於HTML中的標題元素自動生成目錄:

using IronPdf;

// Generate PDF with automatic table of contents
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.TableOfContents = TableOfContentsTypes.WithPageNumbers;
var pdf = renderer.RenderHtmlFileAsPdf("report.html");

我最喜歡的程式庫是IronPDF。它允許快速高效地操作PDF文件。它還有許多有價值的功能,例如導出到PDF/A格式和數位簽署PDF文件。

Milan Jovanovic

Microsoft MVP

查看案例研究

IronOCR意味著我們每年可以從手動處理中節省$40,000,同時提高生產力,釋放資源以進行高影響的任務。我會強烈推薦它。

Brent Matzelle

首席技術官,OPYN

查看案例研究

從Crystal Reports遷移到IronPDF

遷移已建立的報告系統需要謹慎計劃,以在最小化中斷的同時抓住現代化和簡化的機會。 通過理解Crystal Reports概念和基於HTML方法之間的映射,您將更快前進,而不是試圖字面地複製每一個功能或保留原始報告的每個癖好。

將Crystal Reports概念映射到IronPDF

理解概念映射有助於您系統地翻譯現有報告:

Crystal ReportsIronPDF對等
報告區段帶有CSS分頁屬性的HTML div
參數域傳遞給Razor視圖的模型屬性
公式域模型類中的C#計算屬性
運行總計LINQ聚合
子報告部分視圖或合併的PDF文件
分組/排序在將資料傳遞給模板前的LINQ操作
交叉報告使用巢狀迴圈的HTML表格
條件格式化帶有CSS類的Razor @if 塊

轉換.rpt模板的最佳策略

請勿嘗試以程式方式解析.rpt文件。 相反,將現有的PDF輸出視為視覺規範,並使用系統的四步策略重建邏輯:

  1. 清單整理: 記錄所有.rpt文件及其用途、資料來源和使用頻率。 刪除過時報告以減少遷移範圍。

  2. 優先化: 優先遷移高頻報表。針對簡單佈局或持續維護問題的報告進行處理。

  3. 參考: 將現有的Crystal Reports匯出為PDF。 使用這些作為開發人員配對的視覺規範。

  4. 驗證: 用生產資料量進行測試。 模板在10行時渲染即時,但在10,000行時可能會變慢。

在.NET中批次報告生成和排程

生產系統通常需要同時生成多個報告,或按計劃運行報告作業。 IronPDF的執行緒安全設計有效地支持這兩種情況。

並行生成多個報告

對於批次處理,使用Task.WhenAll:

using IronPdf;
using System.Collections.Concurrent;

// Generate multiple invoices in parallel using async processing
public async Task<List<ReportResult>> GenerateInvoiceBatchAsync(List<InvoiceModel> invoices)
{
    var results = new ConcurrentBag<ReportResult>();

    // Process invoices concurrently with controlled parallelism
    await Parallel.ForEachAsync(invoices,
        new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
        async (invoice, token) =>
        {
            // Each thread gets its own renderer instance
            var renderer = new ChromePdfRenderer();
            string html = BuildInvoiceHtml(invoice);
            var pdf = await renderer.RenderHtmlAsPdfAsync(html);

            // Save individual invoice PDF
            string filename = $"Invoice_{invoice.InvoiceNumber}.pdf";
            await pdf.SaveAsAsync(filename);

            results.Add(new ReportResult { InvoiceNumber = invoice.InvoiceNumber, Success = true });
        });

    return results.ToList();
}

範例輸出

批次處理範例並行生成多個發票。 這是生成的批次發票之一:

將報告生成與ASP.NET Core背景服務整合

排程報告生成自然適合於ASP.NET Core's 的託管服務架構:

// Background service for scheduled report generation
public class DailyReportService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            // Calculate next run time (6 AM daily)
            var nextRun = DateTime.Now.Date.AddDays(1).AddHours(6);
            await Task.Delay(nextRun - DateTime.Now, stoppingToken);

            // Create scoped service for report generation
            using var scope = _serviceProvider.CreateScope();
            var reportService = scope.ServiceProvider.GetRequiredService<IReportGenerationService>();

            // Generate and distribute daily report
            var salesReport = await reportService.GenerateDailySalesSummaryAsync();
            // Email or save reports as needed
        }
    }
}

下載完整測試專案

本教程的所有程式碼範例均可從一個準備運行的.NET 10測試專案中獲得。 下載包括完整的原始碼、資料模型、HTML模板和一個測試運行器,用於生成以上所示的所有範例PDF。

後續步驟

本指南中的範例說明了IronPDF處理全方位的業務報告需求:簡單的發票包含行項和總計、複雜的員工名錄帶有分組資料和照片、庫存報告配有條件格式化和圖表、數百個文件的批量處理,以及通過背景服務的排程生成。

如果您在評估替代現有Crystal Reports實現的選擇,請從一個高價值報表開始。 使用此處顯示的HTML-to-PDF模式重建它,比較開發體驗和輸出質量,然後擴展。 許多團隊發現,第一個轉換的報告需要幾小時,因為他們建立了模式和基本模板,而隨後的報告只需幾分鐘來組裝,因為他們重用Razor 模板和樣式。 對於佈局精確度,像素完美渲染指南涵蓋了如何使用CSS將Crystal Reports的輸出精確匹配。

準備好開始構建了嗎? 下載IronPDF並嘗試免費試用。 同一個庫處理從單個報告渲染到跨.NET環境的大批生成。 如果您對報告遷移有疑問或需要架構指導,聯繫我們的工程支援團隊。

常見問題

什麼是IronPDF?

IronPDF是一個C#程式庫,使開發者能夠以程式化的方式建立、編輯和生成PDF文件,為傳統報告工具如Crystal Reports提供了一個現代替代方案。

IronPDF如何作為Crystal Reports的替代方案?

IronPDF提供了一種靈活和現代的報告生成方法,允許開發者使用HTML/CSS模板,這些模板可以輕鬆地樣式化和修改,與Crystal Reports的結構相比更具彈性。

我可以使用IronPDF建立發票嗎?

是的,您可以使用HTML/CSS模板與IronPDF建立詳細且自定義的發票,輕鬆設計出專業外觀的文件。

使用IronPDF生成員工名錄是否可行?

絕對可以。IronPDF允許您利用動態資料和HTML/CSS生成全面的員工名錄,便於清晰有序的呈現。

IronPDF如何幫助庫存報告?

IronPDF可以通過使用HTML/CSS模板簡化庫存報告的建立,這些模板可以動態填充資料,以提供最新且視覺上有吸引力的報告。

在IronPDF中使用HTML/CSS模板有哪些優勢?

在IronPDF中使用HTML/CSS模板可提供設計上的靈活性、易於更新,以及與網頁技術的相容性,使報告佈局更易於維護和增強。

IronPDF支持.NET 10嗎?

是的,IronPDF與.NET 10相容,確保開發者能利用最新.NET功能和改進進行報告生成。

IronPDF如何改善報告生成速度?

IronPDF經過性能優化,允許快速生成報告,透過有效處理HTML/CSS並將其渲染為高質量PDF文件。

Is it possible to automate report generation with IronPDF?

IronPDF supports automation of report generation through batch processing and can be integrated with ASP.NET Core Background Services for scheduled report generation tasks.

What is the best approach to migrate from Crystal Reports to IronPDF?

The best approach involves mapping Crystal Reports concepts to their IronPDF equivalents, prioritizing high-use reports, referencing existing outputs as specifications, and validating the new implementations against production data.

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

...
閱讀更多

準備開始了嗎?

Nuget Downloads 21,253,952版本:2026.10剛剛發布

立即獲取您的免費30天試用密鑰。
不需要信用卡或建立賬戶
C# 用於PDF的NuGet程式庫
使用NuGet安裝

版本: 2026.10

PM > Install-Package IronPdf
nuget.org/packages/IronPdf/
  1. 在解決方案資源管理器,右鍵點選參考,管理NuGet包
  2. 選擇瀏覽並搜尋"IronPdf"
  3. 選擇套件並安裝
C# PDF DLL
下載DLL

版本: 2026.10

或者點擊此處下載Windows安裝程式。

  1. 下載並解壓IronPDF到類似~/Libs的位置,位於您的解決方案目錄中
  2. 在Visual Studio解決方案資源管理器,右鍵點選參考。選擇瀏覽,"IronPdf.dll"

授權從$999起

有問題嗎?聯絡我們的開發團隊。

Key in blue circle

立即免費取得 30 天試用金鑰。

Your trial license will be sent to your email address

無任何限制。100% 解鎖。無需信用卡。

bullet_checked無需信用卡或建立帳號無任何限制。100% 解鎖。無需信用卡。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
預訂您的免費現場演示
Booking Badge

受到全球數百萬工程師的信任

Iron Software的客戶標誌
獲取您的無義務諮詢
您的詳細資訊將始終保密。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
受到全球數百萬工程師的信任
立即獲取您的30天試用金鑰。
無需信用卡或帳戶建立
C# 用於PDF的NuGet程式庫
使用NuGet安裝

版本: 2026.10

PM > Install-Package IronPdf
nuget.org/packages/IronPdf/
  1. 在解決方案資源管理器,右鍵點選參考,管理NuGet包
  2. 選擇瀏覽並搜尋"IronPdf"
  3. 選擇套件並安裝
C# PDF DLL
下載DLL

版本: 2026.10

或者點擊此處下載Windows安裝程式。

  1. 下載並解壓IronPDF到類似~/Libs的位置,位於您的解決方案目錄中
  2. 在Visual Studio解決方案資源管理器,右鍵點選參考。選擇瀏覽,"IronPdf.dll"

授權從$999起