View SSRS Reports on ASP.net MVC

Is there a way to host the SQL Server Reporting Services Report Viewer in an ASP.net MVC view? If not ... what is the best way to do this?

+50
c # asp.net-mvc reporting-services reportviewer
Nov 09 '10 at 19:50
source share
7 answers

No, not in the MVC view. But you can have web form pages in which they have server elements mixed with your MVC site.

Hmm, just ran "mix asp.net mvc and web forms" to find some examples, and google asked if I was human or not :)

In any case, here is the link - http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc - there are several. I also did this on the MVC website for the same reason - report control.

+16
Nov 09 2018-10-11T00:
source share

No, the ReportViewer control will not work if you place it in the MVC view because it requires a ViewState. You will need to create an old school web form and put ReportViewer instead.

The solution I used in the project I was working on was to create a custom route handler, so I could still use URL routing. The route handler accepts parameters such as the name of the report from the RouteData collection, creates an instance of my web form and passes the parameters to it through public properties. The web form will read them in Page_Load and configure the ReportViewer control.

// Configure a route in Global.asax.cs that is handled by a ReportRouteHandler routes.Add("ReportRoute", new Route("Reports/{reportName}", new ReportRouteHandler()); public class ReportRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { var reportName = requestContext.RouteData.Values["reportName"] as string; var webform = BuildManager .CreateInstanceFromVirtualPath("~/Path/To/ReportViewerWebForm.aspx", typeof(Page)) as ReportViewerWebForm; webform.ReportToShow = reportName; return webform; } } 

This code is just a starting point if you decide to use this approach, of course. The one I created also performed some user authentication and parameter checking before returning.

Refresh . It looks like if you are using ASP.NET 4.0, most of this can be done automatically

+14
Nov 09 '10 at 20:32
source share

Now there is an MvcReportViewer helper. We can get it from NuGet.

GitHub project site

Nuget package

+11
Nov 28 '13 at 6:30
source share

The implementation of the SSRS ReportViewer control in MVC consists of two problems:

  1. At a minimum, you need to add the correct dependencies, handlers, and configuration for the ReportViewer control (regardless of project type).
  2. A more difficult hurdle is mixing web forms and MVC . We need a way to render and route incoming requests so that they are handled by pages, controls, and WebForms actions.

Problem 1 - Setting up ReportViewer

If you've done a lot with customizing ReportViewer controls in the past, this may be an old problem, and you can skip to section 2.

  1. Add package / link. ReportViewer control in Microsoft.ReportViewer.WebForms.dll . You can include in your project by adding the package Microsoft.ReportViewer.WebForms from nuget:

    Nuget - Microsoft.ReportViewer.WebForms

  2. Web.config handlers. According to this article on Web.config settings for ReportViewer , and for this SO question, you need to add to the web.config :

     <system.web> <httpHandlers> <add verb="*" path="Reserved.ReportViewerWebControl.axd" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> </httpHandlers> </system.web> <system.webServer> <handlers> <remove name="ReportViewerWebControlHandler" /> <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> 

    In response to this question about duplicate keys , it is usually easiest to remove and then re-add the web server settings.

  3. Fix corrupted image requests - ReportViewer has a defect with blank.gif images global.asax.cs so you can add the following fix to your global.asax.cs :

     protected void Application_BeginRequest(object sender, EventArgs e) { HttpRequest req = HttpContext.Current.Request; if (req.Url.PathAndQuery.StartsWith("/Reserved.ReportViewerWebControl.axd") && !req.Url.ToString().ToLower().Contains("iteration") && !String.IsNullOrEmpty(req.QueryString["ResourceStreamID"]) && req.QueryString["ResourceStreamID"].ToLower().Equals("blank.gif")) { Context.RewritePath(String.Concat(req.Url.PathAndQuery, "&IterationId=0")); } } 
  4. IgnoreRoute.axd - if it is not already there, be sure to enable ScriptResources in your RouteConfig.cs :

     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
  5. Add ReportViewerPage.aspx - add a WebForm page that will contain an instance of the ReportViewer control. For this <form runat="server" > control to work, you need to find the ScriptManager and place it in <form runat="server" > .
    So your new .aspx page should look something like this:

     <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportViewerPage.aspx.cs" Inherits="MVCAppWithReportViewer.ReportViewerPage" %> <%@ Register TagPrefix="rsweb" Namespace="Microsoft.Reporting.WebForms" Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Report Viewer</title> </head> <body> <form id="form1" runat="server"> <rsweb:ReportViewer ID="ReportViewer" runat="server" Height="100%" Width="100%" SizeToReportContent="True" ProcessingMode="Remote" /> <asp:ScriptManager ID="ScriptManager1" runat="server" /> </form> </body> </html> 
  6. Connect ReportViewer to Page_Load It is assumed that you already have an SSRS report fully deployed to the report server, which is available at an address similar to the following:

    http:// ReportServerName /Reports/Pages/Report.aspx?ItemPath= %2fCompany%2f ClientReport

    Then your code on the new WebForm page should look like this:

     public partial class ReportViewerPage : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { // confirm report properties (also setable in attributes) ReportViewer.ProcessingMode = ProcessingMode.Remote; // config variables var reportServer = "ReportServerName"; var reportPath = "/Company/"; var reportName = "ClientReport"; // report setup var serverReport = new ServerReport(); serverReport = ReportViewer.ServerReport; serverReport.ReportServerUrl = new Uri($@"http://{reportServer}/ReportServer"); serverReport.ReportPath = $@"{reportPath}{reportName}"; // report input var parameters = new List<ReportParameter>(); parameters.Add(new ReportParameter("User_uid", "1")); serverReport.SetParameters(parameters); // run report serverReport.Refresh(); } } } 
  7. View report - at this stage you can view your report yourself by selecting " View in browser" or Ctrl + Shift + W

    View in browser

Problem 2 - Mixing Web Forms and MVC

First, let's quickly look at the differences in routing between how these controls are loaded and subsequently updated.

  • MVC routes will look something like this: {controller}/{action}/{id} where the routing mechanism will automatically find the Controller and Action with the specified name, and incoming requests will be processed by this method. For any page request, whether it is loading a page, submitting a form, clicking a button, navigating to an attachment, or calling ajax, the exact execution method is always specified in url {action} .

  • WebForms directs to the code, finding the physical address of the .aspx page, and then uses ViewState & PostData to connect and fire events on this page / control.

    Here is an illustration of the various routing formats in WebForms . And here is a simple button click event that will send a message back to the parent page and trigger the corresponding events on the page based on the sent event data:

    ASP.NET WebForms - Postback

This is a pretty big limitation on our affordable solutions. There is nothing special about the ReportViewer control. This is just a complex set of UserControl classes that respond to clicks and other input events, sending back the current address along with the ViewState and event information. Therefore, any assumptions that were included in the routing and navigation of ReportViewer should be stored in our MVC shell.

  1. Option 1 - Add a route for the .aspx page

    Starting with MVC 4. 0+, you can use URL routing with WebForms . This works well with MVC by adding a Map Page Route (note the portion of the page ) to map the route to a physical file. Therefore, add the following to your RouteConfig.cs :

     routes.MapPageRoute( routeName: "ReportViewer", routeUrl: "ReportViewer/{reportName}", physicalFile: "~/ReportViewerPage.aspx" ); 

    The report will run at ~/Reports/reportName at ~/Reports/reportName . This is likely to be called from within the controller action, possibly with some user-entered parameters or web.config connection strings. There are many ways to manage state in ASP.NET and pass values ​​to ASP.NET web form pages . One option is to save the information in the session and redirect, for example, to your controller:

     HttpContext.Session[reportSetup.ReportName] = new ReportSetup() {ReportName = "ClientReport"}; //reportSetup;} return RedirectToRoute("ReportViewer", new { reportName = reportSetup.ReportName}); 

    Then, on the .aspx page, you can get reportName from RouteData values ​​and any installation parameters from the session:

     // get report name from route string reportName = Page.RouteData.Values["reportName"].ToString(); // get model from session and clear ReportSetup setup = (ReportSetup)HttpContext.Current.Session[reportName]; 

    Pros :

    • Most routing seems to work by default, and AJAX controls are working fine, so you can set AyncRendering=True

    Cons :

    • It is difficult to use an ASP web form with a Razor MVC layout, so rendering will pull users out of the rest of the application stream.
    • In addition, report values ​​must be presented as part of the URL or passed indirectly through the session (as opposed to hydrating directly to the object).
  2. Option 2. .ascx in PartialView on your page

    Adapted from How can I use a ReportViewer control with Razor? , you can use the .ascx control .ascx in PartialViews if they inherit from System.Web.Mvc.ViewUserControl .

    Create a new Web Forms user control named ReportViewerControl.ascx that looks like this:

     <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ReportViewerControl.ascx.cs" Inherits="MVCAppWithReportViewer.ReportViewerControl" %> <%@ Register TagPrefix="rsweb" Namespace="Microsoft.Reporting.WebForms" Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %> <form id="form1" runat="server"> <rsweb:ReportViewer ID="ReportViewer" runat="server" Height="100%" Width="100%" SizeToReportContent="True" ProcessingMode="Remote" AsyncRendering="False" /> <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="false" /> </form> 

    Note You must set AsyncRendering="False" and EnablePartialRendering="false"

    In the code below, you need to replace the inheritance type from System.Web.UI.UserControl with System.Web.Mvc.ViewUserControl .

    And in Page_Init you need to set for Context.Handler Page so that events are logged correctly.

    Therefore, ReportViewerControl.ascx.cs should look like this:

     public partial class ReportViewerControl : System.Web.Mvc.ViewUserControl { protected void Page_Init(object sender, EventArgs e) { // Required for report events to be handled properly. Context.Handler = Page; } protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { /* ... report setup ... */ serverReport.Refresh(); } } } 

    To display a report, add the following to your controller view:

     @Html.Partial("ReportViewerControl", Model) 

    And then in the Page_Load event ReportViewerControl.ascx.cs you can get the passed model from the ViewUserControl.Model property for example:

     ReportSetup setup = (ReportSetup)Model; 

    Pros :

    • Can be embedded in the _layout.cshtml and used in regular views
    • Can pass the model directly

    Cons :

    • AsyncRendering must be set to false, so interactions such as pagination and sorting cause a full page refresh and sometimes fail. Brian Hartman has a ReportViewer-only blog and talks about AsyncRendering and everything about it .

Further reading :

  • How can I use a ReportViewer control in an ASP.NET MVC 3 razor view?
  • How to display a remote ReportXer ASPX page in MVC 4?
  • MVC 5 & SSRS ReportViewer - how to implement?
+10
Dec 01 '14 at 15:28
source share

It is a little simple and will require a little correction in order to convey something decent for presentation in MVC

 public ActionResult Index() { /*Credentials of a user that has access to SSRS*/ string userid = "UserId"; string password = "MyPassword"; string domain = "MyDomain"; string reportURL="http://ServerName/ReportServer?/ReportsFolder/ReportName&Parameter=UserName&rs:Command=Render&rs:Format=PDF"; NetworkCredential nwc = new NetworkCredential(userid, password, domain); WebClient client = new WebClient(); client.Credentials = nwc; Byte[] pageData = client.DownloadData(reportURL); Response.ContentType = "application/pdf"; Response.AddHeader("Content-Disposition", "attachment; filename=" + DateTime.Now); Response.BinaryWrite(pageData); Response.Flush(); Response.End(); //return View(); } 
+4
Jul 03 2018-12-12T00:
source share

A simple solution is to add an iframe to your MVC view, which opens the report you want from the Reporting Services web service. IFrame will fully work with components from reporting services. The parameters used for the url in the iframe can also be controlled dynamically (for example, using ajax) if you want to move the components to your MVC view.

Although this works, you still have to log in to the web reporting service (iframe will open the login dialog). For IE, this is "automatically" done using Windows login credentials.

+3
Oct 26 2018-11-11T00:
source share

I use this link below as a link and it works in our Prod environment

https://github.com/GaoxinHuang/SSRSDemo

0
May 23 '19 at 9:55
source share



All Articles