I recently created a SQL Server Reporting Services (SSRS) report which used a Stored Procedure as a datasource, but the report needed some extra customization we're getting by using PaxScript in a similar web page. This isn't easily achievable using SQL stored procedures, so I decided to use a web service instead as the data source for the report. This way I have the advantage of LINQ/C# and PaxScript. Also, we have a need to run different versions of the web service, each for a different client. So the data source's web service URL needs to be dynamic, rather than static.
Here's how it's done...
In the report Data Source properties, the Type is XML and the Connection string value is a Report Parameter:
Next, the report's Dataset Text should be in the following format:
Note: There is a Parameter for each Web Service method parameter with the correct Name and Type. The ElementPath value is derived partly from the WSDL and partly from the XML that the Web Service method returns:
From WSDL:
"GetPatientVentDataLinqResponse{}/GetPatientVentDataLinqResult{}"
from the Web Service returned XML.
"/PatientVentData{}/Result{ParameterName,ParameterData,UpdateTime}"
Here is the Web Service method:
01: [WebMethod]
02: public XmlDocument GetPatientVentDataLinq(string patientId,
03: string beginDate, string endDate, string deviceID, string userTimeZone) {
04: DataTable result = PatientController.GetVentData(true,
05: SafeCast.Int(patientId),
06: SafeCast.Date(beginDate),
07: SafeCast.Date(endDate),
08: SafeCast.Int(deviceID),
09: userTimeZone);
10: IEnumerable<DataRow> rows = result.AsEnumerable();
11: List<TReads[]> _reads = new List<TReads[]>();
12: foreach (DataColumn _col in result.Columns) {
13: if (_col.ColumnName.Contains("Column") ||
14: _col.ColumnName == "Parameter") {
15: var set = (from ro in rows
16: select new TReads (
17: ro.Field<string>(result.Columns[0].ColumnName),
18: (result.Columns.Contains(_col.ColumnName) ?
19: ro.Field<string>(_col.ColumnName) : null),
20: _col.Caption
21: )).OrderByDescending(o => o.UpdateTime);
22: _reads.Add(set.ToArray()); // ToArray() is to offset LINQ's deferred execution.
23: }
24: }
25: if (_reads.Count > 0) {
26: var re = from o in _reads
27: select o;
28: XElement xDoc =
29: new XElement("PatientVentData",
30: from x in re
31: select (
32: from t in x
33: where t.UpdateTime != "Parameter"
34: select new XElement("Result",
35: new XElement("ParameterName", t.ParameterName),
36: new XElement("ParameterData", t.ParameterData),
37: new XElement("UpdateTime", t.UpdateTime)
38: )
39: )
40: );
41: XmlDocument xmlDocument = new XmlDocument();
42: xmlDocument.LoadXml(xDoc.ToString());
43: return xmlDocument;
44: }
45: return GetEmptySet();
46: }
47:
Here is part the code that calls the Report Service:
(this segment of code establishes the Web Service URL relative to it's own URL and assigns it to the Report Parameters used to call the Report)
01: var url = Request.Url.AbsoluteUri;
02: var index = url.IndexOf(AppRelativeVirtualPath.Substring(1));
03: var webServiceUrl = url.Substring(0, index) + "/Services/BridgeTechVentHistory.asmx";
04:
05: ParameterValue[] parms = new ParameterValue[] {
06: new ParameterValue { Name = "patientID", Value = Request.QueryString[_requestString[0].Name] },
07: new ParameterValue { Name = "beginDate", Value = vdb.ToShortDateString() },
08: new ParameterValue { Name = "endDate", Value = vde.ToShortDateString() },
09: new ParameterValue { Name = "deviceID", Value = Request.QueryString[_requestString[3].Name] },
10: new ParameterValue { Name = "timeZone", Value = UserTimeZoneString },
11: new ParameterValue { Name = "webServiceUrl", Value = webServiceUrl }
12: };
Comments