Implementing a Report Viewer Page - ASP.NET MVC

Overview

The ReportViewer control cannot be hosted on an ASP.NET MVC page - only a WebForms page. This article walks through how to use a ReportViewer control in a mostly-ASP.NET-MVC project.

Code

AppReport Database Table

Create a new dbo.AppReport table in your database. This will hold a list of all reports available on your site.

CREATE TABLE [dbo].[AppReport](
	[AppReportID] [int] IDENTITY(1,1) NOT NULL,
	[DisplayName] [nvarchar](100) NOT NULL,
	[IsDeleted] [bit] NOT NULL,
	[ReportFile] [nvarchar](100) NOT NULL,
 CONSTRAINT [PK_AppReport] PRIMARY KEY CLUSTERED 
(
	[AppReportID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Business Layer

Create a new business object called AppReportManager. Within it create a new method called ReportsForCurrentUser to return a list of reports for the currently logged-in user.

ICredentials Interface

The ReportCredentials class below is based upon the ICredentials interface.

public interface ICredentials
{
    string UserName { get; set; }
    string Password { get; set; }
    string Domain { get; set; }
}

ReportCredentials Class

Create a class in your web project called ReportCredentials. This will be needed if you ever want to user non-default credentials to access the SSRS instance.

[Serializable]
public class ReportServerCredentials : Microsoft.Reporting.WebForms.IReportServerCredentials
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string Domain { get; set; }

    public ReportServerCredentials(ICredentials credentials)
    {
        UserName = credentials.UserName;
        Password = credentials.Password;
        Domain = credentials.Domain;
    }

    public ReportServerCredentials(string userName, string password, string domain)
    {
        UserName = userName;
        Password = password;
        Domain = domain;
    }
    public System.Security.Principal.WindowsIdentity ImpersonationUser
    {
        get
        {
            return null;
        }
    }
    public System.Net.ICredentials NetworkCredentials
    {
        get
        {
            return new System.Net.NetworkCredential(UserName, Password, Domain);
        }
    }
    public bool GetFormsCredentials(out System.Net.Cookie authCoki, out string userName, out string password, out string authority)
    {
        userName = UserName;
        password = Password;
        authority = Domain;
        authCoki = new System.Net.Cookie(".ASPXAUTH", ".ASPXAUTH", "/", "Domain");
        return true;
    }

}

Razor View

Create a new ReportsController with a View method, then create a View.cshtml view with the following content.

@{
    ViewBag.Title = "Reports";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<iframe id="ReportIframe" src="/Reports/ReportViewer/aspx" style="width:100%; height:550px; border: 1px dotted silver;"></iframe>

ReportViewer.aspx Page

Create a Reports folder in the root of your web project, and create a new Web Forms page called ReportViewer.aspx within it with the following content.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportViewer.aspx.cs" Inherits="My.Namespace.Reports.ReportViewer" %>

<%@ Register assembly="Microsoft.ReportViewer.WebForms, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" namespace="Microsoft.Reporting.WebForms" tagprefix="rsweb" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Report Viewer</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        Report: <asp:DropDownList runat="server" ID="uxReportDropDown" DataTextField="DisplayName" DataValueField="ReportFile" />
        <asp:Button runat="server" Text="Go" ID="uxGoButton" OnClick="uxGoButton_Click" />

        <br />
        <br />

        <rsweb:ReportViewer 
            ID="uxReportViewer" 
            runat="server"
            Font-Names="Verdana" 
            Font-Size="8pt" 
            InteractiveDeviceInfos="(Collection)" 
            WaitMessageFont-Names="Verdana" 
            WaitMessageFont-Size="14pt" 
            Height="1100px" 
            Width="98%"
            >

        </rsweb:ReportViewer>
    
        <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

    </div>
    </form>
</body>
</html>

ReportViewer.aspx.cs Code Behind

public partial class ReportViewer : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            InitReportDropDown();
        }
    }

    private void InitReportDropDown()
    {
        var reports = new AppReportManager().ReportsForCurrentUser();

        uxReportDropDown.DataSource = null;
        uxReportDropDown.DataSource = reports;
        uxReportDropDown.DataBind();
    }

    protected void uxGoButton_Click(object sender, EventArgs e)
    {
        var reportName = uxReportDropDown.SelectedValue.ToString();
        RenderServerReport(reportName);
    }

    private void RenderServerReport(string reportName)
    {
        try
        {
            /*--- Inits ---*/
            var rv = uxReportViewer;
            var rpt = rv.ServerReport;
            ReportParameterInfo p = null;

            /*--- Configure ReportViewer Control ---*/
            rv.ShowCredentialPrompts = false;
            rv.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote;

            /*--- Configure ServerReport ---*/
            /* The SomeCustomConfigurationObject retrieves configuration info from the web.config file */
            var config = new SomeCustomConfigurationObject();
                
            if (!config.DefaultCredentials)
                rpt.ReportServerCredentials = new ReportServerCredentials(config);

            rpt.ReportServerUrl = config.ReportServerUrl;
            rpt.ReportPath = config.RootPathWithSlashes + reportName;

            /*--- Set LoginName Parameter (?) ---*/
            p = rpt.GetParameters()["LoginName"];

            if (p != null)
            {
                var loginName = System.Threading.Thread.CurrentPrincipal.Identity.Name;
                var p2 = new ReportParameter("LoginName", loginName);
                rpt.SetParameters(p2);
            }

            rpt.Refresh();
        }
        catch (Exception ex)
        {
            new EventLogManager().LogException(ex);
            System.Diagnostics.Debug.Print(ex.Message);
            throw;
        }
    }

}

web.config Settings

Create settings in your web.config file to support the above code. Note that the ServerReport.ReportServerUrl property should get set to the Web Service URL for your SSRS instance, as seen in the Reporting Services Configuration Manager.