65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.45/5 (37投票s)

2004年12月27日

5分钟阅读

viewsIcon

784335

downloadIcon

2230

一个用于 SQL Reporting Services 的报表查看器页面,该页面仅使用其 SOAP API。

SQLRS - ReportViewer

目录

引言

此代码旨在为 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。这将检索基于给定参数值的可用值列表,以及每个参数的状态,该状态可以是:HasValidValueHasOutstandingDependenciesDynamicValuesUnavailableMissingValidValue

'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

渲染图像

通过将 DeviceInfoStreamRoot 参数设置为指向 GetImage.aspx,报表将所有图像引用该页面。我们将 reportstreamId 作为 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
    • 初始发布。
© . All rights reserved.