Automating Report Deployment with Reporting Services in SharePoint Integration Mode
Automating Report Deployment in Reporting Services can be challenging. SharePoint offers many modes of deployment of files. Unfortunately the out of the box deployment for SharePoint does not allow for automatic hook up of data sources. So you can deploy the rdl's using SPFile upload functions on the SPWeb of your choice but those rdls will exist without data sources. Here are the steps you will need to follow to deploy the reports automatically
1. Create the document library
2. Activate the Report Server Feature - no example but you'll need to check using something like SPContext.Current.Site.Features["367B94A9-4A15-42BA-B4A2-32420363E018"] != null
3. Add the reporting services content type to the document libraries
4. Add the data sources
5. Add the reports
6. Associate the data sources with the reports
Here is my report manager that is an excellent example of being able to add reports dynamically from the file system. In order to upload the report you'll need to call the ReportingServices2006 web service. The reports manager is accessed by the Feature Activator on a custom feature just to give you an idea of how you might drive this. The entry method is Deploy.
class RSHelper
{
public const string DOCLIBRARYNAME = "SomeLibrary";
string dataSourceName = "somedatasource" ;
ReportingService2006 rs;
string libraryUrl;
string path;
SPWeb web;
public void Deploy(string path, SPWeb web)
{
this.path = path;
this.web = web;
this.libraryUrl = string.Format("{0}/{1}/", web.Url, DOCLIBRARYNAME);
rs = new ReportingService2006();
rs.Url = web.Site.Url + "/_vti_bin/ReportServer/ReportService2006.asmx";
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
CreateReportsLibrary();
AddDataSourceToLibrary();
AddReportToLibrary();
}
private void CreateReportsLibrary()
{
Guid guid;
SPDocumentLibrary list = null;
//Not good practice but dictionary throws an exception when item not there.
foreach (object o in web.Lists)
{
SPDocumentLibrary tempLib = o as SPDocumentLibrary;
if (tempLib != null && tempLib.Title == DOCLIBRARYNAME)
{
list = tempLib;
break;
}
}
if (list == null)
{
guid = web.Lists.Add(DOCLIBRARYNAME, "", SPListTemplateType.DocumentLibrary);
list = web.Lists[guid] as SPDocumentLibrary;
}
//Add RS Content Types
(list).ContentTypesEnabled = true;
SPContentTypeId id;
SPContentType contentType;
id = new SPContentTypeId("0x010100C3676CDFA2F24E1D949A8BF2B06F6B8B");//rdl
contentType = web.AvailableContentTypes[id];
if (list.ContentTypes[contentType.Name] == null)
{
(list).ContentTypes.Add(contentType);
}
id = new SPContentTypeId("0x0101007DFDDF56F8A9492DAA9366B83A95B3A0");//rsds
contentType = web.AvailableContentTypes[id];
if (list.ContentTypes[contentType.Name] == null)
{
list.ContentTypes.Add(contentType);
}
id = new SPContentTypeId("0x010100D8704AF8ED734F4088724751E0F2727D");//model
contentType = web.AvailableContentTypes[id];
if (list.ContentTypes[contentType.Name] == null)
{
(list).ContentTypes.Add(contentType);
}
}
private void AddDataSourceToLibrary()
{
DataSourceDefinition dsd = new DataSourceDefinition();
dsd.CredentialRetrieval = CredentialRetrievalEnum.None;
dsd.ConnectString = "data source=.;initial catalog=someDB;Trusted_Connection=true";
dsd.Enabled = true;
dsd.EnabledSpecified = true;
dsd.Extension = "SQL";
dsd.ImpersonateUserSpecified = false;
//Use the default prompt string.
dsd.Prompt = null;
dsd.WindowsCredentials = false;
rs.CreateDataSource(dataSourceName+".rsds", libraryUrl, true, dsd, null);
}
private void AddReportToLibrary()
{
Byte[] definition = null;
Warning[] warnings = null;
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
FileStream stream = File.OpenRead(file);
definition = new Byte[stream.Length];
stream.Read(definition, 0, (int)stream.Length);
stream.Close();
string filename = file.Replace(path, "");
string parent = libraryUrl;
if (file.Contains("rdl"))
{
CatalogItem report = rs.CreateReport(filename, parent,
true, definition, null, out warnings);
AddDataSource(report);
}
else
{
string mime = "image/gif";
CatalogItem report = rs.CreateResource(filename, parent,
true, definition, mime, null);
}
if (warnings != null)
{
foreach (Warning warning in warnings)
{
Logger.Log(warning.Message);
}
}
else
Logger.Log(string.Format("Report: {0} created successfully " +
" with no warnings", file));
}
}
private void AddDataSource(CatalogItem report)
{
DataSourceReference reference = new DataSourceReference();
reference.Reference = string.Format("{0}{1}.rsds",libraryUrl,dataSourceName);
DataSource ds = new DataSource();
ds.Item = reference;
ds.Name = dataSourceName;
rs.SetItemDataSources(report.Path, new DataSource[] { ds });
}
}
Comments
Anonymous
January 31, 2008
The comment has been removedAnonymous
April 30, 2008
Its probably because your report is pointing to a datasource that doesn't exist yet. You need to make sure that DataSource1 is already created before you setitemdatasourcesAnonymous
June 16, 2008
Shawn Would it be possible for you to post a solution/ .cs file featuring this code on this site. I am unsure of the using statements required and any references needed regards owainAnonymous
June 16, 2008
Shawn, further to my earlier comment. These are my error messages. The type or namespace name 'ReportingService2006' could not be found (are you missing a using directive or an assembly reference?) The type or namespace name 'SPWeb' could not be found (are you missing a using directive or an assembly reference?) The type or namespace name 'CatalogItem' could not be found (are you missing a using directive or an assembly reference?) owainAnonymous
June 17, 2008
I had made a previous post with a small code sample on how to upload report deployment. Now I'm improvingAnonymous
June 17, 2008
I added a new post with sample code, please check that out, its automated based on an xml file. Let me know if you have any issues. please comment with your questions.Anonymous
June 04, 2009
I was unable to upload reports when using Forms based authentication. How would you pass the FBA credentials in using the code? Any help is appreciated. rs.Credentials = System.Net.CredentialCache.DefaultCredentials;Anonymous
June 04, 2009
That sounds like a tough one. I would say use a second alternate access mapping but sharepoint ssrs integration doesn't support two aam's. Have you looked at this article http://msdn.microsoft.com/en-us/library/bb975135.aspxAnonymous
June 11, 2009
Using the Authentication web service did the trick! Thanks for the help!Anonymous
July 18, 2009
I encountered the same DataSourceNotFoundException. The solution for me was by using the ReportServer.GetItemDataSources method on the report you are trying to hook up to the datasource file. It returns all the datasources referenced by the report. Go through the DataSources with invalid references (InvalidDataSourceReference) and fix them by setting the correct reference to the datasource file in each datasource. Here is the example private void AddDataSource(CatalogItem report, string dataSourceFileName) { DataSource[] referencedDataSources = rsClient.GetItemDataSources(report.Path); foreach (DataSource dataSource in referencedDataSources) { //Fix Invalid references to the DataSource of the Report. if (dataSource.Item.GetType().ToString() == typeof(InvalidDataSourceReference).ToString()) { DataSourceReference reference = new DataSourceReference(); reference.Reference = string.Format("{0}/{1}", docLibraryUrl, dataSourceFileName); dataSource.Item = reference; } } rsClient.SetItemDataSources(report.Path, referencedDataSources); }Anonymous
April 27, 2012
The comment has been removed