Pregunta Implementación de Reporting Services


Necesito crear un proceso repetible para implementar informes de SQL Server Reporting Services. No estoy a favor de usar Visual Studio o Business Development Studio para hacer esto. El método rs.exe de implementaciones de scripting también parece bastante torpe. ¿Alguien tiene una manera muy elegante que han podido implementar informes? La clave aquí es que quiero que el proceso esté completamente automatizado.


32
2017-09-17 23:35


origen


Respuestas:


Usamos rs.exe, una vez que desarrollamos el script no necesitamos tocarlo más, simplemente funciona.

Aquí está la fuente (la modifiqué ligeramente para eliminar datos confidenciales sin posibilidad de probarla, espero que no haya roto nada), despliega informes e imágenes asociadas desde subdirectorios para varios idiomas. También se crea el origen de datos.

'=====================================================================
'  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

Aquí está el lote para llamar al 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

32
2017-09-18 09:04



Utilicé el script @David suministrado pero tuve que agregar un código (estoy escribiendo esto como una respuesta, ya que esto sería demasiado largo para un comentario).

El problema es: si ya hay un "origen de datos compartido" adjunto a un informe en la definición del informe, este nunca es el mismo origen de datos que el creado en el script.

Esto también se hace evidente a partir de la advertencia emitida por el método "CreateReport":

El conjunto de datos '' se refiere a la fuente de datos compartidos '', que no está publicada en el servidor de informes.

Entonces la fuente de datos debe establecerse explícitamente después. Realicé los siguientes cambios de código:

Agregué una variable global:

Dim dataSourceRefs(0) As DataSource

Al final del método CreateDataSource, esa variable se llena:

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

Y en el método PublishReport, ese origen de datos se establece explícitamente (después de haber llamado a CreateReport):

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

Tenga en cuenta que esta última llamada es solo RS 2005 o superior. Si desea cargar sus informes en un servidor RS 2000, debe usar EstablecerInformeDataSources en lugar:

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

8
2018-05-03 15:39



Bueno, no muy elegante. Creamos nuestra propia herramienta que utiliza el servicio web reportingservices2005. Descubrimos que esta es la forma más confiable de obtener lo que queremos.

No es realmente tan difícil y le permite expandirlo para hacer otras cosas como crear fuentes de datos y carpetas según sea necesario.


1
2017-09-17 23:41



Lo recomiendo RSScripter. Como se menciona en el resumen:

Reporting Services Scripter es un .NET   Aplicación Windows Forms que habilita   scripting y transferencia de todos   Informes de Microsoft SQL Server   Artículos del catálogo de servicios para ayudar en   transfiriéndolos de un servidor a   otro. También se puede usar fácilmente   mover elementos en masa desde un informe   Carpeta de servicios a otra en el mismo   servidor. Dependiendo de las secuencias de comandos   opciones elegidas, Reporting Services   Scripter también puede transferir todo el catálogo   propiedades del elemento como Descripciones,   Opciones de historial, opciones de ejecución   (incluido el informe específico y compartido   horarios), Suscripciones (normal y   controlado por datos) y el informe del lado del servidor   parámetros.


1
2018-04-16 07:12



Sé que dices que no estás a favor del Business Development Studio para hacer esto, pero he descubierto que las herramientas integradas son muy confiables y fáciles de usar.


0
2017-09-17 23:38



¿Has investigado alguna solución de Integración Continua como CruiseControl.NET? Si puede implementar Informes utilizando rs.exe, puede configurar un proceso automatizado en CruiseControl para compilar e implementar sus Informes en un temporizador o cada vez que se modifique un informe.


0
2017-09-18 00:18