| 特性 | Pull 模式 (拉取) | Push 模式 (推送) |
|---|---|---|
| 資料來源 | 報表內建連線資訊,直接連資料庫 | 應用程式準備 DataSet 傳給報表 |
| 程式碼複雜度 | 低 (設定報表檔案路徑即可) | 中 (需自行查詢、填充 DataSet) |
| 效能優化 | 難控制 (連線共用、查詢最佳化) | 高 (連線池、分頁、快取自主控制) |
| 部署相依性 | 報表檔需包含正確連線字串 | 報表檔僅需結構定義 (XSD) |
| 適用場景 | 簡單報表、單一資料庫、低維護 | 複雜邏輯、多資料源、高併發、雲端部署 |
ReportClass 的類別 → var rpt = new MyReport(); 智慧提示、型別安全ReportDocument 動態載入 → rpt.Load(path) 靈活、支援執行時切換報表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);
}
}
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;
}
}
// 遞迴處理子報表
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);
}
}
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();
}
// .rpt 設計時建立參數 @DateFrom, @DateTo
reportDoc.SetParameterValue("@DateFrom", DateTime.Today.AddDays(-30));
reportDoc.SetParameterValue("@DateTo", DateTime.Today);
C:\Windows\Temp 或自訂 Temp 目錄需 IIS_IUSRS 寫入權限考慮到 Crystal Reports 授權成本、部署複雜度、.NET Core 不支援,新專案建議評估: