ServerReport as HTML on MVC Controller Action with ReportViewer on Windows Azure Reporting Services

I needed to work on a task where I had to render a server report (from SQL Server Reporting Services hosted on Windows Azure) as HTML with an MVC Controller Action.

I’ve been using the the Microsoft.ReportViewer.WebForms.dll in the way described on the blog of Richard Astbury.

The steps which I’ve made are the following:

  1. Used the ServerReport with an own Credentials class as follows:
    // Controller action using string as return parameter
    public string Report()
    {
    	var report = new ServerReport
    		{
    			ReportServerUrl = new Uri("https://yourazurereporting.reporting.windows.net/ReportServer"),
    			ReportServerCredentials = new ReportServerCredentials("yourusername", "yourpassword", "yourazurereporting.reporting.windows.net"),
    			ReportPath = "/Test"
    		};
    	// HTML3.2, HTML4.0, MHTML, IMAGE, EXCEL, WORD, CSV, PDF, XML, and NULL
    	var bytearray = report.Render("MHTML");
    	var buf = Encoding.Convert(Encoding.GetEncoding("iso-8859-1"), Encoding.UTF8, bytearray);
    	var mhtml = Encoding.UTF8.GetString(buf, 0, bytearray.Length);
    	MHTMLParser parser = new MHTMLParser(mhtml);
    	string html = parser.getHTMLText();
    	return html;
    }
    

    As you see, the ReportPath doesn’t contain the .rdl extension and anything else…
    The ReportServerCredentials looks like (similarly as described here):

    public sealed class ReportServerCredentials : IReportServerCredentials
    {
    	private readonly string _formsUserName;
    	private readonly string _formsPassword;
    	private readonly string _formsAuthority;
    
    	/// <summary>
    	/// Initializes a new instance of the <see cref="ReportServerCredentials"/> class.
    	/// </summary>
    	/// <param name="userName">Name of the user.</param>
    	/// <param name="password">The password.</param>
    	/// <param name="authority">The authority.</param>
    	public ReportServerCredentials(string userName, string password, string authority)
    	{
    		_formsUserName = userName;
    		_formsPassword = password;
    		_formsAuthority = authority;
    	}
    
    	/// <summary>
    	/// Specifies the user to impersonate when connecting to the report server.
    	/// </summary>
    	/// 
    	/// <returns>
    	/// A WindowsIdentity object encapsulating the user to impersonate when connecting to a report server.
    	/// </returns>
    	public WindowsIdentity ImpersonationUser
    	{
    		get
    		{
    			return null;
    		}
    	}
    
    	/// <summary>
    	/// Gets or sets the network credentials used for authentication with the report server.
    	/// </summary>
    	/// <returns>
    	/// A NetworkCredentials object containing the network credentials used for authentication with the report server.
    	/// </returns>
    	public ICredentials NetworkCredentials
    	{
    		get
    		{
    			return null;
    		}
    	}
    
    	/// <summary>
    	/// Returns a Boolean value indicating whether forms authentication will be used when connecting to the report server, as well as information about the forms credentials to be used for authentication.
    	/// </summary>
    	/// <param name="authCookie">[out] An authentication cookie used by the report server.</param>
    	/// <param name="userName">[out] The user name that will be used to connect to the report server.</param>
    	/// <param name="password">[out] The password of the user.</param>
    	/// <param name="authority">[out] The authority to use when authenticating the user, such as a Microsoft Windows domain.</param>
    	/// <returns>
    	/// Returns true if forms authentication is to be used when connecting to the report server. Information about the credentials to be used for forms authentication is returned via the out parameters used in the method call.
    	/// </returns>
    	public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
    	{
    		authCookie = null;
    		userName = _formsUserName;
    		password = _formsPassword;
    		authority = _formsAuthority;
    		return true;
    	}
    }
    
  2. Converted the returning MHTML to an HTML including base64 encoded images as described in the post of PRNDL Studios
  3. Called the method with a jQuery ajax call and appended to a div.
    <input type="button" onclick="renderContent()" value="Render Report"/>
    <div id="reportContainer"></div>
    <script type="text/javascript">
        function renderContent() {
            var url = '@Url.Action("Report")';
            $.ajax({
                type: 'POST',
                url: url,
                cache: false,
                dataType: 'html',
                async: true,
                success: function (data) {
                    $('#reportContainer').html(data);
                }
            });
        }
    </script>
    
  4. Another important topic is how to get the ReportViewer dlls installed on the Cloud Service. I’ve been trying to install the runtime as described here, but it wasn’t working for me… You will probably need the Redistributable and the Feature Pack. If I make it work, then it is going to be a startup task :).

    For this the best solution what I’ve found was to just copy them all into a folder, and reference them with the Copy Local true option. These were the dlls that I copied:

    C:\Program Files (x86)\Microsoft Visual Studio 11.0\ReportViewer\Microsoft.ReportViewer.WebForms.dll
    C:\windows\assembly\GAC_MSIL\Microsoft.ReportViewer.Common\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.Common.dll
    C:\windows\assembly\GAC_MSIL\Microsoft.ReportViewer.ProcessingObjectModel\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.ProcessingObjectModel.dll
    C:\windows\assembly\GAC_MSIL\Microsoft.ReportViewer.DataVisualization\11.0.0.0__89845dcd8080cc91\Microsoft.ReportViewer.DataVisualization.dll
    C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Types.dll
    
  5. For localizing your reports you might be interested in reading this.
  6. There are other concerns related to using ReportViewer Control in Windows Azure environment related to session state and so on here.

In this way I don’t need to have an extra aspx page for rendering the reports and so on. I’m pretty satisfied with this solution.

Advertisements

About Tamas Nemeth

Husband and proud father of two daughters in Nürnberg. I'm working as a Senior Software Developer and an enthusiastic Clean-Coder. I spend most of my free time with my family (playing, hiking, etc...). I also play table-tennis and badminton sometimes...
This entry was posted in Technical Interest and tagged , , , , , , , , , , , , . Bookmark the permalink.

3 Responses to ServerReport as HTML on MVC Controller Action with ReportViewer on Windows Azure Reporting Services

  1. Mo says:

    Damn! I’m getting the following error:

    The Authentication Extension threw an unexpected exception or returned a value that is not valid: identity==null.

    Any ideas?

  2. Julian says:

    Yoy have soluction?? i can´t run tks

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