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

ASP.NET Crystal Reports 完整應用指南:Pull vs Push 模式、StrongTyped vs UnTyped、登入資訊動態設定

     編輯:ASP.NET 基礎

兩大執行模式比較

特性Pull 模式 (拉取)Push 模式 (推送)
資料來源報表內建連線資訊,直接連資料庫應用程式準備 DataSet 傳給報表
程式碼複雜度低 (設定報表檔案路徑即可)中 (需自行查詢、填充 DataSet)
效能優化難控制 (連線共用、查詢最佳化)高 (連線池、分頁、快取自主控制)
部署相依性報表檔需包含正確連線字串報表檔僅需結構定義 (XSD)
適用場景簡單報表、單一資料庫、低維護複雜邏輯、多資料源、高併發、雲端部署

兩種報表類型

  • StrongTyped (強型別):將 .rpt 加入專案 → 自動產生繼承 ReportClass 的類別 → var rpt = new MyReport(); 智慧提示、型別安全
  • UnTyped (非強型別):報表檔獨立部署 → 使用 ReportDocument 動態載入 → rpt.Load(path) 靈活、支援執行時切換報表

Pull 模式完整實作

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        LoadPullReport();
    }
}

private void LoadPullReport()
{
    var reportDoc = new ReportDocument();
    string rptPath = Server.MapPath("~/Reports/SalesReport.rpt");
    reportDoc.Load(rptPath);

    // 關鍵:動態設定資料庫登入資訊 (解決部署環境連線字串不同)
    ConfigureDatabaseLogon(reportDoc);

    CrystalReportViewer1.ReportSource = reportDoc;
    CrystalReportViewer1.DataBind();
}

private void ConfigureDatabaseLogon(ReportDocument reportDoc)
{
    // 從 Web.config 讀取連線資訊
    string server = ConfigurationManager.AppSettings["DB_Server"];
    string database = ConfigurationManager.AppSettings["DB_Name"];
    string user = ConfigurationManager.AppSettings["DB_User"];
    string pwd = ConfigurationManager.AppSettings["DB_Pwd"];

    var logonInfo = new TableLogOnInfo
    {
        ConnectionInfo = 
        {
            ServerName = server,
            DatabaseName = database,
            UserID = user,
            Password = pwd,
            // 整合驗證時設定 IntegratedSecurity = true
        }
    };

    // 套用至報表中所有資料表
    foreach (Table table in reportDoc.Database.Tables)
    {
        table.ApplyLogOnInfo(logonInfo);
    }
}

Push 模式完整實作

private void LoadPushReport()
{
    // 1. 定義報表需求的 DataSet 結構 (需與 .rpt 定義的 XSD 完全一致)
    DataSet ds = GetReportData(); // 自行實作查詢邏輯

    // 2. 載入報表
    var reportDoc = new ReportDocument();
    string rptPath = Server.MapPath("~/Reports/SalesReport_Push.rpt");
    reportDoc.Load(rptPath);

    // 3. 設定資料來源
    reportDoc.SetDataSource(ds); // 或 reportDoc.SetDataSource(ds.Tables["MainTable"]);

    // 4. 繫結顯示
    CrystalReportViewer1.ReportSource = reportDoc;
    CrystalReportViewer1.DataBind();
}

private DataSet GetReportData()
{
    string connStr = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
    string sql = @"
        SELECT OrderId, CustomerName, OrderDate, TotalAmount, Status
        FROM Orders 
        WHERE OrderDate BETWEEN @Start AND @End";

    using (var conn = new SqlConnection(connStr))
    using (var da = new SqlDataAdapter(sql, conn))
    {
        da.SelectCommand.Parameters.AddWithValue("@Start", DateTime.Today.AddMonths(-1));
        da.SelectCommand.Parameters.AddWithValue("@End", DateTime.Today);
        
        DataSet ds = new DataSet();
        da.Fill(ds, "Orders"); // TableName 必須與 .rpt 定義一致
        return ds;
    }
}

關鍵技術細節

1. 解決「資料庫登入失敗」通用方案

// 遞迴處理子報表
private void ApplyLogOnToAll(ReportDocument reportDoc, TableLogOnInfo logonInfo)
{
    foreach (Table table in reportDoc.Database.Tables)
    {
        table.ApplyLogOnInfo(logonInfo);
    }
    foreach (ReportDocument subReport in reportDoc.Subreports)
    {
        ApplyLogOnToAll(subReport, logonInfo);
    }
}

2. 匯出 PDF/Excel/Word 程式碼

protected void BtnExportPdf_Click(object sender, EventArgs e)
{
    var reportDoc = new ReportDocument();
    reportDoc.Load(Server.MapPath("~/Reports/Invoice.rpt"));
    ConfigureDatabaseLogon(reportDoc);
    
    // 設定參數 (若報表有參數)
    reportDoc.SetParameterValue("@CustomerId", 12345);
    
    Stream stream = reportDoc.ExportToStream(ExportFormatType.PortableDocFormat);
    stream.Seek(0, SeekOrigin.Begin);
    
    Response.Clear();
    Response.ContentType = "application/pdf";
    Response.AddHeader("Content-Disposition", "attachment; filename=Invoice.pdf");
    Response.BinaryWrite(stream.ToArray());
    Response.End();
}

3. 報表參數傳遞

// .rpt 設計時建立參數 @DateFrom, @DateTo
reportDoc.SetParameterValue("@DateFrom", DateTime.Today.AddDays(-30));
reportDoc.SetParameterValue("@DateTo", DateTime.Today);

部署與授權注意事項

⚠️ 生產環境部署清單

  1. 安裝 Crystal Reports Runtime:伺服器必須安裝對應版本 (13.0.x for VS2010, 14.0.x for VS2017/2019/2022)
  2. 授權模式:SAP Crystal Reports for Visual Studio 免費版僅限開發,生產伺服器需購買 Crystal Reports Server 或 BOE 平台授權
  3. 32/64 位元相容:IIS 應用程式集區 啟用 32 位元應用程式 = True (舊版 Runtime 僅 32-bit)
  4. 暫存資料夾權限:C:\Windows\Temp 或自訂 Temp 目錄需 IIS_IUSRS 寫入權限
  5. 字體缺失:報表使用的中文字體 (微軟正黑體等) 需安裝在伺服器

現代替代方案建議

考慮到 Crystal Reports 授權成本、部署複雜度、.NET Core 不支援,新專案建議評估:

  • 開源:NReco.PdfGenerator (HTML 轉 PDF)、QuestPDF (程式化版面)、FastReport Open Source
  • 商業:Stimulsoft、Telerik Reporting、Bold Reports (支援 .NET Core/5/6/7/8)
  • 雲端:Azure SQL Reporting、AWS QuickSight 嵌入式分析
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved