Introduction
May be it’s my bad luck may be something else, but I didn’t find a complete post how to deploy Reports, and Data Sources in Reporting Services in away like BIDS.
First it’s a tool I developed to automate the deployment of BI solution (Creating Data warehouse, installing SSIS packages, creating Jobs, create Cubes and installing reports on Reporting Services Server).
Body
Herein, I'll talk about the last thing which is deploying reports. P.S: It's my way in designing such task (Installing reports on Reporting Services Server) and it's not standard or anything else just (follow your heart :)) Let's begin, I assume you, me, or anybody else has these 3 XML files one for folders, one for data sources and one for reports.
Name: Folder name to be created on Reporting Services.
ParentFolder: '/' means on the top == no parent folder.
Name
Folder
Description
HideInListView
Enabled
ConnectionString
Extension
CredentialRetrieval
WindowsCredentials
ImpersonateUser
ImpersonateUserSpecified
Prompt
UserName
Password
EnabledSpecified
Name: Data Source name to be created on Reporting Services.
Folder: The folder in which Data Source should be in, if we use '/' means on the top == no parent folder.
Description: Data Source Description.
HideInListView: True to hide it in the Reporting Services, otherwise False.
Enabled: True to be enabled, otherwise not enabled.
ConnectionString: Data Source connection string.
Extension: Configured according to the provider for more details see below table...
Provider | Extension |
Microsoft SQL Server | SQL |
OLE DB | OLEDB |
Microsoft SQL Server Analysis Services | OLEDB-MD |
Oracle | ORACLE |
ODBC | ODBC |
XML | XML |
SAP NetWeaver BI | SAPBW |
Hyperion Essbase | ESSBASE |
CredentialRetrieval: How Data Source will retrieve the credential.
WindowsCredentials: True to use Windows credential otherwise it'd use the credential provided in this XML (Username, and Password).
ImpersonateUser: Indicates whether the report server attempts to impersonate a user by using stored credentials after a data processing extension has established an authenticated connection to a data source.
ImpersonateUserSpecified: Gets or sets a value that indicates whether the ImpersonateUser property is specified.
Prompt: Gets or sets the prompt that the report server displays to the user when prompting for credentials.
UserName: Gets or sets the user name that the report server uses to connect to a data source.
Password: Sets the password that the report server uses to connect to a data source. Write-only.
EnabledSpecified: Gets or sets a value that indicates whether the Enabled property is specified.
More details on these properties
http://msdn.microsoft.com/en-us/library/reportservice2005.datasourcedefinition_properties.aspx
Name: Report Name.
Path: .RDL file path.
Folder: The folder in which Report should be in, if we use '/' means on the top == no parent folder.
DataSource: Report's Data Source name of Reporting Services. And these configuration keys
ReportsXMLFilePath: Reports' XML File Path
DataSourcesXMLFilePath: Data Sources' XML File Path
FoldersXMLFilePath: Folders' XML File Path
ReportingServerURL: URL of Reporting Services
Open visual studio and create a C# console application (we don't need any interaction with user everything configured in the application configuration file) From the project main menu Add Web Reference or Add Service Reference then Advanced then Add Web Reference...
URL: http://{Server-Name}/reportserver/ReportService.asmx
Web reference name: Give it meaningful name..
What we did is adding web service by which we can talk to Reporting Services to ask it to do something like (create report, create data source, etc...). Let's write some very simple C# code We have method called DeployReports this method calls 3 other methods in order (CreateFolders, CreateDataSources, and CreateReports)
private void DeployReports()
{
CreateFolders(
ConfigurationSettings.AppSettings["FoldersXMLFilePath"]);
CreateDataSources(
ConfigurationSettings.AppSettings["DataSourcesXMLFilePath"]);
CreateReports(Report.GetReports(
ConfigurationSettings.AppSettings["ReportsXMLFilePath"]));
}
private void CreateFolders(string folderXMLFilePath)
{
ReportingService reportingServicesClient =
new ReportingService();
reportingServicesClient.Credentials = System.Net.CredentialCache.DefaultCredentials;
XDocument xmlDoc = XDocument.Load(folderXMLFilePath);
try
{
var result = from c in xmlDoc.Descendants("Folder")
select new
{
name = (string)c.Element("Name").Value,
parentFolder = (string)c.Element("ParentFolder").Value
};
foreach (var row in result)
{
reportingServicesClient.CreateFolder(row.name, row.parentFolder, null);
Logging.Log(string.Format("Folder {0} created successfully", row.name));
}
}
catch (Exception er)
{
Logging.Log(er.Message);
}
}
}
private void CreateDataSources(string datasourceXMLFilePath)
{
ReportingService reportingServicesClient =
new ReportingService();
reportingServicesClient.Credentials = System.Net.CredentialCache.DefaultCredentials;
DataSourceDefinition tempDataSource;
XDocument xmlDoc = XDocument.Load(datasourceXMLFilePath);
try
{
var result = from c in xmlDoc.Descendants("DataSource")
select new
{
name = (string)c.Element("Name").Value,
folder = (string)c.Element("Folder").Value,
description = (string)c.Element("Description").Value,
hideInListView = (string)c.Element("HideInListView").Value,
enabled = (string)c.Element("Enabled").Value,
connectionString = (string)c.Element("ConnectionString").Value,
extension = (string)c.Element("Extension").Value,
credentialRetrieval = (string)c.Element("CredentialRetrieval").Value,
windowsCredentials = (string)c.Element("WindowsCredentials").Value,
impersonateUser = (string)c.Element("ImpersonateUser").Value,
impersonateUserSpecified = (string)c.Element("ImpersonateUserSpecified").Value,
prompt = (string)c.Element("Prompt").Value,
userName = (string)c.Element("UserName").Value,
password = (string)c.Element("Password").Value,
enabledSpecified = (string)c.Element("EnabledSpecified").Value
};
foreach (var row in result)
{
CredentialRetrievalEnum credentialRetrieval;
EnumConverter ec =
new EnumConverter(typeof(CredentialRetrievalEnum));
credentialRetrieval = (CredentialRetrievalEnum)ec.ConvertFromString(row.credentialRetrieval);
tempDataSource = new DataSourceDefinition();
tempDataSource.CredentialRetrieval = credentialRetrieval;
tempDataSource.ConnectString = row.connectionString;
tempDataSource.Enabled = bool.Parse(row.enabled);
tempDataSource.EnabledSpecified = bool.Parse(row.enabledSpecified);
tempDataSource.Extension = row.extension;
tempDataSource.ImpersonateUserSpecified = bool.Parse(row.impersonateUserSpecified);
tempDataSource.ImpersonateUser = bool.Parse(row.impersonateUser);
tempDataSource.Prompt = row.prompt;
tempDataSource.WindowsCredentials = bool.Parse(row.windowsCredentials);
if(!String.IsNullOrEmpty(row.userName))
tempDataSource.UserName = row.userName;
if(!String.IsNullOrEmpty(row.password))
tempDataSource.Password = row.password;
try
{
reportingServicesClient.CreateDataSource(row.name, row.folder, true, tempDataSource,
null);
Logging.Log(string.Format("Data Source {0} has created successfully", row.name));
}
catch (SoapException e)
{
Logging.Log(e.Detail.InnerXml.ToString());
}
}
}
catch (Exception er)
{
Logging.Log(er.Message);
}
}
private void CreateReports(Report[] reports)
{
ReportingService rsc =
new ReportingService();
rsc.Credentials = System.Net.CredentialCache.DefaultCredentials;
foreach (Report aReport in reports)
{
Byte[] definition = null;
Warning[] warnings = null;
try
{
FileStream stream = File.OpenRead(aReport.Path);
definition = new Byte[stream.Length];
stream.Read(definition, 0, (int)stream.Length);
stream.Close();
}
catch (IOException e)
{
Logging.Log(e.Message);
}
try
{
rsc.CreateReport(aReport.Name, aReport.Folder, true, definition, null);
#region Setting Report Data Source
DataSourceReference reference = new DataSourceReference();
reference.Reference = aReport.DataSource;
DataSource[] dataSources = new DataSource[1];
DataSource ds = new DataSource();
ds.Item = (DataSourceDefinitionOrReference)reference;
ds.Name = aReport.DataSource.Split(’/').Last();//I just need the name not the full path so I split the full name of the datasource by '/' then get the last part like /1/2/3/4/5 I just need 5
dataSources[0] = ds;
rsc.SetReportDataSources(aReport.Folder + "/" + aReport.Name, dataSources);//sets report to datasource
#endregion
if (warnings != null)
{
foreach (Warning warning in warnings)
{
Logging.Log(string.Format("Report: {0} has warnings", warning.Message));//logs if there's any warning in the report creation
}
}
else
Logging.Log(string.Format("Report: {0} created successfully with no warnings", aReport.Name));
}
catch (SoapException e)
{
Logging.Log(e.Detail.InnerXml.ToString());
}
}
}
Report\Logger Class will be attached in the Source code...
I don't see any tough code to explain any developer familiar with C# will understand it very well, but if you have any question please feel free to ask me.