代码之家  ›  专栏  ›  技术社区  ›  Dismissile

在ASP.net MVC站点中查看SSRS报告

  •  50
  • Dismissile  · 技术社区  · 15 年前

    是否可以将SQL Server Reporting Services报表查看器控件放在ASP.net MVC视图上?如果不是…什么是最好的方法来实现这一点?

    6 回复  |  直到 15 年前
        1
  •  16
  •   Mike Hildner    15 年前

    不,不在MVC视图中。但是您可以有一个web表单页面,其中包含服务器控件并与MVC站点混合在一起。

    嗯,只需在谷歌上搜索“混合asp.net mvc和web表单”就可以找到一些例子,谷歌质疑我是不是人类:)

    无论如何,这里有一个链接- http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc -外面有一些。我在一个MVC站点上也做了同样的工作-报表控件。

        2
  •  14
  •   Brant Bobby    15 年前

    不,如果将ReportViewer控件放在MVC视图中,它将无法工作,因为它需要ViewState。您必须创建一个旧的学校web窗体,并将报表查看器放在那里。

    我在一个项目中使用的解决方案是创建一个自定义路由处理程序,这样我仍然可以使用URL路由。路由处理程序将从RouteData集合获取诸如报表名称之类的参数,创建web窗体的实例,并通过公共属性将参数传递给它。web表单将在Page_中读取这些内容加载并配置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;
        }
    }
    

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

    更新 most of this can be done automatically !

        3
  •  11
  •   Deilan Matt Breckon    10 年前

    现在有一个MvcReportViewer助手。我们可以从努杰那里得到。

    Project Site on GitHub

    NuGet Package

        4
  •  10
  •   KyleMit Steven Vachon    7 年前

    1. 至少,您需要添加正确的依赖项、处理程序和 ReportViewer控件的配置
    2. 更棘手的障碍是 . 我们需要一种呈现和路由传入请求的方法,这样它们将由WebForms页面、控件和操作处理。

    问题1-配置 ReportViewer

    如果您过去在设置ReportViewer控件方面做了很多工作,那么这可能是一个旧帽子,您可以跳到第2节。

    1. 添加包/引用 -那个 ReportViewer 控制生活在 Microsoft.ReportViewer.WebForms.dll . 您可以通过添加 Microsoft.ReportViewer.WebForms 来自nuget的包:

      Nuget - Microsoft.ReportViewer.WebForms

    2. 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 ,通常最容易删除然后重新添加web服务器配置

    3. -ReportViewer中有一个已知的缺陷 blank.gif images not loading 所以您可以在 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公司 -如果还没有,一定要 allow ScriptResources 在你的 RouteConfig.cs :

      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      
    5. 添加ReportViewerPage.aspx -添加将保存ReportViewer控件实例的WebForm页。为了工作,该控件需要找到 ScriptManager 控制并置于 <form runat="server" > .

      <%@ 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. 连接报表查看器 Page_Load -假设您已经将SSRS报告完全部署到一个报告服务器上,该服务器在如下地址可用:

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

      那么您在新的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 = $@"{reportPath}{reportName}";
      
                  // report input
                  var parameters = new List<ReportParameter>();
                  parameters.Add(new ReportParameter("User_uid", "1"));
                  serverReport.SetParameters(parameters);
      
                  // run report
                  serverReport.Refresh();
              }
          }
      }
      
    7. 查看报表 -此时,您应该可以通过选择 在浏览器中查看 Ctrl键 移位 +

      View in Browser

    问题2——混合WebFrand和MVC

    首先,让我们快速分析这些控件如何加载和随后更新之间的路由差异

    • 路线会像这样 {controller}/{action}/{id} Controller Action 使用指定的名称和传入的请求将由该方法处理。在任何页面请求上,无论是页面加载、表单提交、按钮单击、定位导航还是ajax调用,执行的确切方法总是在url中指定的 {action} .

    • 这是一个 illustration of different routing formats in WebForms . 下面是一个简单的按钮单击事件,它将向父页面提交一篇文章,并根据提交的事件数据在页面内引发适当的事件:

      ASP.NET WebForms - Postback

    这对我们可用的解决方案是一个很大的限制。没有什么特别的 控件 控制。它只是一组复杂的用户控件类,通过将当前地址连同ViewState和事件信息一起发回,来响应click和其他输入事件。因此,无论在ReportViewer的路由和导航中加入了什么样的假设,都需要在MVC包装器中持久化。

    1. 从MVC4.0+开始,您可以使用 URL Routing with WebForms Map Page Route (注意 部分) 将路由映射到物理文件。所以在你的 路线图.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

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

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

      // 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? ,您可以消费 partialview中的控件,只要它们继承自 System.Web.Mvc.ViewUserControl .

      创建一个名为 ReportViewerControl.ascx 看起来是这样的:

      <%@ 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页面加载事件中,可以从 ViewUserControl.Model 这样的属性:

      ReportSetup setup = (ReportSetup)Model;
      

      赞成的意见

      • 可以成为大师 _layout.cshtml 在常规视图中使用
      • 可直接传递模型

      欺骗

    进一步阅读 :

        5
  •  4
  •   Leon    13 年前

    这有点简单,需要在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();
        }
    
        6
  •  3
  •   Johncl    14 年前

    尽管这样做有效,但您仍然需要登录到web报表服务(iframe将打开一个登录对话框)。对于IE来说,这是“自动”完成的,虽然使用你的windows登录凭据。