首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET WebForms 整合 Crystal Reports 完整實作指南

     編輯:ASP.NET 基礎

前言

Crystal Reports 是傳統 ASP.NET WebForms 專案常用的報表引擎。本文說明在 WebForm 中正確初始化 `ReportDocument`、設定資料來源、處理分頁/匯出、以及關鍵的資源釋放模式,避免記憶體洩漏與「報表文件過多」錯誤。

一、核心實作模式:Page_Init / Page_Unload 配對

public partial class ReportViewerPage : System.Web.UI.Page
{
    private ReportDocument _rptDocument;

    protected void Page_Init(object sender, EventArgs e)
    {
        // 必須在 Page_Init 重新載入報表,確保 ViewState/Postback 正常
        ConfigureCrystalReport();
    }

    protected void Page_Unload(object sender, EventArgs e)
    {
        // 關鍵:每次請求結束必須釋放 ReportDocument
        if (_rptDocument != null)
        {
            _rptDocument.Close();
            _rptDocument.Dispose();
            _rptDocument = null;
        }
    }

    private void ConfigureCrystalReport()
    {
        // 1. 解密查詢參數
        string encryptedId = Request.QueryString["toid"];
        string decrypted = BusinessObject.Util.Decrypt(encryptedId);
        int tourOrderId = Util.ConvertTo<int>(decrypted, 0);

        // 2. 檢查 ViewState 快取(避免重複載入 .rpt 檔與查詢資料)
        if (ViewState["reportdoc"] == null)
        {
            // 3. 載入報表範本
            string reportPath = Server.MapPath("~/Report/TourNote.rpt");
            _rptDocument = new ReportDocument();
            _rptDocument.Load(reportPath);

            // 4. 取得資料集(含多張 Table)
            DataSet ds = BusinessObject.TourOrders.GetTourNoteDsRpt(tourOrderId);
            
            // 快取 DataSet 供 Postback 重用
            ViewState["reportdata"] = ds;

            // 5. 設定資料來源
            _rptDocument.SetDataSource(ds);

            // 6. 列印設定
            _rptDocument.PrintOptions.PaperSize = PaperSize.DefaultPaperSize;

            // 7. 快取 ReportDocument
            ViewState["reportdoc"] = _rptDocument;
        }
        else
        {
            // Postback 時從 ViewState 還原
            _rptDocument = (ReportDocument)ViewState["reportdoc"];
        }

        // 8. 綁定至 CrystalReportViewer
        this.CrystalReportViewer1.ReportSource = _rptDocument;
        
        // 選用:隱藏群組樹、工具列按鈕
        this.CrystalReportViewer1.HasToggleGroupTreeButton = false;
        this.CrystalReportViewer1.DisplayGroupTree = false;
    }
}

二、關鍵技術細節解析

為什麼要在 Page_Init 初始化?

  • `CrystalReportViewer` 需要在頁面生命週期早期綁定 `ReportSource`,才能正確處理分頁、匯出、列印等 Postback 操作
  • `Page_Load` 太晚,會導致「報表來源未設定」或分頁失效

ViewState 快取 ReportDocument 的優缺點

優點缺點
避免重複載入 .rpt 檔案ViewState 體積大(含報表定義與資料),增加頁面傳輸量
Postback 保持報表狀態(分頁、排序)併發用戶多時伺服器記憶體壓力大

建議: 小型報表、低併發可用 ViewState;大型報表或高併發應改用 `Session` 或暫存檔快取,並設定適當逾期清理。

資料來源設定最佳實務

// 正確:使用強型別 DataSet 或 DataTable
_rptDocument.SetDataSource(typedDataSet); 

// 或逐張表設定(報表包含多張不相關表時)
_rptDocument.Database.Tables["Table1"].SetDataSource(dt1);
_rptDocument.Database.Tables["Table2"].SetDataSource(dt2);

// 參數欄位設定
_rptDocument.SetParameterValue("ReportTitle", "月銷售報表");
_rptDocument.SetParameterValue("DateRange", $"{startDate:d} ~ {endDate:d}");

三、常見功能擴充

1. 匯出為 PDF / Excel / Word

protected void btnExportPdf_Click(object sender, EventArgs e)
{
    ConfigureCrystalReport(); // 確保報表已載入
    
    Stream stream = _rptDocument.ExportToStream(ExportFormatType.PortableDocFormat);
    Response.Clear();
    Response.Buffer = true;
    Response.ContentType = "application/pdf";
    Response.AddHeader("Content-Disposition", "attachment;filename=Report.pdf");
    Response.BinaryWrite((stream as MemoryStream).ToArray());
    Response.Flush();
    Response.End();
}

2. 直接列印到印表機

protected void btnPrint_Click(object sender, EventArgs e)
{
    ConfigureCrystalReport();
    _rptDocument.PrintOptions.PrinterName = "\\\\PrintServer\\HP_LaserJet"; // 網路印表機
    _rptDocument.PrintToPrinter(1, false, 0, 0); // 份數、雙面、起始頁、結束頁
}

3. 動態調整報表欄位顯示/隱藏

private void ToggleSectionVisibility(string sectionName, bool visible)
{
    var section = _rptDocument.ReportDefinition.Sections[sectionName];
    if (section != null) section.SectionFormat.EnableSuppress = !visible;
}

四、部署與授權注意事項

  1. Runtime 版本一致:開發機、伺服器需安裝相同版本 Crystal Reports Runtime (32/64 位元對應 IIS 應用程式集區)
  2. 授權模式:SAP Crystal Reports for Visual Studio 免費版支援基本功能,進階功能需購買授權
  3. 目錄權限:`C:\Windows\Temp` 或自訂暫存目錄需給 IIS_IUSRS 寫入權限(報表引擎會產生暫存檔)
  4. Web.config 設定:
    <configSections>
      <section name="crystalReport" type="CrystalDecisions.Shared.CrystalReportsSection, CrystalDecisions.Shared" />
    </configSections>
    <crystalReport>
      <resourceUri /> <!-- 避免資源 URI 問題 -->
    </crystalReport>

五、記憶體洩漏防範檢查清單

  • [ ] 每個 Request 結束呼叫 `Close()` + `Dispose()`
  • [ ] 例外發生時也能釋放(使用 `try/finally` 或 `using` 包裝)
  • [ ] 避免長期在 Session/Application 快取 `ReportDocument`
  • [ ] 監控 `crystal_*.tmp` 暫存檔數量,定期清理
  • [ ] 考慮改用輕量替代方案:FastReport、Stimulsoft、或前端 JS 報表

總結

Crystal Reports 在 ASP.NET WebForms 中的正確使用關鍵在於:`Page_Init` 初始化、`Page_Unload` 確實釋放、資料來源正確綁定、部署環境 Runtime 版本一致。雖然功能強大,但資源佔用高、授權複雜,新專案建議評估現代化替代方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved