SSRS RDL Mapping datasources programmatically - deployment

We are using rs.exe for deployment of RDLs to ReportServer.
As DataSource, Shared DataSet and RDLs reside in different folders.After deploying RDLs, mapping between RDL to Shared DataSets and Shared DataSets to DataSource are removed.
I have to map each RDL manually to the respective DataSets and DataSource. I have 200 RDLs and it's really hard to do manually.
I need code for Mapping RDLs to Datasets after deploying the RDLs
Could some body help with some code for my requirement?

I've created an rs.exe script that performs the following:
Deploys a report based on a file Report.rdl. The report has one reference to a Shared Data Source and one reference to a Shared DataSet. The report is deployed to the report server / directory.
Sets the Data Source for the report to an existing Shared Data Source on the report server. The Data Source is deployed as /Data Sources/DS.
Set the DataSet for the report to an existing Shared DataSet on the report server. The Data Source is deployed as /Datasets/DataSet.
The script contains the following code:
Public Sub Main()
Dim definition As [Byte]() = Nothing
Dim warnings As Warning() = Nothing
'Read report from file on disk
Dim stream As FileStream = File.OpenRead("Report.rdl")
definition = New [Byte](stream.Length - 1) {}
stream.Read(definition, 0, CInt(stream.Length))
stream.Close()
'Deploy report
'ItemType, name, folder, overwrite, definition, properties
rs.CreateCatalogItem("Report", "Report", "/", True, definition, Nothing, warnings)
'Update existing report Data Souce reference to Shared Data Source on server
Dim dataSourceRefs(0) As DataSource
Dim dsr As New DataSourceReference
dsr.Reference = "/Data Sources/DS"
Dim ds As New DataSource
ds.Item = CType(dsr, DataSourceDefinitionOrReference)
ds.Name = "DS"
dataSourceRefs(0) = ds
rs.SetItemDataSources("/Report", dataSourceRefs)
'Update existing report DataSet reference to Shared DataSet on server
Dim dataSetRefs(0) as ItemReference
Dim dset as New ItemReference
dset.Name = "DataSet"
dset.Reference = "/Datasets/DataSet"
dataSetRefs(0) = dset
rs.SetItemReferences("/Report", dataSetRefs)
End Sub
It sounds like you're already deploying the reports succesfully.
So, the main things to note are the code snippets that update the Data Source reference and the DataSet reference. The methods to note are:
SetItemDataSources to update the Data Source.
SetItemReferences to update the DataSet.
This is for one report, so you'll need to wrap up the code in a sub routine for your deployment script, but hopefully this will help you out.

Related

Crystal reports - server and database

Im using visual studio 2010 + Sql Server 2008.
Im trying to show my reports using CR.. well when i try to use the system in my local machine, everything is ok.
I use store procedures to create reports.
The issue appears when i deploy the system in another PC.. A message appears asking for:
Server: // RETRIEVES ORIGINAL Server(Local)// Its not Correct i need to get Client Server
Database: // RETRIEVES ORIGINAL DB(Local)// Its not Correct i need to get Client DB
Username: I don't use any user , what user ?
Password: I don't use any password, what password?
i saw another solutions, but i can't find what's the data that i must use in Username or password. i use Windows autenthication to login to sql..
Thanks.
Regards.
Edit.. that's my code.. i can't use parameters, i don't receive any error. but system dont recognize the parameter that i send...
Dim NuevoReporte As New CReportNotaPorUsuario
Dim contenido As String
Dim ReportPath As String = My.Application.Info.DirectoryPath & "\CReportNotaPorUsuario.rpt"
Dim ConexionCR As New CrystalDecisions.Shared.ConnectionInfo()
contenido = Servicios.Funciones_Auxiliares.LeerArchivo(My.Application.Info.DirectoryPath & "\configuracion.txt")
ConexionCR.ServerName = Servicios.Funciones_Auxiliares.TextoEntreMarcas(contenido, "<server>", "</server>")
ConexionCR.DatabaseName = Servicios.Funciones_Auxiliares.TextoEntreMarcas(contenido, "<catalog>", "</catalog>")
ConexionCR.IntegratedSecurity = True
CrystalReportViewer1.ReportSource = ReportPath
'NuevoReporte.SetParameterValue("#cod_usuario", cbousuario.SelectedValue)
Dim field1 As ParameterField = Me.CrystalReportViewer1.ParameterFieldInfo(0)
Dim val1 As New ParameterDiscreteValue()
val1.Value = cbousuario.SelectedValue
field1.CurrentValues.Add(val1)
SetDBLogonForReport(ConexionCR)
It appears that you have separate servers and databases between the development and production environment. You need to make sure when you deploy your VS solution that the production server and database get referenced, not the development server and database.
There are some tutorials out there that can help you find a way to achieve this. Check out:
http://msdn.microsoft.com/en-us/library/dd193254(v=vs.100).aspx
Visual Studio 2010 Database Project Deploy to Different Environments
http://www.asp.net/web-forms/tutorials/deployment/advanced-enterprise-web-deployment/customizing-database-deployments-for-multiple-environments
EDIT: This seems to have evolved into a different issue than originally stated in the question. To dynamically get the connection string for CR from the text file, you will have to read teh text file first and put server name and database name into variables. Reading a text file, you can use something like string text = File.ReadAllText(#"C:\Folder\File.txt"); but you will need to extract server name and database name into variables. Then in order to use the variables in your connection string you use ConnectionInfo.Servername = variable1; and ConnectionInfo.DatabaseName = variable2.

SSRS ReportingService2010 change embedded DataSource to shared DataSource

I have SQL Server 2008 with SSRS installed on one server and SQL Server 2008 R2 with SSRS installed on a new server. I want to migrate 200+ reports as well as a few shared schedules and a couple data sources from the first server to the second one using the SSRS web service API. For simplicity sake since there are only a couple of shared data sources I went ahead and created those using the Report Manager interface.
Unfortunately, those who came before me embedded the data source information in each report (connection string, login, password, etc). I thought this would be a great time to change these to point to the shared data source so this would not have to be done for each report, one by one. I can create the reports on the new server just fine using CreateCatalogItem but I can't seem to determine how to properly go about changing from an embedded data source to a shared data source.
So far I have tried both SetItemReferences:
itemRef.Reference = "/Data Sources/TMS";
itemRef.Name = "TMS";
itemRef.Reference = "/Data Sources/TMS";
rs2010.SetItemReferences(catItem.Path, new ReportService2010.ItemReference[] { itemRef });
and SetItemDataSources:
ReportService2010.DataSourceReference dataSourceRef = new ReportService2010.DataSourceReference();
dataSourceRef.Reference = "/Data Sources/TMS";
ReportService2010.DataSource dataSource = new ReportService2010.DataSource();
dataSource.Name = "TMS";
dataSource.Item = dataSourceRef;
rs2010.SetItemDataSources(catItem.Path, new ReportService2010.DataSource[] { dataSource });
Both methods result in a "NotFoundException" when attempted on a report with an embedded data source but they both work just fine on reports that are already pointing to a shared data source.
Furthermore, I have searched all over Google as well as StackOverflow for a solution but have found nothing. Can anyone point me in the right direction here?
So I kept working with the SetItemReferences method and had a brilliant idea that ended up working. The final code I used is below:
List<ReportService2010.ItemReference> itemRefs = new List<ReportService2010.ItemReference>();
ReportService2010.DataSource[] itemDataSources = rs2010.GetItemDataSources(catItem.Path);
foreach (ReportService2010.DataSource itemDataSource in itemDataSources)
{
ReportService2010.ItemReference itemRef = new ReportService2010.ItemReference();
itemRef.Name = itemDataSource.Name;
itemRef.Reference = "/Data Sources/TMS";
itemRefs.Add(itemRef);
}
rs2010.SetItemReferences(catItem.Path, itemRefs.ToArray());
The problem was that I was not using the same DataSource name as what was found in the report .rdl file. I was able to determine what the name should be using the GetItemDataSources method. Since this method returns an array and may have more than one item in said array, I looped through it to create multiple ItemReferences if more than one existed though I doubt that happens very often if at all.

Accessing File-Stream Data Methods (T-SQL and Managed API)

I have "File-Stream" enabled database. I have created table with column that has the "file-stream" attribute and manage to record successfully row in the table. So, what I have got is image stored in my "File-Stream" as BLOB.
What is my problem?
I have to get this image and show it in the web browser using classic asp (I am total newbie in this server-language and I am not allowed to use the asp.net). I have searched and read a lot (there are many information about doing that with asp.net and almost nothing showing how to do this with classic asp) and found a article (http://www.simple-talk.com/sql/learn-sql-server/an-introduction-to-sql-server-filestream/) that shows to ways to read the data:
"Accessing FILESTREAM Data using TSQL" and "Accessing FILESTREAM data with Managed API"
The first one I have been able to understand and use. The second one (there is a example with vb.net code) I haven't been able.
This is the code:
‘Create a connection to the database
Dim ConStr As String
ConStr = "Data Source=JACOBXPS\katmaifs;Initial Catalog=NorthPole" & _
";Integrated Security=True"
Dim con As New SqlConnection(ConStr)
con.Open()
'Retrieve the FilePath() of the image file
Dim sqlCommand As New SqlCommand()
sqlCommand.Connection = con
sqlCommand.CommandText = "SELECT ItemImage.PathName() AS PathName " + _
"FROM items WHERE ItemNumber = 'MS1001'"
Dim filePath As String = sqlCommand.ExecuteScalar()
'Obtain a Transaction Context
Dim transaction As SqlTransaction = con.BeginTransaction("ItemTran")
sqlCommand.Transaction = transaction
sqlCommand.CommandText = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()"
Dim txContext As Byte() = sqlCommand.ExecuteScalar()
' Open and read file using SqlFileStream Class
Dim sqlFileStream As New SqlFileStream(filePath, txContext, FileAccess.Read)
Dim buffer As Byte() = New Byte(sqlFileStream.Length) {}
sqlFileStream.Read(buffer, 0, buffer.Length)
'Bind the image data to an image control
Dim ms As MemoryStream = New MemoryStream(buffer)
Dim bmp As Bitmap = New Bitmap(ms)
ItemImage.Image = bmp
'Cleanup
sqlFileStream.Close()
sqlCommand.Transaction.Commit()
con.Close()
I was not able to transform this in classic asp but in the same article I have read something more frustrating:
When accessing FILESTREAM data using TSQL, SQL Server reads the content of the >FILESTREAM data file and serves it to the client. SQL Server memory is used for reading >the content of the data file. Accessing FILESTREAM data using Win32 Streaming does not >use SQL Server memory. In addition it allows the application to take advantage of the >Streaming capabilities of the NT File System.
So what is my real problem?
Can be the vb.net code transform and used in a classic asp?And if it can, does that mean that when I am using the "file-stream" enable futures and want to display data in the web it will be more slow then using desktop application?
I am pretty confused and will appreciate any answer or link with article to read.
A little confused on the question but if all you're trying to do is display some BLOB data from the database as an Image on the webpage then you should have an "image.asp" page that looks something like this ...
SQL = "SELECT FILE_NAME,IMAGE_FILE FROM tblImages WHERE ID = " & request("id")
Set rs =db.Execute( SQL )
if not(rs.eof) then
Response.ContentType = "application/octet-stream"
Response.AddHeader "Content-Disposition", "attachment;filename=" & rs("FILE_NAME")
Response.BinaryWrite rs("IMAGE_FILE")
else
response.Write("No such record found in the database at row " & request("id"))
end if

Dynamically changing CSV data source using ApplyLogOnInfo

I have a .rpt file that I have created by setting it's data source as a text (csv) file using the (Access/Excel (DAO) ) option.
Now I want the same .rpt file loaded using a C# code and each time my C# code will change the input file and I want a new report to be generated based on the data in the new text file.
I am doing the following code and when I export the file to a pdf document, it still displays the data according to the data in the old input file.
I have checked off the option in the .rpt file that says "save data with report" and "verify on first refresh".
What am I missing here?
CODE:
cryRpt = new ReportDocument();
cryRpt.Load(reportfile);
Tables tables = cryRpt.Database.Tables;
TableLogOnInfo tableLogonInfo;
foreach (Table table in cryRpt.Database.Tables)
{
tableLogonInfo = table.LogOnInfo;
tableLogonInfo.TableName = "MYdata_BS_NEW#csv";
table.Location = "MYdata_BS_NEW#csv";
table.ApplyLogOnInfo(tableLogonInfo);
}
cryRpt.Refresh();
// After this I export the report to pdf document.

Reporting Services Deployment

I need to create a repeatable process for deploying SQL Server Reporting Services reports. I am not in favor of using Visual Studio and or Business Development Studio to do this. The rs.exe method of scripting deployments also seems rather clunky. Does anyone have a very elegant way that they have been able to deploy reports. The key here is that I want the process to be completely automated.
We use rs.exe, once we developed the script we have not needed to touch it anymore, it just works.
Here is the source (I slightly modified it by hand to remove sensitive data without a chance to test it, hope I did not brake anything), it deploys reports and associated images from subdirectories for various languages. Also datasource is created.
'=====================================================================
' 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
Here is the batch to call the 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
I used the script #David supplied but I had to add some code (I'm typing this up as an answer, as this would be too long for a comment.
The problem is: if there is already a "shared datasource" attached to a report in the report definition, this is never the same datasource as the one that is created in the script.
This also becomes apparent from the warning emitted by the "CreateReport" method:
The data set '' refers to the shared data source '', which is not published on the report server.
So the data source has to be set explicitly afterwards. I've made the following code changes:
I added a global variable:
Dim dataSourceRefs(0) As DataSource
At the end of the CreateDataSource method, that variable gets filled:
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
And in the PublishReport method, that data source gets explicitly set (after CreateReport has been called):
rs.SetItemDataSources(targetFolder + "/" + reportName.Substring(0, reportName.Length - 4), dataSourceRefs)
Note that this last call is only RS 2005 or higher. If you want to load your reports onto a RS 2000 server, you have to use SetReportDataSources in stead:
rs.SetReportDataSources(targetFolder + "/" + reportName.Substring(0, reportName.Length - 4), dataSourceRefs)
Well not really elegant. We created our own tool that uses the reportingservices2005 web service. We found this to be the most reliable way of getting what we want.
It's not really that difficult and lets you expand it to do other things like creating data sources and folders as required.
I strongly recommend RSScripter. As noted in the overview:
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.
I know you say that you're not in favor of the Business Development Studio to do this, but I've found the built-in tools to be very reliable and easy to use.
Have you looked into any Continuous Integration solutions such as CruiseControl.NET? If you are able to deploy Reports using rs.exe then you can setup an automated process in CruiseControl to build and deploy your Reports on a timer or whenever a report is modified.
In our environment, we develop in VS with version control then deploy to DEV SSRS. Once the report is validated, we use ReportSync program to deploy reports from ReportServer DEV to ReportServer PROD. The RS.EXE scripts still have their place, but I have found ReportSync to be a much simpler and agile way to promote a report.
ReportSync:
ReportSync is an open source program free to download and use. It works great for downloading reports in bulk, and it can even push a report from one server to another server.
How to get download the program?
Download the source code files from Github: Phires/ReportSynch, Run VS, Open the solution file (.SLN), compile the program, find the executable file (.EXE) from the C:\Temp\reportsync-master\bin\Release folder. Finally, saved the .EXE somewhere for you to use regularly
How do I copy SSRS reports to a new server if I am not the owner of the reports --> ReportSync answer by nunespascal
How to deploy a report?
Run the executable and the interface will launch.
Use the SOURCE and DESTINATION dialogues to choose a single report, multiple reports, or an entire folder of reports. You can any target folder you would like. (HINT: You can even target the same server if you are wanting to duplicate a report on the same server.)
After making your selections press the Sync button
Go to the target server, and validate the change took effect by reviewing the Changed By Date.
This tool has been very convenient, but I have noticed some quirks. For example when I want to update just one report that already exists in the destination, here is what I have to select-- [Source:Report> Target:Folder> Sync]. WARNING: You might think you would select the target server report to update it, but I have tried this and the report does not get updated.
What else can ReportSync do?
There is also an Export feature, which works marvelously for simply dumping all the RDL files to a folder for me to access. This is helpful in the event you need to migrate the server, add the files to to a VS Solution Project, or do anything else will all the files.
In my testing this program does not migrate other content-- subscriptions, shared data sources, shared data sets. It is just applicable to the report files.
I know this post is old, but I came across it when researching RS.EXE scripts, so I thought I would provide an answer this question.