使用 SOAP API 的 SQL Reporting Services 查看器页面






4.45/5 (37投票s)
2004年12月27日
5分钟阅读

784335

2230
一个用于 SQL Reporting Services 的报表查看器页面,该页面仅使用其 SOAP API。
目录
引言
此代码旨在为 SQL Reporting Services 查看器提供一个起点,该查看器仅使用 SOAP API 进行渲染。如果格式为 HTML,则此报表将作为 HTML 片段嵌入到调用页面中,并且不使用 IFRAME。这是对 URL 报表访问或使用 RS 安装附带的示例报表查看器 Web 服务器控件的替代方案。
如果您正在寻找更多关于如何将报表及其参数集成到您可能使用与 Reporting Services 不同的身份验证方法的 Web 应用程序中的方法,这篇文章将对您有所帮助,通常如果您想要比 ReportViewer Web 服务器控件已有的功能更多的功能。所有参数提示都是动态创建的,您可以轻松地应用不同的格式,甚至隐藏其中的一些。
先决条件
- 我假设您熟悉 SQL Reporting Services、它们是什么、设计和安装。有关此主题的更多信息,请单击此处。
- 您应该已经安装了 SQL Reporting Services,并且知道 WSDL 的地址。
- 您还应该安装了 SQL Reporting Services 示例报表或有其他可用报表。
架构
本项目包含两个 ASP.NET (VB.NET) 页面
- ReportViewer.aspx,它显示 SQL Reporting Services 报表,以及所有相关的提示和缩放/格式选项。
- GetImage.aspx,它将渲染与报表关联的任何图像。可以通过 SQL Reporting Services WSDL 的 Web 服务代理类来访问 Reporting Services。浏览器没有直接调用报表服务器。报表名称、报表服务器 WSDL 地址、用户名和密码在页面类的属性中硬编码。我在这里概述了报表查看器页面、代码隐藏和图像渲染页面,以提供概念和原因。您也可以在 VS 中打开项目并直接查看代码,因为我添加了尽可能多的注释。
报表查看器页面
所有报表提示将在页面加载事件中动态创建。因此,我们只需要在网页中放置将托管它们的占位符。这是 HTML 代码
<%@ Page Language="vb" AutoEventWireup="false"
Codebehind="ReportViewer.aspx.vb"
Inherits="SQLRS_ReportViewer.ReportViewer"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>ReportViewer</title>
<meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
<LINK href="Styles.css" type="text/css" rel="stylesheet">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="get" runat="server">
<input type="hidden" name="Report" id="Report" runat="server">
<TABLE id="TablePrompts" runat="server"
class="MenuBarBkGnd ParamsGrid" width="550"></TABLE>
<div id="ReportPlaceholder" runat =server></div>
</form>
</body>
</HTML>
代码后台
首先,我们调用 GetReportParameters
方法来获取参数列表。ForRendering
参数设置为 False
。
reportParametersArray =
rs.GetReportParameters(reportPath, Nothing, False, Nothing, Nothing)
如果报表有任何关联的参数,我们将创建一个动态的 ParameterValue
数组来收集它们的值。它们可能来自三个来源:URL 参数、上一页提交或报表定义内部。值为空的参数不会存储在此数组中。我们使用此数组再次调用 GetReportParameters
方法,这次将 ForRendering
参数设置为 True
。这将检索基于给定参数值的可用值列表,以及每个参数的状态,该状态可以是:HasValidValue
、HasOutstandingDependencies
、DynamicValuesUnavailable
或 MissingValidValue
。
'hash table with dependecies
Dim Dependencies As New System.Collections.Hashtable
'we need a dynamic array for storing parameter values
Dim reportParameterValues As ArrayList
If reportParametersArray.Length > 0 Then
reportParameterValues = New ArrayList
'loop over each parameter and build the array of values
For Each parameter As ReportParameter In reportParametersArray
Dim value As ParameterValue = New ParameterValue
value.Name = parameter.Name
value.Label = parameter.Name
'if the report value is coming from URL or previous submission
'then it is part of the Request
If Not Request(Parameter.Name) Is Nothing Then
'set the value from URL or submission
value.Value = Request(Parameter.Name)
ElseIf Not Parameter.DefaultValues Is Nothing Then
'set the value to the one defined inside report
value.Value = Parameter.DefaultValues(0)
Else
'in this case we dont have a value for this parameter
'we cannot render this report
value.Value = ""
reportCanBeRendered = False
End If
If value.Value <> "" Then
reportParameterValues.Add(value)
End If
'check if this parameter is dependent of another one
If Not (parameter.Dependencies Is Nothing) Then
For Each d As String In parameter.Dependencies
'add the parameter as a dependecy if was not already added
If Not Dependencies.Contains(d) Then
Dependencies.Add(d, Nothing)
End If
Next
End If
Next 'from: For Each Parameter As ReportParameter In Parameters
'Get the list of parameters this time specifying to
'render the report (ForRender set to true)
'valid values for these parameters will be populated
reportParametersArray =
rs.GetReportParameters(reportPath, Nothing, True, _
reportParameterValues.ToArray(GetType(ParameterValue)), Nothing)
然后我再次遍历参数数组并动态构建提示的 HTML。我使用 HTML 控件而不是 ASP Web 控件,因为这样在表单提交时可以更轻松地捕获值。在循环中,将根据 Parameter.State
属性的值确定是否可以渲染报表。某些参数可能依赖于其他参数,并且可能尚未指定它们的有效值。
Dim i As Integer = 0
For Each parameter As ReportParameter In reportParametersArray
' if any of parameters doesnt have valid values the
' report cannot be rendered
If parameter.State <> ParameterStateEnum.HasValidValue Then
reportCanBeRendered = False
End If
If parameter.DefaultValues(0) =
"" And parameter.AllowBlankSpecified And Not parameter.AllowBlank Then
reportCanBeRendered = False
End If
If parameter.DefaultValues(0) Is Nothing And _
parameter.NullableSpecified And Not parameter.Nullable Then
reportCanBeRendered = False
End If
If i Mod 2 = 0 Then
TR = New System.Web.UI.HtmlControls.HtmlTableRow
End If
'set the propmt text
TD = New System.Web.UI.HtmlControls.HtmlTableCell
TD.InnerHtml = Parameter.Prompt
TR.Controls.Add(TD)
'set the prompt input control
TD = New System.Web.UI.HtmlControls.HtmlTableCell
Dim promptType As String = "textbox"
If Parameter.ValidValuesQueryBased Then
promptType = "dropdown"
End If
If Not parameter.ValidValues Is Nothing Then
If parameter.ValidValues.Length > 1 Then
promptType = "dropdown"
End If
End If
Select Case promptType
Case "dropdown"
'in this case we set a drop down select list
S = New System.Web.UI.HtmlControls.HtmlSelect
S.ID = Parameter.Name
S.Name = Parameter.Name
If Not Parameter.ValidValues Is Nothing _
And Parameter.ValidValues.Length > 0 Then
If Parameter.State =
ParameterStateEnum.MissingValidValue Or
Parameter.State =
ParameterStateEnum.HasOutstandingDependencies Then
reportCanBeRendered = False
LI =
New System.Web.UI.WebControls.ListItem("<Select a Value>", "")
S.Items.Add(LI)
End If
For Each vv As ValidValue In Parameter.ValidValues
LI = New System.Web.UI.WebControls.ListItem(vv.Label, vv.Value)
'see if this value is the same with the default value
'in which case we make the current list item selected
If vv.Value = parameter.DefaultValues(0) And Parameter.State =
ParameterStateEnum.HasValidValue Then
LI.Selected = True
End If
S.Items.Add(LI)
Next
End If
'check if this parameter have dependencies.
'If it does then we need to reload the page to
'reload the value of dependent params
If Dependencies.Contains(Parameter.Name) Then
S.Attributes.Add("OnChange", "this.form.submit();return true")
End If
TD.Controls.Add(S)
Case "textbox"
'in this case we set an input text box
T = New System.Web.UI.HtmlControls.HtmlInputText
T.ID = Parameter.Name
T.Name = Parameter.Name
If parameter.DefaultValues.Length > 0 Then
T.Value = Parameter.DefaultValues(0)
End If
TD.Controls.Add(T)
End Select
TR.Controls.Add(TD)
'add this row to the table
If i Mod 2 = 1 Then
TablePrompts.Controls.Add(TR)
End If
i += 1
Next 'from: For Each Parameter As ReportParameter In Parameters
If i Mod 2 = 1 Then
TablePrompts.Controls.Add(TR)
End If
End If
最后一步是根据 format
参数渲染报表并将其显示在页面上。如果格式为 HTML4.0 或 HTML3.2,则我们构建一个特定的 DeviceInfo
参数。StreamRoot
参数应指向 GetImage.aspx 页面。这一点非常重要
Dim streamRoot As String
streamRoot = "getimage.aspx?report=" & reportPath & "&streamid="
Select Case format
Case "HTML4.0", "HTML3.2"
deviceInfo = "<DeviceInfo>"
deviceInfo &= "<StreamRoot>" & streamRoot & </StreamRoot>"
deviceInfo &= "<Toolbar>False</Toolbar>"
deviceInfo &= "<Parameters>False</Parameters>"
deviceInfo &= "<HTMLFragment>True</HTMLFragment>"
deviceInfo &= "<StyleStream>False</StyleStream>"
deviceInfo &= "<Section>0</Section>"
deviceInfo &= "<Zoom>" & zoom & "</Zoom>"
deviceInfo &= "</DeviceInfo>"
Case Else
deviceInfo = "<DeviceInfo></DeviceInfo>"
End Select
下面是如何渲染和显示报表
Dim credentials As DataSourceCredentials() = Nothing
Dim showHideToggle As String = Nothing
Dim encoding As String
Dim mimeType As String
Dim warnings As Warning() = Nothing
Dim reportHistoryParameters As ParameterValue() = Nothing
Dim historyID As String = Nothing
Dim streamIDs As String() = Nothing
Dim sh As New SessionHeader
rs.SessionHeaderValue = sh
Dim result As Byte() = Nothing
'prepare report parameters array.
Dim reportParameterValues2 As ParameterValue() = Nothing
If Not reportParameterValues Is Nothing Then
reportParameterValues2 =
reportParameterValues.ToArray(GetType(ParameterValue))
End If
result = rs.Render(reportPath, format, historyID, deviceInfo, _
reportParameterValues2, credentials, showHideToggle, _
encoding, mimeType, reportHistoryParameters, warnings, _
streamIDs)
'store ReportingServices and parameters object is session
'layer in case we need it for image streams
Session("rs") = rs
Session("reportParameterValues") = reportParameterValues2
Select Case format
Case "HTML4.0", "HTML3.2"
Dim enc As System.Text.Encoding = System.Text.Encoding.UTF8
'get the report as a string
Dim tmpReport As String = enc.GetString(result)
'replace all occurrences of report server link with
'current page link
tmpReport =
tmpReport.Replace(reportServerURL.Replace("/ReportService.asmx", "?"),_
"http://" & Request("SERVER_NAME") _
& Request("SCRIPT_NAME") & "?Report=")
ReportPlaceholder.InnerHtml = tmpReport
Case Else
Response.ClearContent()
Response.AppendHeader("content-length", _
result.Length.ToString())
Response.ContentType = mimeType
Response.BinaryWrite(result)
Response.Flush()
Response.Close()
End Select
渲染图像
通过将 DeviceInfo
的 StreamRoot
参数设置为指向 GetImage.aspx,报表将所有图像引用该页面。我们将 report
和 streamId
作为 URL 参数传递。对于其他所有内容,我们可以使用会话层。以下是 GetImage.aspx 的代码隐藏
Private Sub Page_Load(_
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
Dim reportPath As String = Server.UrlDecode(Request("report"))
Dim streamID As String = Request("streamid")
Dim rs As ReportingService = Session("rs")
Dim encodingImage As String
Dim mimeTypeImage As String
Dim image As Byte()
image =
rs.RenderStream(reportPath, "HTML4.0", streamID, _
Nothing, Nothing, Session("reportParameterValues"), _
encodingImage, mimeTypeImage)
Response.Clear()
Response.ContentType = mimeTypeImage
Response.AppendHeader("content-length", image.Length.ToString())
Response.BinaryWrite(image)
Response.Flush()
Response.Close()
End Sub
Using the Code
要按原样使用此代码,您应该将其作为 ASP.NET 应用程序安装在 Web 服务器上的某个位置。然后修改代码隐藏中找到的以下变量
Private reportServerURL As String =
"http://yourServer/ReportServer/ReportService.asmx"
Private reportPath As String = "/SampleReports/Product Line Sales"
Private reportUser As String = "user"
Private userPassword As String = "password"
Private domain As String = "DOMAIN"
在 reportUser
中指定的用户名应该有权访问远程报表服务器上的报表。报表也可以作为 URL 参数指定,以及任何其他报表参数
https:///SQLRS-ReportViewer/ReportViewer.aspx?
Report=%2FSampleReports%2FProduct+Line+Sales& _
ProductCategory=4&ProductSubCategory=26
要在其他应用程序中使用此代码
- 将
Page_Load
的整个逻辑复制到您的页面或用户控件中。 - 将 ReportingService.vb 作为现有项添加到您的项目中。
- 将 GetImage.aspx 页面添加到您的项目中,并确保
deviceInfo
结构中的StreamRoot
指向它。 - 导入或修改 Styles.css 中的样式
要点
我认为最有趣的一点是我们如何重建参数提示。这为自定义这些提示打开了大门,例如,为 DateTime
参数设置一个 Calendar
控件,隐藏一些报表参数,或者在后台提供值。我目前将其用于最后一个原因,即我有一个带有几个参数的报表,其中一个参数是用户 ID。我显然不希望用户被提示输入该 ID,因此在构建提示时,我会遍历除 UserID
之外的所有参数。在构建 reportParameterValues
时,我仍然为其指定值。
已知限制
到目前为止,代码不执行验证。这意味着如果您为不允许空值的字段提交空值,代码将不会显示任何验证消息。此时的另一个限制是,除 HTML 以外的其他格式将在同一页面中渲染,而不是在新版本的 Internet Explorer 中。
结论
SQL Reporting Services 可用于构建报表并在完全独立的应用程序中显示它们。只需付出一点额外的努力,就可以根据需要自定义参数提示。
历史
- 02/21/2005
- 修复了关于没有参数的报表的 bug。
- 02/07/2005
- 增加了对依赖参数的支持
- 更改了图像和所有其他流的处理方式。感谢 Bart Fibrich。
- 01/27/2005
- 增加了对钻取链接的支持,作为
ReplacementRoot
设备设置的替代方案。
- 增加了对钻取链接的支持,作为
- 12/27/2004
- 初始发布。