日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

在没有SSRS的ASP.NET中运行RDL/RDLC(SQL报告)

發布時間:2023/12/20 asp.net 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在没有SSRS的ASP.NET中运行RDL/RDLC(SQL报告) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

介紹

先決條件

戰略

使用代碼

以終為始

故事的其余部分

從RDLC文件中獲取查詢

設置任何參數

重構

報表參數/查詢參數

網址參數

運行查詢并填寫數據表

跟進(重構)

更新:導致錯誤的其他事情

結論


  • 下載 VStudio 2010 的舊源 - 21.2 KB?
  • 下載 VStudio 2013 的源代碼?- 179.6 KB

?

這是一個常見的場景:您有一個用ASP.NET(或MVCSharePoint)編寫的網站,并且您想顯示一些報告。您可能正計劃編寫一些新報告,并且您正在嘗試決定使用哪種技術,或者您可能有幾個之前已經制作的SSRS報告,并且您希望從您的ASP.NET站點運行它們。

CodeProject上有很多很好的文章,展示了如何使用RDLC文件運行報表,無論是來自ASP.NET還是WinForms等。閱讀它們之后,您的選擇似乎是:

  • 將報表放入SSRS并使用ReportViewer控件調用SSRS運行您的報表
  • .RDL.RDLC文件添加到您的項目中,并創建一些對象來存放數據,以便報表具有與數據庫的接口,我想要第三種選擇:
  • 只需像SSRS一樣運行它,但無需安裝SSRS服務器。我說的是最低限度的足跡。我只想將.RDL.RDLC文件的名稱傳遞給ASPX頁面并讓它運行。這就是SSRS的做法。我應該也能做到。
  • 這是第三種選擇的實現。

    先決條件

  • 要運行它,您仍然需要安裝報告運行時。您可以將其添加為Nuget“Microsoft.ReportViewer.Runtime.Common”“Microsoft.ReportViewer.WebForms”(或WinForms)。Microsoft 下載站點上提供了可再發行組件。
  • 我有一些舊報告,它們是用舊的商業智能開發工作室(2008)制作的。我還有一些使用ReportBuilder(內置SSRS網絡)制作的新報告。此解決方案適用于任何一個。
  • 戰略

    .RDLC文件都是XML?如果您使用記事本打開它并檢查內容,您會看到XML描述了顯示/設計,但它還包含其他一些有用的特征。其中之一是報表的查詢(獲取數據)。

    我的策略是提取數據庫查詢,設置任何參數,運行查詢,將結果存儲在DataTable(s)中并將其提供給報告。

    我的目標是從通用頁面運行我的報告,并通過URL QueryString傳遞報告名稱和任何查詢參數,如下所示:

    .../View.aspx?Report=Example.rdlc&StartDate=1/1/2012&EndDate=12/31/2012

    為簡單起見,我將只使用應用程序其余部分使用的相同DB連接字符串,但我會將其包裝在本地工廠方法中,以實現可維護性。

    使用代碼

    以終為始

    這就是我開始的地方。這些示例效果很好,但無法使用嵌入在報告中的查詢。在代碼塊(如下)中,您可以看到我創建了一個名為Report?(命名空間是RDL)的類來封裝RDLC的內容/結構。我的RDL.Report類還包含一個工廠方法來幫助將XML轉換為對象。

    //View.aspx.cs protected void ShowReport() {System.IO.FileInfo reportFullPath = this.ReportFile;//check to make sure the file ACTUALLY exists, before we start working on itif (reportFullPath != null){//map the reporting engine to the .rdl/.rdlc filervReportViewer.LocalReport.ReportPath = reportFullPath.FullName; // 1. Clear Report DatarvReportViewer.LocalReport.DataSources.Clear();// 2. Get the data for the report// Look-up the DB query in the "DataSets" // element of the report file (.rdl/.rdlc which contains XML)RDL.ReportreportDef = RDL.Report.GetReportFromFile(reportFullPath.FullName);// Run each query (usually, there is only one) and attach it to the reportforeach (RDL.DataSet ds in reportDef.DataSets){//copy the parameters from the QueryString into the ReportParameters definitions (objects)ds.AssignParameters(this.ReportParameters);//run the query to get real data for the reportSystem.Data.DataTable tbl = ds.GetDataTable(this.DBConnectionString);//attach the data/table to the Report's dataset(s), by nameReportDataSource rds = new ReportDataSource();rds.Name = ds.Name; //This refers to the dataset name in the RDLC filerds.Value = tbl;rvReportViewer.LocalReport.DataSources.Add(rds);}rvReportViewer.LocalReport.Refresh();} }

    故事的其余部分

    (上面的)代碼塊顯示了應用程序的核心;運行查詢并將數據附加到報表,然后運行報表?,F在,讓我們看看獲取數據的部分。

    RDLC文件中獲取查詢

    .RDLC文件中,查詢的XML如下所示(刪除其他所有內容后):

    <Report><DataSets><DataSet Name="IrrelevantToThisExample"><Query><DataSourceName>DataTableName</DataSourceName><CommandText>SELECT * FROM sys.Tables</CommandText></Query></DataSet></DataSets> </Report>

    在我的第一次嘗試中,我使用XPathXML(在RDLC文件內部)中提取查詢。它適用于簡單的查詢。但是,我意識到如果查詢有任何參數(或存儲過程等),事情就會變得一團糟。

    在我的第二次嘗試中,我采取了不同的方法。我意識到如果我將XML反序列化為一堆對象,代碼會更容易。這聽起來既復雜又可怕,但是一旦你看到它,你就會意識到XML序列化/反序列化是多么簡單。

    與此XML匹配的(簡化的)類如下所示:

    [Serializable(), System.Xml.Serialization.XmlRoot("Report")] public class Report : SerializableBase {public List<DataSet> DataSets = new List<DataSet>(); }public class DataSet {[System.Xml.Serialization.XmlAttribute]public string Name;public Query Query = new Query(); }public class Query {public string DataSourceName;public string CommandText; }

    反序列化XML后,您可以輕松提取查詢,如下所示:

    Report report =Report.Deserialize(xml, typeof(RDL.Report)); String commandText = report.DataSets[0].Query.CommandText;

    SerializableBase對象是我從幾個項目中重復使用的東西。它使將任何對象序列化或反序列化為XML變得簡單,反之亦然。這是代碼:

    [Serializable] public class SerializableBase {public static SerializableBase Deserialize(String xml, Type type){//… some code omitted for brevity. See downloads.System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(type);using (System.IO.StringReadersr = new System.IO.StringReader(xml)){return (SerializableBase)ser.Deserialize(sr);}} }

    設置任何參數

    正如我前面提到的,在我處理參數化查詢和存儲過程之前,代碼非常簡單。我不得不添加更多的反序列化類。為簡潔起見,我會將它們包含在下載的代碼中,但可以免去您在此處閱讀代碼的麻煩。別擔心。它們是非常簡單(無聊)的類,與XML的結構相匹配,就像上面的序列化類一樣。

    重構

    此代碼的其余部分從實用程序類開始??赐曛?#xff0c;我意識到如果我將實用程序代碼封裝在序列化類中作為方法而不是作為外部輔助實用程序函數,那將更加純粹地面向對象。它使序列化類看起來更復雜。這就是為什么在本文中,我首先以最簡單的形式描述原始類(如上)。

    報表參數/查詢參數

    不幸的是,在RDLC文件中,查詢塊定義了它的參數,但沒有為它們定義類型。DB會阻塞不容易轉換的類型,例如:DateTimeNumericInteger。幸運的是,參數類型在RDLCXML的單獨部分中定義。我只需要將它們復制到查詢參數定義中。不幸的是,它使代碼看起來有點老套,但它確實可靠地完成了工作。

    //Report.cs private void ResolveParameterTypes() {//for each report parameter, find the matching query parameter and copy-in the data typeforeach (ReportParameter rParam in this.ReportParameters){foreach (DataSet ds in this.DataSets)foreach (QueryParameter qParam in ds.Query.QueryParameters){if (qParam.Value == "=Parameters!" + rParam.Name + ".Value"){qParam.DataType = rParam.DataType;}}} } // override the constructor so the report param types are always resolved to the query params //as a bonus, now you don't have to cast it after deserializing it public static Report Deserialize(string xml, Type type) {Report re;re = (Report)SerializableBase.Deserialize(xml, type);//copy the type-names from the ReportParameters to the QueryParametersre.ResolveParameterTypes();return re; }

    網址參數

    現在,我將(URL)QueryString中的參數復制到報告的param中。自然,我對與報告中的QueryString參數名稱匹配的參數名稱做出了一些重大假設。如果它們不匹配,則會出現錯誤,但應該很容易找出問題所在。我還可以添加一些診斷程序來檢測哪些參數沒有獲得分配給它們的值(可能稍后)。

    //View.aspx.cs private System.Collections.Hashtable ReportParameters {get{System.Collections.Hashtable re = new System.Collections.Hashtable();//gather any params so they can be passed to the reportforeach (string key in Request.QueryString.AllKeys){if (key.ToLower() != "path")//ignore the "path" param. It describes the report’s file path{re.Add(key, Request.QueryString[key]);}}return re;} }//DataSet.cs public void AssignParameters(System.Collections.HashtablewebParameters) {foreach (RDL.QueryParameter param in this.Query.QueryParameters){string paramName = param.Name.Replace("@", "");//if this report param was passed as an arg to the report, then populate itif (webParameters[paramName] != null)param.Value = webParameters[paramName].ToString();} }

    運行查詢并填寫數據表

    這是很基本的。設置命令對象,添加參數,然后只需使用DataAdapter來填充表格。

    //DataSet.cs public System.Data.DataTable GetDataTable(string DBConnectionString) {System.Data.DataTable re = new System.Data.DataTable();using (System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter(this.Query.CommandText, DBConnectionString)){if (this.Query.QueryParameters.Count > 0){foreach (RDL.QueryParameter param in this.Query.QueryParameters){string paramName = param.Name.Replace("@", "");//OLEDB chokes on the @symbol, it prefers ? marksusing (System.Data.OleDb.OleDbCommand cmd = da.SelectCommand)cmd.CommandText = cmd.CommandText.Replace(param.Name, "?");using (System.Data.OleDb.OleDbParameterCollection params = da.SelectCommand.Parameters)switch (param.DataType){case "Text":params.Add(new OleDbParameter(paramName, OleDbType.VarWChar) { Value = param.Value });break;case "Boolean":params.Add(new OleDbParameter(paramName, OleDbType.Boolean) { Value = param.Value });break;case "DateTime":params.Add(new OleDbParameter(paramName, OleDbType.Date) { Value = param.Value });break;case "Integer":params.Add(new OleDbParameter(paramName, OleDbType.Integer) { Value = param.Value });break;case "Float":params.Add(new OleDbParameter(paramName, OleDbType.Decimal) { Value = param.Value });break;default:params.Add(new OleDbParameter(paramName, param.Value));break;}}}da.fill(re);re.TableName = this.Name;return re; }

    跟進(重構)

    我確實重構了這段代碼(在下載中),這使它有點混亂。我想讓它變得靈活,這樣我就可以在多個項目中使用它。由于我無法確定db連接字符串將始終是OLEDBSqlClient連接,因此我檢查了連接字符串并為其中任何一個使用了適當的庫集(OLEDB/SQLClient)。代碼長度增加了一倍,但更便攜。

    更新:導致錯誤的其他事情

    一位朋友幫我運行了一些測試報告,結果表明如果出現問題,該ReportViewer控件不會生成任何好的/有用的錯誤消息。相比之下,我放在View頁面的“Download”按鈕,在處理過程中很容易報錯。從中,我學到了一些東西:

  • 如果報表具有外部圖形或報表部件,則這些文件需要可用(也就是說,您也需要/reports文件夾中的這些文件)并且在正確的路徑中。對于我的測試示例,報告使用文件夾/Reports/Web Parts/中的圖形。
  • 如果報告具有必需的參數(或不是可選的),則必須提供這些參數,否則報告將不會運行。
  • 參數可以區分大小寫。也許它只是.NET。無論哪種方式,如果您的報告無法運行,請檢查以確保您提供的是PrintIDPrintId,而不僅僅是printid
  • 最后,我最近更新了這個示例以使用Visual Studio 2013運行。我添加了一個診斷頁面,以檢查一些設置。我改進了下載選項。我改進了這個例子來處理外部圖像,并檢測所需的報告參數。

    我希望你發現它對你更有效。如果沒有,我會很感激反饋,甚至可能是一個示例文件(.rdl),這樣我就可以解決任何錯誤。

    結論

    這就是從RDLC文件中提取查詢并在ASP.NET中運行它所需的全部內容。

    SSRS最初是由Microsoft編寫的,作為如何使用這些技術來完成我在此處展示的內容的示例。當然,SSRS的許多功能遠遠超出了我所展示的范圍,但如果您不需要所有這些豐富的功能,那么此代碼對于您和您的.NET項目來說應該是快速且可移植的。

    https://www.codeproject.com/Articles/607382/Running-a-RDL-RDLC-SQL-Report-in-ASP-NET-without-S

    總結

    以上是生活随笔為你收集整理的在没有SSRS的ASP.NET中运行RDL/RDLC(SQL报告)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。