Silverlight Reporting Support for SSRS reports – Problem and Possible solutions

After a long break, working on setting up things with the new company, I am back to blogging and would be involved looking into Silverlight development, Sharepoint and general Business problems which I encounter with my new venture.

I was working on a project a few days before and got to implement reporting support in Silverlight 3 project which doesn’t support Reporting natively or doesnt provides a control similar to ASP.NET ReportViewer Control. In this post we will look into the how we can work around this problem with the best possible solutions available for Silverlight 3.

If you try looking around for solution you will find a solution provided by Perpetuum Software http://www.perpetuumsoft.com/Silverlight-Viewer-for-Reporting-Services.aspx. They have offered a solution but due to two things I didnt go for it – 1) The print quality was not good for me 2) Its obviously costing some bucks :)

So, I tried to find how can we workaround it in a free way and leveraging the Microsoft ReportViewer Control itself. So, what we can do is we can have ASP.NET report viewer being used by our application being called by Silverlight app, which is being hosted on a ASP.NET page itself. So, from the Silverlight app when a button is clicked or some event occurs we can cause a pop-up to show the report viewer using some javascript etc.

There are 3 possible solutions which a user can go:
1) Use of pop-up window, which is called by an Event in Silverlight app and ASP.NET report viewer is being used as it is in the pop-up window. The Report customization is part of your report development.
The major issue here is pop-up blockers which by default comes with major browser and hence your pop-up would be blocked mostly causing a bad user experience. Good part is the solution works and presents you with the report.

2) Use of iframe on the same page where Silverlight app is also hosted. The iframe is hidden initially and based on the Silverlight Event this iFrame is made visible and hence we see the report inside an iframe.
Good part is it gives a good user experience and the report viewer looks continous and part of application.

3) Use some third party control like Telerik or so and they have HtmlPlaceholder Silverlight control which can be used to provide with the url of Report and it takes care of setting iFrame and writing the javascript for you to make it cross browser compliant. This approach also essentially uses the iframe way to show the reports.

Let’s look into some code snippet below which uses the iFrame way (2 approach as stated above) so that you can use them in your app if you are working out with this problem or scenario:

1) Default.aspx where the Silverlight object is hosted and iframe added by us:
(I have used inline styling for demo here but you should be using proper styling)

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="abc.Web._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>abc</title>
    <style type="text/css">
    html, body {
	    height: 100%;
	    overflow: auto;
    }
    body {
	    padding: 0;
	    margin: 0;
    }
    #silverlightControlHost {
	    height: 100%;
	    text-align:center;
    }
    </style>
    <script type="text/javascript" src="Silverlight.js"></script>
    <script type="text/javascript">
        function onSilverlightError(sender, args) {
            var appSource = "";
            if (sender != null && sender != 0) {
              appSource = sender.getHost().Source;
            }
            
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;

            if (errorType == "ImageError" || errorType == "MediaError") {
              return;
            }

            var errMsg = "Unhandled Error in Silverlight Application " +  appSource + "\n" ;

            errMsg += "Code: "+ iErrorCode + "    \n";
            errMsg += "Category: " + errorType + "       \n";
            errMsg += "Message: " + args.ErrorMessage + "     \n";

            if (errorType == "ParserError") {
                errMsg += "File: " + args.xamlFile + "     \n";
                errMsg += "Line: " + args.lineNumber + "     \n";
                errMsg += "Position: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError") {           
                if (args.lineNumber != 0) {
                    errMsg += "Line: " + args.lineNumber + "     \n";
                    errMsg += "Position: " +  args.charPosition + "     \n";
                }
                errMsg += "MethodName: " + args.methodName + "     \n";
            }

            throw new Error(errMsg);
        }
    </script>
</head>
<body style="background-colr:black;">
    <form id="form1" runat="server" style="height:100%">
    <div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="950">
		  <param name="source" value="ClientBin/abc.xap"/>
		  <param name="onError" value="onSilverlightError" />
		  <param name="background" value="white" />
		  <param name="minRuntimeVersion" value="3.0.40624.0" />
		  <param name="autoUpgrade" value="true" />
                  <strong><param value="true" name="windowless" /></strong>
		  <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration:none">
 			  <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/>
		  </a>
	    </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
        <div id="divReport" style="margin: 5% auto 0pt 18%; position: relative; z-index: 5; background-color: white; opacity: 1; float: left;">
         <iframe style="border: medium none ; margin: 0pt auto; z-index: 10; display:none;" id="_report"></iframe>
     </div>
    </form>
</body>
</html>

Here we can see that we are using a iframe which has a style of display:none which hides the iframe when the application loads.

2) In your Silverlight app. Create a button and bind an Event handler to it. In the event handler you can use the below code:

private void Btn_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Uri sourceUri = new Uri(HtmlPage.Document.DocumentUri, Application.Current.Host.Source.ToString().Substring(0, Application.Current.Host.Source.ToString().IndexOf("ClientBin") - 1) + "/ReportViewerPage.aspx?ReportName=Report1&Client=L1");

            string wid = ContentStackPanel.ActualHeight.ToString();
            string hei = ContentStackPanel.ActualWidth.ToString();

            HtmlPage.Document.GetElementById("_report").SetStyleAttribute("display", "");
            HtmlPage.Document.GetElementById("_report").SetProperty("height", hei);
            HtmlPage.Document.GetElementById("_report").SetProperty("width", wid);
            HtmlPage.Document.GetElementById("_report").SetAttribute("src", sourceUri.ToString());
            //Above code will make the iframe solution work

            //Below code is for using pop-up window. So you can comment the code if you are only using iframe
            if (true == HtmlPage.IsPopupWindowAllowed)
            {
                System.Text.StringBuilder codeToRun = new System.Text.StringBuilder();
                codeToRun.Append("window.open(");
                codeToRun.Append("\"");
                codeToRun.Append(sourceUri.ToString());
                codeToRun.Append("\",");
                codeToRun.Append("\"");
                codeToRun.Append("\",");
                codeToRun.Append("\"");
                codeToRun.Append("width=" + wid + ",height=" + hei);                
                codeToRun.Append(",scrollbars=yes,menubar=no,toolbar=no,resizable=yes");
                codeToRun.Append("\");");
                try
                {
                    HtmlPage.Window.Eval(codeToRun.ToString());
                }
                catch
                {
                    MessageBox.Show("You must enable popups to view reports.  Safari browser is not supported.", "Error", MessageBoxButton.OK);
                }
            }
            else
                MessageBox.Show("You must enable popups to view reports.  Safari browser is not supported.", "Error", MessageBoxButton.OK);
        }

In this code we are making the src component of iframe which is a aspx page in the project called ReportViewerPage.aspx and use some query string parameters to pass the report name and parameters.

The iframe style property is changed and its height and width is set to the container above which it has to be shown and then using the windowless param of Silverlight object and CSS of setting position and z-index we can have our iframe show on top of Silverlight giving the user and impression that the reportviewer is part of Silverlight app itself.

3) ReportViewerPage.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportViewerPage.aspx.cs" Inherits="abc.Web.ReportViewerPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
    
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>    
</head>
<body>
    <form id="form1" runat="server">
   <div>
        <rsweb:ReportViewer ID="MainReportViewer" runat="server" 
            ProcessingMode="Remote"
            Width="100%"
            Height="700"
            ShowExportControls="True"
            ShowFindControls="True"
            ShowParameterPrompts="False"
            ShowPromptAreaButton="False"
            ShowRefreshButton="False"
            ShowPrintButton="true"
            ShowZoomControl="true"
            ZoomMode="Percent"
            BackColor="White" >
            <ServerReport DisplayName="MainReport" ReportServerUrl="" />
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

4) ReportViewerPage.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.Reporting.WebForms;
using System.Configuration;

namespace abc.Web
{
    public partial class ReportViewerPage : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            MainReportViewer.ProcessingMode = ProcessingMode.Remote;
            MainReportViewer.ZoomMode = ZoomMode.Percent;
            MainReportViewer.ZoomPercent = 100;
            MainReportViewer.ServerReport.ReportPath = ConfigurationSettings.AppSettings["ReportPath"] + this.Request.QueryString["ReportName"];
            MainReportViewer.ServerReport.ReportServerUrl = new Uri(ConfigurationSettings.AppSettings["ReportServerUrl"]);
            List parameters = new List();
            List values = new List();
            values.Add(this.Request.QueryString["Client"]);
           
            ReportParameter oneParamter = new ReportParameter("Client", values.ToArray());
            values.Clear();
            string apars = this.Request.QueryString["Apar_Id"];
            values = apars.Split(new[] { "," }, StringSplitOptions.None).ToList();
            ReportParameter twoParamter = new ReportParameter("Apar_Id", values.ToArray());

            parameters.Add(oneParamter);
            parameters.Add(twoParamter);
            MainReportViewer.ServerReport.SetParameters(parameters.ToArray());
            MainReportViewer.ShowParameterPrompts = false;
            MainReportViewer.ServerReport.Refresh();
        }
    }
}

This page reads the parameter passed by iframe src property and then parses the query string to make a Report Server call. The parameters are passed using Report parameter and if your report is set to take parameters then these parameters would be used to show the report in the Report Viewer.

You need to provide ReportServer url like http://localhost/ReportServer and ReportPath like “/FirstReport/” which will be appended by specific report name send by the Silverlight app. So finally it should look something like – http://localhost/ReportServer/FirstReport/MyReport

You need to prepare a report for the above to work and have it hosted on your server (localhost or external server) and then point the add in this program to your server.

This overall is a simple way to get the SSRS Report being shown in a ASP.NET along with Silverlight app hosted but giving the impression that Reporting support is part of Silverlight app itself.

I Hope this will solve your problems if you are working on this scenario. Write back if you find any issues or clarification regarding any code.

I have a working solution with my and have tested the code with local and external report server and it works just fine.

Good day!!
bye for now.

About these ads

14 Responses to Silverlight Reporting Support for SSRS reports – Problem and Possible solutions

  1. [...] Silverlight Reporting Support for SSRS reports – Problem and … [...]

  2. heyjude says:

    this truly helps, now i happen the troubles and i donot know how to puzzle out,
    i research google and found your blog,
    thanks once againjust one thing, may i post this article on my blog? i will add the source and credit to your site.regards!

  3. Sapna says:

    Hello Sushant,

    Iam new to silverlight concepts.
    Can you please help me understand where the Button needs to be added?
    When I create a new silverlight application it creates 2 projects SilverlightApplication and SilverlightApplication.web
    In the SilverlightApplication.web, there is a Default.aspx page as well as the SilverlightApplicationTestPage.aspx(which embeds the silverlight object)

  4. Junted says:

    This is awesome!!! I have been trying to find a way to implement this functionality in my application. Thank you very much!

  5. Brian says:

    Very helpful, thanks very much. The only issue I’m having is that I would like to use the ReportServer’s aspx page instead of creating my own with a reportviewer in it. When I try setting the sourceURI of the iframe to this page, it appears beneath the Silverlight control instead of on top.

  6. Elibariki Muna says:

    I have a problem with the lines

    List parameters = new List();

    List values = new List();

    The compiler gives “Using the generic type System.Collections.List requires 1 type arguments”

  7. sushantp says:

    You can just use var parameters = new List(); or whatever type your parameters names and parameter values would be. The parameter and values can be passed in different ways and this is one of the ways.

    Do let me know in case of any further issues.

  8. [...] Reporting Support for SSRS reports – Problems and Possible Solutions (link) en Sushantp’s [...]

  9. Chris Newton says:

    Hi,

    Thank you for writing this article, it has been very helpful. Can I ask how you have tackled the issue of security? I am part of a project team developing a BI application that integrates with SSRS. The core application is secured using a custom membership provider and I nede to be able to apply/pass security to SSRS in terms of the reports that a particular user can view.

    Kind Regards,
    Chris

  10. Satya says:

    Hi Sushanth,

    Thanks for the nice article

    I implemented like you suggested I am having security issue when reports are not running in debug mode (i.e. from Visual Studio). Do you have any thoughts on that?

    Thanks,
    Satya

  11. Saritha says:

    Can you please post working code.I do have same requirement when i ma using your code it is not working for me.

    Thanks
    Saritha

  12. [...] Sorry, we did not find the headline of this post.    ASP.NET Read the original post on Asp.net… [...]

  13. Thank you for the auspicious writeup. It in fact was a amusement account it.
    Look advanced to more added agreeable from you!

    However, how could we communicate?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Who am I what am I doing?

Who am I what am I doing?

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: