Jul 22

This article describes how to render a list of data sources and dataset's from with a Report Definition (.RDL) file, while using the SQL Server Reporting Services Web Services. You will find a dowload of the code at the end of the article.

This article assumes you have the following:

  • SQL Server 2008 and Reporting Services installed
  • Microsoft Visual Studio 2008 installed
  • Experience with Reporting Services 2005/2008 
  • Experience with ASP.NET and C#
  • Experience with the Reporting Services SOAP API

Steps Taken:

  1. Create ASP.NET Web Application
  2. Reference Reporting Services Web Services SOAP API
  3. Add Web Form
  4. Reference required namespaces  
  5. Create code for both ListReportDataSource and ListReportDataset
  6. Run code 

Create ASP.NET Web Application

1) Open Microsoft Visual Studio 2008 from Start >> All Programs >> Microsoft Visual Studio 2008 >> Microsoft Visual Studio 2008

2) From the menubar, select File >> New >> Project

reporting builder 2.0

3) Expand the C# node and select the Web child node.

4) From the template pane, select ASP.NET Web Application.

5) Name the project "RSIntegrationDemo".

reporting builder 2.0

6) Click OK.

Reference Reporting Services SOAP API

1)  From within your Solution Explorer pane, right click on the project name and select Add Web Reference... to create a new web services reference.

reporting builder 2.0

2) For URL: enter "http://localhost/reportserver/ReportService2005.asmx?wsdl" (replace localhost with your server name, if different).

3) For Web Reference Name: enter RS2005.

reporting builder 2.0

4) Click Add Reference button.

You will notice a new folder named Web References with RS2005 reference located within the folder.

reporting builder 2.0

 You have completed referencing the Reporting Services WSDL

 Add Web Form

1) Create a new Web Form and name it "RSDataset.aspx".

Reference Namespaces

1) Open the RDLUpload.aspx.cs and add the following additional namespaces: 

using System.Web.Services.Protocols; // protocols used to transmit data across the wire using ASP.NET

using RSIntegrationDemo.RS2005; // your wsdl reference

//used for ListReportDataset

using System.Xml;

using System.Xml.XPath;

using System.IO;

Adding the Data Source Code

The ListReportDataSource method will return all data sources within a report, by using the GetItemDataSources method, within the Reporting Services SOAP API. The custom method ListReportDataSource takes one parameter - ReportPath (string).

  /// <summary>

        /// lists all datasources within a report definition (.rdl)

        /// </summary>

        /// <param name="reportName"></param>

        private void ListReportDataSource(string reportPath)

        {

            DataSource[] dataSources = null;

 

            try

            {

                dataSources = rs.GetItemDataSources(reportPath);

 

                if (dataSources != null)

                {

                    foreach (DataSource ds in dataSources)

                    {

                        Response.Write(ds.Name + "<br />");

                    }

                }

            }

            catch (SoapException e)

            {

                Response.Write(e.Detail.InnerXml.ToString());

            }           

        }

Adding the Dataset Source Code

The ListReportDataset method will return all dataset items within a report, by using the GetReportDefinition method, within the Reporting Services SOAP API. In addition to the GetReportDefinition, we use the following objects to help with reading the stream:

  • byte[] - array of bytes 
  • XmlDocument - Represents an XML document
  • MemoryStream - Creates a stream whose backing store is memory. In this case we use for initializing a new non-resizable instance of the MemoryStream class based on the specified byte array.
  • XmlNode - Represents a single node in the XML document. References our XmlDocument object.
  • XmlNodeList - Represents an ordered collection of nodes. All the elements under our Root Node (XmlNode reference and xpath).

The custom method ListReportDataset takes one parameter - ReportPath (string).

        /// <summary>

        /// List all dataset(s) names within a report definition (.rdl) file

        /// </summary>

        /// <param name="reportPath"></param>

        private void ListReportDataset(string reportPath)

        {

            byte[] reportDefinition = null;

            XmlDocument xmldoc = null;

 

            reportDefinition = rs.GetReportDefinition(reportPath);

 

            using (MemoryStream rdlFile = new MemoryStream(reportDefinition))

            {

                xmldoc = new XmlDocument();

                xmldoc.Load(rdlFile);

                rdlFile.Close();

            }

 

            XmlNode root = xmldoc.DocumentElement;

            // Get all the elements under the root node.

            XmlNodeList nodelist = root.SelectNodes("descendant::*");

 

            foreach (XmlNode node in nodelist)

            {

                if (node.Name == "DataSets") // Only search DataSets.

                {  

                    XmlNodeList childList = node.ChildNodes;

 

                    foreach (XmlNode childnode in childList)

                    {

                        if (childnode.Name == "DataSet") // Check if DataSet element exists.

                        {

                            Response.Write(childnode.Attributes["Name"].Value + "<br />");

                        }

                    }

                }

            }

        }

Run Code

1) You'll need to call the methods in your Page_Load before running your code. Enter the following code (change the report path to desired location):

  private ReportingService2005 rs;

 

        protected void Page_Load(object sender, EventArgs e)

        {

            rs = new ReportingService2005();

            // Create an instance of the Web service proxy and set the credentials

            rs.Credentials = System.Net.CredentialCache.DefaultCredentials;

 

            if (!IsPostBack)

            {

                // get list of data sources...

                ListReportDataSource("/Corporate Reports/Company Sales 2008");

                // get list of dataset's...

                ListReportDataset("/Corporate Reports/Company Sales 2008");

            }

        }

That's it! Think about applying these concepts while using custom user controls for best results.

Cheers!

Download the code here: RSIntegrationDemo.zip (442.21 kb)

Jul 02

This article will demo the use of Reporting Services SOAP API to integrate with a web application. We will begin by creating a new Web Project in VS 2008 and configuring the web.config so we can authenticate using impersonation. Next, we will reference the ReportingService2005 web services proxy object. Finally, enter some code to render a list of reports from within the Report Catalog.

For this example, we will be using Visual Studio 2008 and ASP.NET/C# for sample code.

This article assumes you have the following:

  • SQL Server 2008 and Reporting Services installed
  • Microsoft Visual Studio 2008 installed
  • Reporting Services 2008 installed and a configured Report Server
  • Experience with Reporting Services 2005/2008 
  • Experience with ASP.NET and C#
  • Exposure to Web Services

Steps Taken:

  1. Create a ASP.NET Web Application project
  2. Reference the Reporting Services WSDL
  3. Add Treeview control to web form
  4. Develop code to consume Reporting Services Web Service

Create new ASP.NET Web Application

1) Open Microsoft Visual Studio 2008 from Start >> All Programs >> Microsoft Visual Studio 2008 >> Microsoft Visual Studio 2008

2) From the menubar, select File >> New >> Project

reporting builder 2.0

3) Expand the C# node and select the Web child node.

4) From the template pane, select ASP.NET Web Application.

5) Name the project "RSIntegrationDemo".

reporting builder 2.0

6) Click OK.

Reference Reporting Services WSDL

1)  From within your Solution Explorer pane, right click on the project name and select Add Web Reference... to create a new web services reference.

reporting builder 2.0

2) For URL: enter "http://localhost/reportserver/ReportService2005.asmx?wsdl" (replace localhost with your server name, if different).

3) For Web Reference Name: enter RS2005.

reporting builder 2.0

4) Click Add Reference button.

You will notice a new folder named Web References with RS2005 reference located within the folder.

reporting builder 2.0

 You have completed referencing the Reporting Services WSDL

Adding a TreeView Control

1)  When you create your project, the ASP.NET Web Application template should have included a default.aspx page, along with a default.aspx.cs file. If you do not have this file, please add a new web form to your project and name it "default.aspx".

2) Open the default.aspx web form in design mode.

3) Point to the Toolbox pane (if not visible) and expand the Navigation tab.

4) Drag on drop the TreeView object to the default.aspx web form.

5) From within the design pane, right click the TreeView item you just added and select properties.

6) From the properties pane on the right, name the TreeView "tvCatalog".

Steps 7-9 are optional.

7) Right click on the TreeView object and click the right arrow to expand the TreeView Tasks.

reporting builder 2.0

8) Select Auto Format...

9) From the Select a scheme:, select "XP File Explorer" and then click OK.

10) Save your work.

Consuming the Reporting Services Web Service

1) Open the default.aspx.cs file.

2) In order to communicate with our web service we need to add the following reference to our file.

using RSIntegrationDemo.RS2005;

3) Add the following code above Page_Load(object sender, EventArgs e)

 private ReportingService2005 rs;

 

        protected void Page_Load(object sender, EventArgs e)

        {

 

4) We need to create and instance of ReportingService2005 and pass credentials in order to authenticate to the web service. Enter the following code within the Page_Load event.

 protected void Page_Load(object sender, EventArgs e)

        {

            rs = new ReportingService2005();

            // Create an instance of the Web service proxy and set the credentials

            rs.Credentials = System.Net.CredentialCache.DefaultCredentials;

 

            if(!IsPostBack)

                BuildTreeView();

        }

Note: The DefaultCredentials property applies only to NTLM, negotiate, and Kerberos-based authentication. For ASP.NET applications, the default credentials are the user credentials of the logged-in user, or the user being impersonated. If you have problems authenticating, make sure the application pool account used has permissions to SSRS.  

5) Next, we will add our private methods, which will populate the treeview control with report items from the catalog. The first method, BuildTreeView() creates the Parent Node for our treeview control. The Method then calls the GetCatalogItems() method, which populates the treeview control with Report Items. 

Objects and Methods used:

CatalogItem - This object is used to return a report item from the report server database. We will pass an array of CatalogItem objects.

ListChildren - This will return a list of children withing a specified folder. For example, if we wanted all folder, reports, datasources, etc. returned, we would simply pass the following: 

 /// <summary>

        /// Build Treeview

        /// </summary>

        private void BuildTreeView()

        {

            TreeNode RootNode = new TreeNode();

            // give root node a name

            RootNode.Text = "Report Server";

            RootNode.Expanded = true;

            // add node to treeview object

            tvCatalog.Nodes.AddAt(0, RootNode);

            // populate treeview with catalog items

            GetCatalogItems(string.Empty, RootNode);           

        }

 

        /// <summary>

        /// recursivly get folder items from report

        /// server catalog; render to treeview control

        /// </summary>

        /// <param name="catalogPath"></param>

        /// <param name="parentNode"></param>

        private void GetCatalogItems(string catalogPath, TreeNode parentNode)

        {

            CatalogItem[] items;

 

            try

            {

                // if catalog path is empty, use root, if not pass the folder path

                if (catalogPath.Length == 0)

                {

                    items = rs.ListChildren("/", false); // no recursion (false)

                }

                else

                {

                    items = rs.ListChildren(catalogPath, false); // no recursion (false)

                }

 

                // iterate through catalog items and populate treeview control

                foreach (CatalogItem item in items)

                {

                    // if folder is hidden, skip it

                    if (item.Hidden != true)

                    {

                        // ensure only folders are rendered

                        if (item.Type.Equals(ItemTypeEnum.Folder) &

                            (item.Type != ItemTypeEnum.DataSource

                            & item.Name != "Data Sources"))

                        {

                            TreeNode folderNode = new TreeNode(item.Name, null);

                            folderNode.ImageUrl = GetNodeImage(item.Type);

                            folderNode.Text = item.Name;

                            folderNode.Value = item.Path;

                            folderNode.ToolTip = item.Name;

                            //Add the node to the parent node collection                           

                            parentNode.ChildNodes.Add(folderNode);

                            // recurse                      

                            GetCatalogItems(item.Path, folderNode);

                        }

                    }

                }

            }

            catch (Exception ex)

            {

                throw (new Exception(ex.Message));

            }

            finally

            {

                rs.Dispose();

            }

        } 

6) Add the following method to handle the node image

 /// <summary>

        /// Gets corresponding node image

        /// (e.g., folder, reports,..)

        /// </summary>

        /// <param name="type"></param>

        /// <returns></returns>

        private string GetNodeImage(ItemTypeEnum type)

        {

            string imagePath = string.Empty;

 

            switch (type)

            {

                case ItemTypeEnum.Folder:

                    imagePath = folderImage;

                    break;

                case ItemTypeEnum.Report:

                    imagePath = reportImage;

                    break;

                case ItemTypeEnum.LinkedReport:

                    imagePath = reportImage;

                    break;

            }

 

            return imagePath;

        }

 

7) Add the following Constants 

const string reportImage = "~/images/report.gif";

const string folderImage = "~/images/folder.gif";

You can get the images from the download below.

Optionally, you may consider using a custom user control to handle this functionality.

Download code here:

RSIntegrationDemo.zip (442.21 kb)