How can I use a reportviewer control in an asp.net mvc 3 razor view?

asp.net Mvc-3RazorReportviewer

asp.net Mvc-3 Problem Overview


I'm trying to use a reportviewer control, within a razor view, in the mvc 3 framework. The online documentation talks of drag and drop. Any suggestion on how to insert it into the view.

asp.net Mvc-3 Solutions


Solution 1 - asp.net Mvc-3

The following solution works only for single page reports. Refer to comments for more details.

ReportViewer is a server control and thus can not be used within a razor view. However you can add a ASPX view page, view user control or traditional web form that containing a ReportViewer into the application.

You will need to ensure that you have added the relevant handler into your web.config.

If you use a ASPX view page or view user control you will need to set AsyncRendering to false to get the report to display properly.

Update:

Added more sample code. Note there are no meaningful changes required in Global.asax.

Web.Config

Mine ended up as follows:

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->

<configuration>
  <appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
  </appSettings>
    
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="Microsoft.ReportViewer.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
      </assemblies>
    </compilation>

    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>

    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages"/>
      </namespaces>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true"/>
    <handlers>
      <add name="ReportViewerWebControlHandler" preCondition="integratedMode" verb="*" path="Reserved.ReportViewerWebControl.axd" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </handlers>
  </system.webServer>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Controller

The controller actions are very simple.

As a bonus the File() action returns the output of "TestReport.rdlc" as a PDF file.

using System.Web.Mvc;
using Microsoft.Reporting.WebForms;

...

public class PDFController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public FileResult File()
    {
        ReportViewer rv = new Microsoft.Reporting.WebForms.ReportViewer();
        rv.ProcessingMode = ProcessingMode.Local;
        rv.LocalReport.ReportPath = Server.MapPath("~/Reports/TestReport.rdlc");
        rv.LocalReport.Refresh();

        byte[] streamBytes = null;
        string mimeType = "";
        string encoding = "";
        string filenameExtension = "";
        string[] streamids = null;
        Warning[] warnings = null;

        streamBytes = rv.LocalReport.Render("PDF", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);

        return File(streamBytes, mimeType, "TestReport.pdf");
    }

    public ActionResult ASPXView()
    {
        return View();
    }

    public ActionResult ASPXUserControl()
    {
        return View();
    }
}

ASPXView.apsx

The ASPXView is as follows.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <title>ASPXView</title>
</head>
<body>
    <div>
        <script runat="server">
            private void Page_Load(object sender, System.EventArgs e)
            {
                ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Reports/TestReport.rdlc");
                ReportViewer1.LocalReport.Refresh();
            }
        </script>
        <form id="Form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">          
        </asp:ScriptManager>
        <rsweb:reportviewer id="ReportViewer1" runat="server" height="500" width="500" AsyncRendering="false"></rsweb:reportviewer>
        </form>        
    </div>
</body>
</html>

ViewUserControl1.ascx

The ASPX user control looks like:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<script runat="server">
  private void Page_Load(object sender, System.EventArgs e)
  {
      ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Reports/TestReport.rdlc");
      ReportViewer1.LocalReport.Refresh();
  }
</script>
<form id="Form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<rsweb:ReportViewer ID="ReportViewer1" runat="server" AsyncRendering="false"></rsweb:ReportViewer>
</form>

ASPXUserControl.cshtml

Razor view. Requires ViewUserControl1.ascx.

@{
    ViewBag.Title = "ASPXUserControl";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>ASPXUserControl</h2>
@Html.Partial("ViewUserControl1")

References

http://blogs.msdn.com/b/sajoshi/archive/2010/06/16/asp-net-mvc-handling-ssrs-reports-with-reportviewer-part-i.aspx

https://stackoverflow.com/questions/5296485/bind-report-to-reportviewer-in-web-mvc2

Solution 2 - asp.net Mvc-3

This is a simple task. You can follow the following steps.

  1. Create a folder in your solution and name it Reports.

  2. Add an ASP.Net web form and name it ReportView.aspx

  3. Create a Class ReportData and add it to the Reports folder. Add the following code to the Class.

     public class ReportData  
     {  
         public ReportData()  
         {  
             this.ReportParameters = new List<Parameter>();  
             this.DataParameters = new List<Parameter>();  
         }
    
         public bool IsLocal { get; set; }
         public string ReportName { get; set; }
         public List<Parameter> ReportParameters { get; set; }
         public List<Parameter> DataParameters { get; set; }
     }
    
     public class Parameter  
     {  
         public string ParameterName { get; set; }  
         public string Value { get; set; }  
     }
    
  4. Add another Class and name it ReportBasePage.cs. Add the following code in this Class.

     public class ReportBasePage : System.Web.UI.Page
     {
         protected ReportData ReportDataObj { get; set; }
    
         protected override void OnInit(EventArgs e)
         {
             base.OnInit(e);
             if (HttpContext.Current != null)
                 if (HttpContext.Current.Session["ReportData"] != null)
                 {
                     ReportDataObj = HttpContext.Current.Session["ReportData"] as ReportData;
                     return;
                 }
             ReportDataObj = new ReportData();
             CaptureRouteData(Page.Request);
         }
    
    
         private void CaptureRouteData(HttpRequest request)
         {
             var mode = (request.QueryString["rptmode"] + "").Trim();
             ReportDataObj.IsLocal = mode == "local" ? true : false;
             ReportDataObj.ReportName = request.QueryString["reportname"] + "";
             string dquerystr = request.QueryString["parameters"] + "";
             if (!String.IsNullOrEmpty(dquerystr.Trim()))
             {
                 var param1 = dquerystr.Split(',');
                 foreach (string pm in param1)
                 {
                     var rp = new Parameter();
                     var kd = pm.Split('=');
                     if (kd[0].Substring(0, 2) == "rp")
                     {
                         rp.ParameterName = kd[0].Replace("rp", "");
                         if (kd.Length > 1) rp.Value = kd[1];
                         ReportDataObj.ReportParameters.Add(rp);
                     }
                     else if (kd[0].Substring(0, 2) == "dp")
                     {
                         rp.ParameterName = kd[0].Replace("dp", "");
                         if (kd.Length > 1) rp.Value = kd[1];
                         ReportDataObj.DataParameters.Add(rp);
                     }
                 }
             }
         }
     }
    
  5. Add ScriptManager to the ReportView.aspx page. Now add a Report Viewer to the page. In report viewer set the property AsyncRendering="false". The code is given below.

         <rsweb:ReportViewer ID="ReportViewerRSFReports" runat="server" AsyncRendering="false"
             Width="1271px" Height="1000px" >
         </rsweb:ReportViewer>
    
  6. Add two NameSpace in ReportView.aspx.cs

     using Microsoft.Reporting.WebForms;
     using System.IO;
    
  7. Change the System.Web.UI.Page to ReportBasePage. Just replace your code using the following.

     public partial class ReportView : ReportBasePage
     {
         protected void Page_Load(object sender, EventArgs e)
         {
             if (!IsPostBack)
             {
                 RenderReportModels(this.ReportDataObj);
             }
         }
    
         private void RenderReportModels(ReportData reportData)
         {
             // This is the Data Access Layer from which a method is called to fill data to the list.
             RASolarERPData dal = new RASolarERPData();
             List<ClosingInventoryValuation> objClosingInventory = new List<ClosingInventoryValuation>();
    
             // Reset report properties.
             ReportViewerRSFReports.Height = Unit.Parse("100%");
             ReportViewerRSFReports.Width = Unit.Parse("100%");
             ReportViewerRSFReports.CssClass = "table";
    
             // Clear out any previous datasources.
             this.ReportViewerRSFReports.LocalReport.DataSources.Clear();
    
             // Set report mode for local processing.
             ReportViewerRSFReports.ProcessingMode = ProcessingMode.Local;
    
             // Validate report source.
             var rptPath = Server.MapPath(@"./Report/" + reportData.ReportName +".rdlc");
             
             //@"E:\RSFERP_SourceCode\RASolarERP\RASolarERP\Reports\Report\" + reportData.ReportName + ".rdlc";
             //Server.MapPath(@"./Report/ClosingInventory.rdlc");
    
             if (!File.Exists(rptPath))
                 return;
    
             // Set report path.
             this.ReportViewerRSFReports.LocalReport.ReportPath = rptPath;
    
             // Set report parameters.
             var rpPms = ReportViewerRSFReports.LocalReport.GetParameters();
             foreach (var rpm in rpPms)
             {
                 var p = reportData.ReportParameters.SingleOrDefault(o => o.ParameterName.ToLower() == rpm.Name.ToLower());
                 if (p != null)
                 {
                     ReportParameter rp = new ReportParameter(rpm.Name, p.Value);
                     ReportViewerRSFReports.LocalReport.SetParameters(rp);
                 }
             }
    
             //Set data paramater for report SP execution
             objClosingInventory = dal.ClosingInventoryReport(this.ReportDataObj.DataParameters[0].Value);
    
             // Load the dataSource.
             var dsmems = ReportViewerRSFReports.LocalReport.GetDataSourceNames();
             ReportViewerRSFReports.LocalReport.DataSources.Add(new ReportDataSource(dsmems[0], objClosingInventory));
    
             // Refresh the ReportViewer.
             ReportViewerRSFReports.LocalReport.Refresh();
         }
     }
    
  8. Add a Folder to the Reports Folder and name it Report. Now add a RDLC report to the Reports/Report folder and name it ClosingInventory.rdlc.

  9. Now add a Controller and name it ReportController. In the controller add the following action method.

     public ActionResult ReportViewer()
         {                
             ViewData["reportUrl"] = "../Reports/View/local/ClosingInventory/";
            
             return View();
         }
    
  10. Add a view page click on the ReportViewer Controller. Name the view page ReportViewer.cshtml. Add the following code to the view page.

    @using (Html.BeginForm("Login"))
     { 
           @Html.DropDownList("ddlYearMonthFormat", new SelectList(ViewBag.YearMonthFormat, "YearMonthValue",
     "YearMonthName"), new { @class = "DropDown" })
    
    Stock In Transit: @Html.TextBox("txtStockInTransit", "", new { @class = "LogInTextBox" })
    
    <input type="submit" onclick="return ReportValidationCheck();" name="ShowReport"
                     value="Show Report" />
    
    }
    
  11. Add an Iframe. Set the property of the Iframe as follows

    frameborder="0"  width="1000"; height="1000"; style="overflow:hidden;"
    scrolling="no"
    
  12. Add Following JavaScript to the viewer.

    function ReportValidationCheck() {
    
        var url = $('#hdUrl').val();
        var yearmonth = $('#ddlYearMonthFormat').val();      
        var stockInTransit = $('#txtStockInTransit').val()
    
        if (stockInTransit == "") {
            stockInTransit = 0;
        }
    
        if (yearmonth == "0") {
            alert("Please Select Month Correctly.");
        }
        else {
    
            //url = url + "dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
    
            url = "../Reports/ReportView.aspx?rptmode=local&reportname=ClosingInventory&parameters=dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
    
            var myframe = document.getElementById("ifrmReportViewer");
            if (myframe !== null) {
                if (myframe.src) {
                    myframe.src = url;
                }
                else if (myframe.contentWindow !== null && myframe.contentWindow.location !== null) {
                    myframe.contentWindow.location = url;
                }
                else { myframe.setAttribute('src', url); }
            }
        }
    
        return false;
    }
    
  13. Web.config file add the following key to the appSettings section

    add key="UnobtrusiveJavaScriptEnabled" value="true"
    
  14. In system.web handlers Section add the following key

    add verb="*" path="Reserved.ReportViewerWebControl.axd" type = "Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    
  15. Change your data source to your own. This solution is very simple and I think every one will enjoy it.

Solution 3 - asp.net Mvc-3

I am using ASP.NET MVC3 with SSRS 2008 and I couldn't get @Adrian's to work 100% for me when trying to get reports from a remote server.

Finally, I found that I needed to change the Page_Load method in ViewUserControl1.ascx to look like this:

ReportViewer1.ProcessingMode = ProcessingMode.Remote;
ServerReport serverReport = ReportViewer1.ServerReport;
serverReport.ReportServerUrl = new Uri("http://<Server Name>/reportserver");
serverReport.ReportPath = "/My Folder/MyReport";
serverReport.Refresh();

I had been missing the ProcessingMode.Remote.

References:

http://msdn.microsoft.com/en-us/library/aa337091.aspx - ReportViewer

Solution 4 - asp.net Mvc-3

Here is the complete solution for directly integrating a report-viewer control (as well as any asp.net server side control) in an MVC .aspx view, which will also work on a report with multiple pages (unlike Adrian Toman's answer) and with AsyncRendering set to true, (based on "Pro ASP.NET MVC Framework" by Steve Sanderson).

What one needs to do is basically:

  1. Add a form with runat = "server"

  2. Add the control, (for report-viewer controls it can also sometimes work even with AsyncRendering="True" but not always, so check in your specific case)

  3. Add server side scripting by using script tags with runat = "server"

  4. Override the Page_Init event with the code shown below, to enable the use of PostBack and Viewstate

Here is a demonstration:

<form ID="form1" runat="server">
    <rsweb:ReportViewer ID="ReportViewer1" runat="server" />
</form>
<script runat="server">
    protected void Page_Init(object sender, EventArgs e)
    {
        Context.Handler = Page;
    }
    //Other code needed for the report viewer here        
</script>

It is of course recommended to fully utilize the MVC approach, by preparing all needed data in the controller, and then passing it to the view via the ViewModel.

This will allow reuse of the View!

However this is only said for data this is needed for every post back, or even if they are required only for initialization if it is not data intensive, and the data also has not to be dependent on the PostBack and ViewState values.

However even data intensive can sometimes be encapsulated into a lambda expression and then passed to the view to be called there.

A couple of notes though:

  • By doing this the view essentially turns into a web form with all it's drawbacks, (i.e. Postbacks, and the possibility of non Asp.NET controls getting overriden)
  • The hack of overriding Page_Init is undocumented, and it is subject to change at any time

Solution 5 - asp.net Mvc-3

There's a MvcReportViewer helper in NuGet.

http://www.nuget.org/packages/MvcReportViewer/

And this is the details:

https://github.com/ilich/MvcReportViewer

I have using this. It works great.

Solution 6 - asp.net Mvc-3

the documentations refers to an ASP.NET application.
You can try and have a look at my answer here.
I have an example attached to my reply.
Another example for ASP.NET MVC3 can be found here.

Solution 7 - asp.net Mvc-3

You will not only have to use an asp.net page but

If using the Entity Framework or LinqToSql (if using partial classes) move the data into a separate project, the report designer cannot see the classes.

Move the reports to another project/dll, VS10 has bugs were asp.net projects cannot see object datasources in web apps. Then stream the reports from the dll into your mvc projects aspx page.

This applies for mvc and webform projects. Using sql reports in the local mode is not a pleasent development experience. Also watch your webserver memory if exporting large reports. The reportviewer/export is very poorly designed.

Solution 8 - asp.net Mvc-3

It is possible to get an SSRS report to appear on an MVC page without using iFrames or an aspx page.

The bulk of the work is explained here:

http://geekswithblogs.net/stun/archive/2010/02/26/executing-reporting-services-web-service-from-asp-net-mvc-using-wcf-add-service-reference.aspx

The link explains how to create a web service and MVC action method that will allow you to call the reporting service and render result of the web service as an Excel file. With a small change to the code in the example you can render it as HTML.

All you need to do then is use a button to call a javascript function that makes an AJAX call to your MVC action which returns the HTML of the report. When the AJAX call returns with the HTML just replace a div with this HTML.

We use AngularJS so my example below is in that format, but it could be any javascript function

$scope.getReport = function()
{
    $http({
        method: "POST",
        url: "Report/ExportReport",
        data: 
                [
                    { Name: 'DateFrom', Value: $scope.dateFrom },
                    { Name: 'DateTo', Value: $scope.dateTo },
                    { Name: 'LocationsCSV', Value: $scope.locationCSV }
                ]
        
    })
    .success(function (serverData)
    {
        $("#ReportDiv").html(serverData);
    });
    
};

And the Action Method - mainly taken from the above link...

    [System.Web.Mvc.HttpPost]
    public FileContentResult ExportReport([FromBody]List<ReportParameterModel> parameters)
    {
         byte[] output;
         string extension, mimeType, encoding;
         string reportName = "/Reports/DummyReport";
         ReportService.Warning[] warnings;
         string[] ids;

     ReportExporter.Export(
            "ReportExecutionServiceSoap" 
	        new NetworkCredential("username", "password", "domain"),
	        reportName,
            parameters.ToArray(),
	        ExportFormat.HTML4,
	        out output,
	        out extension,
	        out mimeType,
	        out encoding,
            out warnings,
            out ids
        );

        //-------------------------------------------------------------
        // Set HTTP Response Header to show download dialog popup
        //-------------------------------------------------------------
        Response.AddHeader("content-disposition", string.Format("attachment;filename=GeneratedExcelFile{0:yyyyMMdd}.{1}", DateTime.Today, extension));
        return new FileContentResult(output, mimeType);
    }

So the result is that you get to pass parameters to an SSRS reporting server which returns a report which you render as HTML. Everything appears on the one page. This is the best solution I could find

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArunView Question on Stackoverflow
Solution 1 - asp.net Mvc-3Adrian TomanView Answer on Stackoverflow
Solution 2 - asp.net Mvc-3Md. Nazrul IslamView Answer on Stackoverflow
Solution 3 - asp.net Mvc-3wilsjdView Answer on Stackoverflow
Solution 4 - asp.net Mvc-3yoel halbView Answer on Stackoverflow
Solution 5 - asp.net Mvc-3Hayu RahizaView Answer on Stackoverflow
Solution 6 - asp.net Mvc-3LeftyXView Answer on Stackoverflow
Solution 7 - asp.net Mvc-3user965445View Answer on Stackoverflow
Solution 8 - asp.net Mvc-3NeilView Answer on Stackoverflow