报表服务部署

时间:2020-03-06 14:19:26  来源:igfitidea点击:

我需要创建一个可重复的过程来部署SQL Server Reporting Services报表。我不赞成使用Visual Studio和/或者Business Development Studio来执行此操作。脚本部署的rs.exe方法似乎也很笨拙。是否有人能以一种非常优雅的方式来部署报告。这里的关键是我希望流程完全自动化。

解决方案

我知道我们说我们不赞成Business Development Studio这样做,但是我发现内置工具非常可靠且易于使用。

好吧,不是很优雅。我们创建了自己的工具,该工具使用了reportservices2005 Web服务。我们发现这是获得我们想要的东西的最可靠的方法。

其实并没有那么困难,可以让我们扩展它来执行其他操作,例如根据需要创建数据源和文件夹。

我们是否研究过任何持续集成解决方案,例如CruiseControl.NET?如果我们能够使用rs.exe部署报表,则可以在CruiseControl中设置一个自动过程,以在计时器上或者在修改报表时生成和部署报表。

我们使用rs.exe,一旦我们开发了脚本,就不再需要接触它,它就可以工作。

这是源(我手动进行了一些稍微的修改,以删除敏感数据而没有机会对其进行测试,希望我没有做任何事情),它从子目录中为各种语言部署报告和相关图像。还将创建数据源。

'=====================================================================
'  File:      PublishReports.rss
'
'  Summary: Script that can be used with RS.exe to 
'           publish the reports.
'
'  Rss file spans from beginnig of this comment to end of module
' (except of "End Module").
'=====================================================================

Dim langPaths As String() = {"en", "cs", "pl", "de"}
Dim filePath As String = Environment.CurrentDirectory

Public Sub Main()

    rs.Credentials = System.Net.CredentialCache.DefaultCredentials

    'Create parent folder
    Try
        rs.CreateFolder(parentFolder, "/", Nothing)
        Console.WriteLine("Parent folder created: {0}", parentFolder)
    Catch e As Exception
        Console.WriteLine(e.Message)
    End Try

    PublishLanguagesFromFolder(filePath)

End Sub

Public Sub PublishLanguagesFromFolder(ByVal folder As String)
    Dim Lang As Integer
    Dim langPath As String

    For Lang = langPaths.GetLowerBound(0) To langPaths.GetUpperBound(0)
        langPath = langPaths(Lang)

        'Create the lang folder
        Try
            rs.CreateFolder(langPath, "/" + parentFolder, Nothing)
            Console.WriteLine("Parent lang folder created: {0}", parentFolder + "/" + langPath)
        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try

        'Create the shared data source
        CreateDataSource("/" + parentFolder + "/" + langPath)

        'Publish reports and images
        PublishFolderContents(folder + "\" + langPath, "/" + parentFolder + "/" + langPath)
    Next 'Lang
End Sub

Public Sub CreateDataSource(ByVal targetFolder As String)
    Dim name As String = "data source"

    'Data source definition.
    Dim definition As New DataSourceDefinition
    definition.CredentialRetrieval = CredentialRetrievalEnum.Store
    definition.ConnectString = "data source=" + dbServer + ";initial catalog=" + db
    definition.Enabled = True
    definition.EnabledSpecified = True
    definition.Extension = "SQL"
    definition.ImpersonateUser = False
    definition.ImpersonateUserSpecified = True
    'Use the default prompt string.
    definition.Prompt = Nothing
    definition.WindowsCredentials = False
    'Login information
    definition.UserName = "user"
    definition.Password = "password"

    Try
    'name, folder, overwrite, definition, properties 
        rs.CreateDataSource(name, targetFolder, True, definition, Nothing)
    Catch e As Exception
        Console.WriteLine(e.Message)
    End Try

End Sub

Public Sub PublishFolderContents(ByVal sourceFolder As String, ByVal targetFolder As String)
    Dim di As New DirectoryInfo(sourceFolder)
    Dim fis As FileInfo() = di.GetFiles()
    Dim fi As FileInfo

    Dim fileName As String

    For Each fi In fis
        fileName = fi.Name
        Select Case fileName.Substring(fileName.Length - 4).ToUpper
            Case ".RDL"
                PublishReport(sourceFolder, fileName, targetFolder)
            Case ".JPG", ".JPEG"
                PublishResource(sourceFolder, fileName, "image/jpeg", targetFolder)
            Case ".GIF", ".PNG", ".BMP"
                PublishResource(sourceFolder, fileName, "image/" + fileName.Substring(fileName.Length - 3).ToLower, targetFolder)
        End Select
    Next fi
End Sub

Public Sub PublishReport(ByVal sourceFolder As String, ByVal reportName As String, ByVal targetFolder As String)
    Dim definition As [Byte]() = Nothing
    Dim warnings As Warning() = Nothing

    Try
        Dim stream As FileStream = File.OpenRead(sourceFolder + "\" + reportName)
        definition = New [Byte](stream.Length) {}
        stream.Read(definition, 0, CInt(stream.Length))
        stream.Close()
    Catch e As IOException
        Console.WriteLine(e.Message)
    End Try

    Try
   'name, folder, overwrite, definition, properties 
        warnings = rs.CreateReport(reportName.Substring(0, reportName.Length - 4), targetFolder, True, definition, Nothing)

        If Not (warnings Is Nothing) Then
            Dim warning As Warning
            For Each warning In warnings
                Console.WriteLine(warning.Message)
            Next warning
        Else
            Console.WriteLine("Report: {0} published successfully with no warnings", targetFolder + "/" + reportName)
        End If
    Catch e As Exception
        Console.WriteLine(e.Message)
    End Try
End Sub

Public Sub PublishResource(ByVal sourceFolder As String, ByVal resourceName As String, ByVal resourceMIME As String, ByVal targetFolder As String)
    Dim definition As [Byte]() = Nothing
    Dim warnings As Warning() = Nothing

    Try
        Dim stream As FileStream = File.OpenRead(sourceFolder + "\" + resourceName)
        definition = New [Byte](stream.Length) {}
        stream.Read(definition, 0, CInt(stream.Length))
        stream.Close()
    Catch e As IOException
        Console.WriteLine(e.Message)
    End Try

    Try
    'name, folder, overwrite, definition, MIME, properties 
        rs.CreateResource(resourceName, targetFolder, True, definition, resourceMIME, Nothing)
        Console.WriteLine("Resource: {0} with MIME {1} created successfully", targetFolder + "/" + resourceName, resourceMIME)
    Catch e As Exception
        Console.WriteLine(e.Message)
    End Try
End Sub

这是调用rs.exe的批处理:

SET ReportServer=%1
SET DBServer=%2
SET DBName=%3
SET ReportFolder=%4

rs -i PublishReports.rss -s %ReportServer% -v dbServer="%DBServer%" -v db="%DBName%" -v parentFolder="%ReportFolder%" >PublishReports.log 2>&1

pause

我强烈推荐RSScripter。如概述中所述:

Reporting Services Scripter is a .NET
  Windows Forms application that enables
  scripting and transfer of all
  Microsoft SQL Server Reporting
  Services catalog items to aid in
  transferring them from one server to
  another. It can also be used to easily
  move items on mass from one Reporting
  Services folder to another on the same
  server. Depending on the scripting
  options chosen, Reporting Services
  Scripter can also transfer all catalog
  item properties such as Descriptions,
  History options, Execution options
  (including report specific and shared
  schedules), Subscriptions (normal and
  data driven) and server side report
  parameters.

我使用了@David提供的脚本,但是我不得不添加一些代码(我将其输入为答案,因为这对于注释来说太长了。

问题是:如果报表定义中已经有添加到报表的"共享数据源",则此数据源永远不会与脚本中创建的数据源相同。

从" CreateReport"方法发出的警告中也可以明显看出这一点:

The data set '' refers to the shared data source '', which is not published on the report server.

因此,之后必须显式设置数据源。我进行了以下代码更改:

我添加了一个全局变量:

Dim dataSourceRefs(0) As DataSource

在CreateDataSource方法的末尾,将填充该变量:

Dim dsr As New DataSourceReference
dsr.Reference = "/" + parentFolder + "/" + db
Dim ds As New DataSource
ds.Item = CType(dsr, DataSourceDefinitionOrReference)
ds.Name = db
dataSourceRefs(0) = ds

并在PublishReport方法中,显式设置该数据源(在调用CreateReport之后):

rs.SetItemDataSources(targetFolder + "/" + reportName.Substring(0, reportName.Length - 4), dataSourceRefs)

请注意,此最后一次调用仅是RS 2005或者更高版本。如果要将报告加载到RS 2000服务器上,则必须改为使用SetReportDataSources:

rs.SetReportDataSources(targetFolder + "/" + reportName.Substring(0, reportName.Length - 4), dataSourceRefs)