在 ASP.net MVC 站点中查看 s-s-rS 报告

Posted

技术标签:

【中文标题】在 ASP.net MVC 站点中查看 s-s-rS 报告【英文标题】:Viewing s-s-rS Reports in an ASP.net MVC Site 【发布时间】:2011-05-07 11:22:46 【问题描述】:

有没有办法将 SQL Server Reporting Services 报表查看器控件放在 ASP.net MVC 视图上?如果不是...实现此目的的最佳方法是什么?

【问题讨论】:

我建议添加另一个带有老式 ReprtViewer 和 WebForms 的网站,并将其指向主网站的子文件夹,甚至使用 IFRAME。这是一个干净的解决方案。 【参考方案1】:

不,不在 MVC 视图中。但是您可以将包含服务器控件的 Web 表单页面与您的 MVC 站点混合在一起。

嗯,刚刚google了“mix asp.net mvc and web forms”来找一些例子,google质疑我是不是人:)

无论如何,这里有一个链接 - http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc - 那里有几个。出于同样的原因,我也在 MVC 站点中执行此操作 - 报告控件。

【讨论】:

谢谢。我想可能是这种情况。当您将 WebForms 页面添加到您的 MVC 应用程序时,是否有任何方法可以创建一个“路由”,让您拥有一个漂亮的 URL,而不是看到类似 www.foobar.com/reports/report.aspx 之类的东西? 是的,有 - 你使用的是什么版本的 asp.net?如果是 4.0,请查看 ScottGu 的博客 - weblogs.asp.net/scottgu/archive/2009/10/13/…。如果不是,我不确定 - 还没有这样做。【参考方案2】:

不,如果您将 ReportViewer 控件放在 MVC 视图中,它将无法工作,因为它需要 ViewState。您必须创建一个老式 Web 表单并将 ReportViewer 放在那里。

我在一个项目中使用的一个解决方案是创建一个自定义路由处理程序,这样我仍然可以使用 URL 路由。路由处理程序将从 RouteData 集合中获取报告名称等参数,创建我的 Web 表单的实例,并通过公共属性将参数传递给它。 Web 表单将在 Page_Load 中读取这些内容并配置 ReportViewer 控件。

// 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;
    

当然,如果您决定使用这种方法,这段代码只是一个起点。我创建的那个也在返回之前做了一些用户认证和参数验证。

更新:看起来如果您使用的是 ASP.NET 4.0,most of this can be done automatically!

【讨论】:

【参考方案3】:

在 MVC 中实现一个 s-s-rS ReportViewer 控件包含两个问题:

    至少,您需要为 ReportViewer 控件添加正确的依赖项、处理程序和配置(无论项目类型如何)。 更棘手的障碍在于混合使用 WebForms 和 MVC。我们需要一种呈现和路由传入请求的方法,以便它们将由 WebForms 页面、控件和操作处理。

问题 1 - 配置ReportViewer

如果您过去在设置 ReportViewer 控件方面做了很多工作,那么这可能已经过时了,您可以跳到第 2 部分。

    添加包/引用 - ReportViewer 控件位于 Microsoft.ReportViewer.WebForms.dll 中。您可以通过从 nuget 添加 Microsoft.ReportViewer.WebForms 包来包含在您的项目中:

    Web.config 处理程序 - 根据这篇关于 Web.config Settings for ReportViewer 和 this SO question 的文章,您需要将以下内容添加到您的 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>
    

    根据this question on duplicate keys,通常最容易删除然后重新添加网络服务器配置

    修复损坏的图像请求 - 带有blank.gif images not loading 的 ReportViewer 中存在一个已知缺陷,因此您可以将以下修复添加到您的 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"));
        
    
    

    IgnoreRoute .axd - 如果还没有,请确保在您的RouteConfig.cs 中输入allow ScriptResources:

    routes.IgnoreRoute("resource.axd/*pathInfo");
    

    添加 ReportViewerPage.aspx - 添加一个包含 ReportViewer 控件实例的 WebForm 页面。为了工作,该控件需要找到一个ScriptManager 控件并放在&lt;form runat="server" &gt; 内。 因此,您的新 .aspx 页面应如下所示:

    <%@ 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>
    

    Page_Load 上连接 ReportViewer - 假设您已经将 s-s-rS 报告完全部署到报告服务器,该报告服务器可在如下地址获得:

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

    那么您在新 WebForm 页面中的代码隐藏应该如下所示:

    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 = $@"reportPathreportName";
    
                // report input
                var parameters = new List<ReportParameter>();
                parameters.Add(new ReportParameter("User_uid", "1"));
                serverReport.SetParameters(parameters);
    
                // run report
                serverReport.Refresh();
            
        
    
    

    查看报告 - 此时您应该能够通过选择 在浏览器中查看Ctrl + Shift + W

问题 2 - 混合 WebForms 和 MVC

首先,让我们快速剖析一下这些控件的加载方式和后续更新方式之间的路由差异

MVC 路由看起来像这样controller/action/id,其中路由引擎会自动找到具有指定名称的ControllerAction,传入的请求将由它处理方法。在任何页面请求中,无论是来自页面加载、表单提交、按钮单击、锚导航还是 ajax 调用,都始终在 url action 中指定正在执行的确切方法。

WebForms 通过查找物理 .aspx 页面地址路由到代码,然后使用 ViewState 和 PostData 连接并触发该页面/控件上的事件。

这是illustration of different routing formats in WebForms。这是一个简单的按钮单击事件,它将向父页面提交一个帖子,并根据提交的事件数据在页面内引发相应的事件:

这对我们可用的解决方案是一个很大的限制。 ReportViewer 控件没有什么特别之处。它只是一组复杂的 UserControl 类,它们通过回发当前地址以及 ViewState 和 Event 信息来响应单击和其他输入事件。因此,在 ReportViewer 的路由和导航中包含的任何假设都需要保留到我们的 MVC 包装器中。

    选项 1 - 为 .aspx 页面添加路由

    从 MVC 4.0+ 开始,您可以使用 URL Routing with WebForms。这通过添加Map<b><i>Page</i></b>Route (注意页面部分)与 MVC 很好地混合,以将路由映射到物理文件。因此,将以下内容添加到您的RouteConfig.cs

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

    当您导航到地址 ~/Reports/reportName 时,报告将运行。这可能会从控制器操作内部调用,可能使用一些用户输入的参数或 web.config 连接字符串。有很多ways to manage state in ASP.NET 和Pass Values to ASP.NET Web Forms Pages。一种选择是将信息存储在 Session 中并像这样在控制器中重定向:

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

    然后,在 .aspx 页面中,您可以从 RouteData 值和会话中的任何设置参数中获取 reportName

    // 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];
    

    优点

    大部分路由似乎默认都可以,AJAX控件也可以正常工作,所以可以设置AyncRendering=True

    缺点

    use an ASP Web Form with a Razor MVC Layout 很难,因此渲染将使用户脱离应用程序的其余部分。 此外,报告值必须作为 URL 的一部分公开或通过会话间接传递(而不是直接水合到对象上)。

    选项 2 - 将 .ascx 嵌套在页面上的 PartialView

    改编自How can I use a ReportViewer control with Razor?,只要继承自System.Web.Mvc.ViewUserControl,就可以在PartialViews中使用.ascx控件。

    创建一个名为 ReportViewerControl.ascx 的新 Web 窗体用户控件,如下所示:

    <%@ 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>
    

    注意:必须设置AsyncRendering="False"EnablePartialRendering="false"

    在后面的代码中,您需要将继承类型从System.Web.UI.UserControl 替换为System.Web.Mvc.ViewUserControl

    Page_Init 上,您需要将Context.Handler 设置为Page,以便正确注册事件。

    所以ReportViewerControl.ascx.cs 应该是这样的:

    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();
            
        
    
    

    为了呈现报告,将以下内容添加到您的控制器视图中:

    @Html.Partial("ReportViewerControl", Model)
    

    然后在 ReportViewerControl.ascx.cs Page_Load 事件中,您可以从 ViewUserControl.Model 属性中检索传入的模型,如下所示:

    ReportSetup setup = (ReportSetup)Model;
    

    优点

    可以构建到 master _layout.cshtml 并在常规视图中使用 可以直接传模型

    缺点

    AsyncRendering 必须设置为 false,因此分页和排序等交互会导致整页刷新,有时会出现问题。 Brian Hartman 有一个专门针对 ReportViewer 的博客,其中谈到了 AsyncRendering and all the Baggage that Comes With It。

进一步阅读

How can I use a reportviewer control in an ASP.NET MVC 3 razor view? How do I render a remote ReportViewer aspx page in MVC 4? MVC 5 & s-s-rS ReportViewer - How to Implement?

【讨论】:

@Reddy,如果同时发布两种代码语言,答案会很长,但您只需将其复制并粘贴到 converter.telerik.com/ 即可获得相同代码的 C# 语法。 谢谢凯尔。我明白了 @KyleMit 我尝试使用你的路线,但我在我的 mvc 应用程序中得到 404,任何故障排除建议 这只是将它连接到Public Class ReportViewer : Inherits Page,这是我作为名为@9​​87654400@ 的库的一部分。当您生成 aspx 文件时,它应该会为您检测。 如果您正在运行 C#,AutoEventWireup 应该为 true,因为 Handles 关键字在 C# (AFAIK) 中没有等效项【参考方案4】:

现在有一个 MvcReportViewer 助手。我们可以从 NuGet 获取它。

Project Site on GitHub

NuGet Package

【讨论】:

您提供的两个链接都是同一个网址。【参考方案5】:

这有点简单,需要一些修复才能将一些像样的东西传递给 MVC 中的视图

public ActionResult Index()

    /*Credentials of a user that has access to s-s-rS*/
    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();
    

【讨论】:

修复一下是什么意思? 嗨,伙计。我使用您的方法下载基于 URL 的 s-s-rS 文件。我使用 webclient 默认凭据并尝试向用户返回 PDF 文件。但是用户得到一个非零大小的 PDF 文件,它是空白的。你遇到过同样的问题吗? ActionResult 方法返回 View() 被注释掉。 ??【参考方案6】:

一个简单的解决方案是将 iframe 添加到您的 MVC 视图中,以便从报告服务 Web 服务中打开您想要的报告。 iframe 将与报告服务中的组件一起完全运行。如果要将组件移到 MVC 视图中,也可以动态控制 iframe 中用于 url 的参数(例如使用 ajax)。

虽然这可行,但您仍需要登录网络报告服务(iframe 将打开一个登录对话框)。对于 IE,这是通过使用您的 Windows 登录凭据“自动”完成的。

【讨论】:

如果用户查看源代码,如何将absoluteurl隐藏到s-s-rS报告中?【参考方案7】:

您可以使用 ReportViewerForMvc 在 MVC 中查看报告,方法是使用 Nuget 安装它

Install-Package Microsoft.Report.Viewer -Version 11.0.0

Install-Package Microsoft.ReportViewer.Runtime.WebForms -Version 12.0.2402.15

Install-Package ReportViewerForMvc

如上所示安装 ReportViewer 和其他所需的 Nuget 包后,在 Visual Studio 项目中添加新的 Report.rdlc

在上面创建的report.rdlc中添加数据集

现在,在MVC中创建一个ActionMethod,它将从数据库中查询数据并返回报告

 s-s-rSInMVC.Report.Report ds = new s-s-rSInMVC.Report.Report();
    public ActionResult ReportStudent()
    
        ReportViewer reportViewer = new ReportViewer();
        reportViewer.ProcessingMode = ProcessingMode.Local;
        reportViewer.SizeToReportContent = true;
        reportViewer.Width = Unit.Percentage(900);
        reportViewer.Height = Unit.Percentage(900);

        var connectionString = ConfigurationManager.ConnectionStrings["s-s-rSInMVC.Properties.Settings.StudentsConnectionString"].ConnectionString;


        SqlConnection conx = new SqlConnection(connectionString);
        SqlDataAdapter adp = new SqlDataAdapter("SELECT * FROM Student_details", conx);

        adp.Fill(ds, ds.Student_details.TableName);

        reportViewer.LocalReport.ReportPath = Request.MapPath(Request.ApplicationPath) + @"Report\Report1.rdlc";
        reportViewer.LocalReport.DataSources.Add(new ReportDataSource("DataSet1", ds.Tables[0]));


        ViewBag.ReportViewer = reportViewer;

        return View();
    

在视图中,您有如下代码

@using ReportViewerForMvc;
@
   ViewBag.Title = "Report Student";
 
 <br/>
<br />

   @Html.ReportViewer(ViewBag.ReportViewer as Microsoft.Reporting.WebForms.ReportViewer)

就是这样,我们完成了。

参考:https://qawithexperts.com/article/asp.net/displaying-s-s-rs-sql-server-reporting-service-in-mvc-view/77

【讨论】:

【参考方案8】:

以防万一它对任何人有所帮助,我发现这些视频教程很容易理解。 (你只需要忍受第一个视频中可怕的背景音乐。

s-s-rS 2019 Report in ASP Net MVC 5

How To Filter s-s-rS 2019 Report Using Parameter

我不得不安装“ReportViewerForMvc14”而不是“ReportViewerForMvc”(在视频中使用),因为它不再可用。包装上的说明说它与原始版本相同,但只是更新为可与 ReportViewer 14.0 一起使用。

【讨论】:

以上是关于在 ASP.net MVC 站点中查看 s-s-rS 报告的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法让 Asp.net 零公共站点(Asp.net MVC)中的实时登录用户?

在 ASP.NET MVC 站点中返回视图时操作页面滚动

将Asp.Net WebAPI从AngularJS App的Asp.Net MVC站点移动到一个单独的站点

样式不适用于 ASP.NET MVC 站点

如何在 ASP .NET MVC 中使用 Resources 和 CultureInfo 更改站点语言?

为啥我的 ASP.NET MVC 站点中的此 AJAX 请求会触发预检检查?