如何在MVC4中呈现远程ReportViewer aspx页面?

时间:2021-07-26 07:17:13

I'm working on an MVC4 application that needs to render a remote report from SSRS using the ReportViewer. With help from this forum, I've managed to get the page to render under MVC, but callbacks won't work (loads the initial page). Exporting the report works fine (and gives all pages). When I inspect the page, I noticed the following error after changing pages:

我正在开发一个MVC4应用程序,它需要使用ReportViewer从SSRS呈现一个远程报告。在这个论坛的帮助下,我设法使页面在MVC下呈现,但是回调不起作用(加载初始页面)。导出报表可以正常工作(并提供所有页面)。当我查看页面时,我注意到以下错误:

Uncaught Sys.WebForms.PageRequestManagerParserErrorException: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed.

未捕获Sys.WebForms。PageRequestManagerParserErrorException:Sys.WebForms。PageRequestManagerParserErrorException:无法解析从服务器接收的消息。

I found this article on combining MVC and Web Forms, but it appears outdated since there are no more Master layout pages. This is related to but not a duplicate of How can I use a reportviewer control in an asp.net mvc 3 razor view? since that article is only for local reports. I've tried changing AsyncRendering to true and false. When true, it doesn't load at all. Any suggestions would be greatly appreciated.

我发现这篇关于结合MVC和Web表单的文章已经过时了,因为已经没有主布局页面了。这与如何在asp.net mvc 3 razor视图中使用reportviewer控件有关,但不是副本。因为那篇文章只针对本地报告。我尝试过将异步转换为真和假。如果为真,则完全不加载。如有任何建议,我们将不胜感激。

Update: AsyncRendering behavior appears to have changed between previous versions of Visual Studio.

更新:在Visual Studio的以前版本之间,异步行为似乎已经发生了变化。

3 个解决方案

#1


6  

In the end, I ended up having to ditch both my original answer and the callbacks criteria due to the unacceptable security risks. In my case, I wrote controller code rendering the report as HTML to a byte array and from there to a FileContentResult that MVC was kind enough to render as a static HTML page. Exporting as PDF, Excel, or any other options will eventually be implemented in a similar method by changing the Render parameter from HTML4.0 to whatever is appropriate (PDF,XLS) and the MIME type. This approach works with SQL Server 2008R2 and beyond. I haven't tried it with previous versions of SQL Server.

最后,由于无法接受的安全风险,我不得不放弃原来的答案和回调标准。在我的例子中,我编写了控制器代码,将报告呈现为HTML到一个字节数组,然后从这里到一个FileContentResult, MVC很好地呈现为一个静态HTML页面。将呈现参数从HTML4.0更改为适当的(PDF、XLS)和MIME类型,最终将以类似的方式实现以PDF、Excel或任何其他选项导出。这种方法适用于SQL Server 2008R2及以上版本。我还没有在以前的SQL Server版本中尝试过。

[OutputCache(Duration = 120, VaryByParam = "id")]
public ActionResult ExportHTML(int id)
{
    // we need to add code to check the user's access to the preliminary report.
    // Also need to consolidate code between ExportHTML and ExportPDF.
    var userid = <userid>;
    var password = <password>;
    var domain = <domain>;
    IReportServerCredentials irsc = new myApp.Models.CustomReportCredentials(userid,
        password, domain);
    var parametersCollection = new List<ReportParameter>();
    parametersCollection.Add(new ReportParameter("Snapshot", id.ToString(), false));
    ReportViewer rv = new Microsoft.Reporting.WebForms.ReportViewer();
    rv.ProcessingMode = ProcessingMode.Remote;
    rv.ServerReport.ReportServerCredentials = irsc;
    rv.ServerReport.ReportPath = <reportpath>;
    rv.ServerReport.ReportServerUrl = new Uri("http://localhost/ReportServer");
    rv.ServerReport.SetParameters(parametersCollection);

    rv.ServerReport.Refresh();
    byte[] streamBytes = null;
    string mimeType = "";
    string encoding = "";
    string filenameExtension = "";
    string[] streamids = null;
    Warning[] warnings = null;

    streamBytes = rv.ServerReport.Render("HTML4.0", null, out mimeType, out encoding,
                                         out filenameExtension, out stream ids,
                                         out warnings);
    var HTMLReport = File(streamBytes, "text/html");
    return HTMLReport;
}

#2


0  

I'm still hoping for a better answer but in the meantime, my solution appears to satisfy the criteria. It makes use of the Kendo Web Window (so I suppose you could theoretically write your own using jQuery). I haven't modified it yet to pass parameters, but it's a start. I also haven't secured the redirect action, so it's currently possible for a user to view the source, grab the URL from the jQuery load, go to that address and get the underlying report URL from there. I'm going to look into marking it as a ChildActionOnly or some other means of insuring that the action is only available to my window. I also found that I can render the report to HTML4.0, stuff that in a FileResult and load the content that way as well - but then the report is static HTML.

我仍然希望得到一个更好的答案,但同时,我的解决方案似乎满足了标准。它利用了Kendo Web窗口(因此我认为理论上您可以使用jQuery编写自己的)。我还没有修改它来传递参数,但是这是一个开始。我还没有保护重定向操作,所以目前用户可以查看源文件、从jQuery加载中获取URL、访问该地址并从那里获取底层报告URL。我打算把它标记为仅为ChildActionOnly或其他一些方法来确保这个动作只对我的窗口可用。我还发现,我可以将报告呈现给HTML4.0,这些内容在FileResult中,并以这种方式加载内容——但是报告是静态HTML。

View:

观点:

    @(Html.Kendo().Grid(Model)
    .Name("IndexGrid")
    .Columns(col => 
    {
        col.Bound(c => c.SchoolYear);
        col.Bound(c => c.SubmissionTypeDesc);
        col.Bound(c => c.EntityDesc);
        col.Bound(c => c.SubmissionDate);
        col.Bound(c => c.UserName);
        col.Bound(c => c.Certified);
        col.Command(c => 
            {
                c.Custom("Edit")
                    .Text("View")
                    .Action("Edit", "Draft");
                c.Custom("Preview")
                    .Click("windowOpen");
                c.Custom("Certify")
                    .Action("Certify", "Draft");
                c.Custom("Download")
                    .Action("DumpExcel", "Draft");
            }
            ).Title("<b>Actions</b>")
            .HtmlAttributes(new { style = "width:200px;" });
    })
    .DataSource(ds => ds.Server()
        .Model(model => model.Id(pk => pk.snapshot_id))
        )
    .Sortable(sort => sort.Enabled(true).SortMode(GridSortMode.MultipleColumn).AllowUnsort(true))
    .Reorderable(reorder => reorder.Columns(true))
    .Groupable(group => group.Enabled(true))
    )
</article>

@(Html.Kendo().Window()
      .Name("window") //The name of the window is mandatory. It specifies the "id" attribute of the widget.
      .Title("Preliminary Report") //set the title of the window
      .LoadContentFrom("Redir", "Reports") //define the Action and Controller name
      .Visible(false)
      .Iframe(true)
      .Resizable()
      .Width(750)
      .Height(500)
      .Scrollable(false)
      .Draggable()
          .Actions(a =>
          {
              a.Refresh();
              a.Minimize();
              a.Maximize();
              a.Close();
          })

)
<script>
    function windowOpen(e) {
        e.preventDefault();
        var window = $("#window").data("kendoWindow");
        window.open();
    }
</script>

ReportController snippet:

ReportController片段:

public ActionResult Redir()
{
    return RedirectPermanent("../ASPReports/ReportForm.aspx");
}

ReportForm.aspx:

ReportForm.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="~/ASPReports/ReportForm.aspx.cs" Inherits="MyApp.Reports.ReportForm"%>

<%@ 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 id="Head1" runat="server">
    <title></title>
</head>
<body>
    <form id="reportForm" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
        <rsweb:ReportViewer ID="mainReportViewer" runat="server"  SizeToReportContent="true">
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

ReportForm.aspx.cs (code-behind):

ReportForm.aspx。cs(后台代码):

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        // credentials - could pull from config
        var userid = ""; 
        var password = "";
        var domain = "";

        IReportServerCredentials irsc = new CustomReportCredentials(userid, password, domain);
        mainReportViewer.ServerReport.ReportServerCredentials = irsc;

        //mainReportViewer.ServerReport.ReportServerUrl =
        //    new Uri(ConfigurationManager.AppSettings["ReportServerUrl"]);
        mainReportViewer.ServerReport.ReportServerUrl =
            new Uri("http://localhost/ReportServer");
        mainReportViewer.ServerReport.ReportPath = "Path";


        mainReportViewer.ProcessingMode = ProcessingMode.Remote;
        mainReportViewer.ShowParameterPrompts = false;
        mainReportViewer.ShowRefreshButton = false;
        mainReportViewer.ShowWaitControlCancelLink = false;
        mainReportViewer.ShowBackButton = false;
        mainReportViewer.ShowCredentialPrompts = false;
        var parametersCollection = new List<ReportParameter>();
        //parametersCollection.Add(new ReportParameter("Snapshot", "##", false));
        mainReportViewer.ServerReport.SetParameters(parametersCollection);
        mainReportViewer.ServerReport.Refresh();
    }
}

#3


-1  

Just use IFRAME. Create another web site or virtual directory, create application using Web Forms and then show his report viewer pages inside IFRAME on MVC application. You can set report parameters using query string. I have many times placed the report viewer into different systems using this way.

只使用IFRAME。创建另一个web站点或虚拟目录,使用web表单创建应用程序,然后在MVC应用程序的IFRAME中显示他的报表查看器页面。可以使用查询字符串设置报表参数。我多次使用这种方法将报表查看器放置到不同的系统中。

#1


6  

In the end, I ended up having to ditch both my original answer and the callbacks criteria due to the unacceptable security risks. In my case, I wrote controller code rendering the report as HTML to a byte array and from there to a FileContentResult that MVC was kind enough to render as a static HTML page. Exporting as PDF, Excel, or any other options will eventually be implemented in a similar method by changing the Render parameter from HTML4.0 to whatever is appropriate (PDF,XLS) and the MIME type. This approach works with SQL Server 2008R2 and beyond. I haven't tried it with previous versions of SQL Server.

最后,由于无法接受的安全风险,我不得不放弃原来的答案和回调标准。在我的例子中,我编写了控制器代码,将报告呈现为HTML到一个字节数组,然后从这里到一个FileContentResult, MVC很好地呈现为一个静态HTML页面。将呈现参数从HTML4.0更改为适当的(PDF、XLS)和MIME类型,最终将以类似的方式实现以PDF、Excel或任何其他选项导出。这种方法适用于SQL Server 2008R2及以上版本。我还没有在以前的SQL Server版本中尝试过。

[OutputCache(Duration = 120, VaryByParam = "id")]
public ActionResult ExportHTML(int id)
{
    // we need to add code to check the user's access to the preliminary report.
    // Also need to consolidate code between ExportHTML and ExportPDF.
    var userid = <userid>;
    var password = <password>;
    var domain = <domain>;
    IReportServerCredentials irsc = new myApp.Models.CustomReportCredentials(userid,
        password, domain);
    var parametersCollection = new List<ReportParameter>();
    parametersCollection.Add(new ReportParameter("Snapshot", id.ToString(), false));
    ReportViewer rv = new Microsoft.Reporting.WebForms.ReportViewer();
    rv.ProcessingMode = ProcessingMode.Remote;
    rv.ServerReport.ReportServerCredentials = irsc;
    rv.ServerReport.ReportPath = <reportpath>;
    rv.ServerReport.ReportServerUrl = new Uri("http://localhost/ReportServer");
    rv.ServerReport.SetParameters(parametersCollection);

    rv.ServerReport.Refresh();
    byte[] streamBytes = null;
    string mimeType = "";
    string encoding = "";
    string filenameExtension = "";
    string[] streamids = null;
    Warning[] warnings = null;

    streamBytes = rv.ServerReport.Render("HTML4.0", null, out mimeType, out encoding,
                                         out filenameExtension, out stream ids,
                                         out warnings);
    var HTMLReport = File(streamBytes, "text/html");
    return HTMLReport;
}

#2


0  

I'm still hoping for a better answer but in the meantime, my solution appears to satisfy the criteria. It makes use of the Kendo Web Window (so I suppose you could theoretically write your own using jQuery). I haven't modified it yet to pass parameters, but it's a start. I also haven't secured the redirect action, so it's currently possible for a user to view the source, grab the URL from the jQuery load, go to that address and get the underlying report URL from there. I'm going to look into marking it as a ChildActionOnly or some other means of insuring that the action is only available to my window. I also found that I can render the report to HTML4.0, stuff that in a FileResult and load the content that way as well - but then the report is static HTML.

我仍然希望得到一个更好的答案,但同时,我的解决方案似乎满足了标准。它利用了Kendo Web窗口(因此我认为理论上您可以使用jQuery编写自己的)。我还没有修改它来传递参数,但是这是一个开始。我还没有保护重定向操作,所以目前用户可以查看源文件、从jQuery加载中获取URL、访问该地址并从那里获取底层报告URL。我打算把它标记为仅为ChildActionOnly或其他一些方法来确保这个动作只对我的窗口可用。我还发现,我可以将报告呈现给HTML4.0,这些内容在FileResult中,并以这种方式加载内容——但是报告是静态HTML。

View:

观点:

    @(Html.Kendo().Grid(Model)
    .Name("IndexGrid")
    .Columns(col => 
    {
        col.Bound(c => c.SchoolYear);
        col.Bound(c => c.SubmissionTypeDesc);
        col.Bound(c => c.EntityDesc);
        col.Bound(c => c.SubmissionDate);
        col.Bound(c => c.UserName);
        col.Bound(c => c.Certified);
        col.Command(c => 
            {
                c.Custom("Edit")
                    .Text("View")
                    .Action("Edit", "Draft");
                c.Custom("Preview")
                    .Click("windowOpen");
                c.Custom("Certify")
                    .Action("Certify", "Draft");
                c.Custom("Download")
                    .Action("DumpExcel", "Draft");
            }
            ).Title("<b>Actions</b>")
            .HtmlAttributes(new { style = "width:200px;" });
    })
    .DataSource(ds => ds.Server()
        .Model(model => model.Id(pk => pk.snapshot_id))
        )
    .Sortable(sort => sort.Enabled(true).SortMode(GridSortMode.MultipleColumn).AllowUnsort(true))
    .Reorderable(reorder => reorder.Columns(true))
    .Groupable(group => group.Enabled(true))
    )
</article>

@(Html.Kendo().Window()
      .Name("window") //The name of the window is mandatory. It specifies the "id" attribute of the widget.
      .Title("Preliminary Report") //set the title of the window
      .LoadContentFrom("Redir", "Reports") //define the Action and Controller name
      .Visible(false)
      .Iframe(true)
      .Resizable()
      .Width(750)
      .Height(500)
      .Scrollable(false)
      .Draggable()
          .Actions(a =>
          {
              a.Refresh();
              a.Minimize();
              a.Maximize();
              a.Close();
          })

)
<script>
    function windowOpen(e) {
        e.preventDefault();
        var window = $("#window").data("kendoWindow");
        window.open();
    }
</script>

ReportController snippet:

ReportController片段:

public ActionResult Redir()
{
    return RedirectPermanent("../ASPReports/ReportForm.aspx");
}

ReportForm.aspx:

ReportForm.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="~/ASPReports/ReportForm.aspx.cs" Inherits="MyApp.Reports.ReportForm"%>

<%@ 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 id="Head1" runat="server">
    <title></title>
</head>
<body>
    <form id="reportForm" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
        <rsweb:ReportViewer ID="mainReportViewer" runat="server"  SizeToReportContent="true">
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

ReportForm.aspx.cs (code-behind):

ReportForm.aspx。cs(后台代码):

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        // credentials - could pull from config
        var userid = ""; 
        var password = "";
        var domain = "";

        IReportServerCredentials irsc = new CustomReportCredentials(userid, password, domain);
        mainReportViewer.ServerReport.ReportServerCredentials = irsc;

        //mainReportViewer.ServerReport.ReportServerUrl =
        //    new Uri(ConfigurationManager.AppSettings["ReportServerUrl"]);
        mainReportViewer.ServerReport.ReportServerUrl =
            new Uri("http://localhost/ReportServer");
        mainReportViewer.ServerReport.ReportPath = "Path";


        mainReportViewer.ProcessingMode = ProcessingMode.Remote;
        mainReportViewer.ShowParameterPrompts = false;
        mainReportViewer.ShowRefreshButton = false;
        mainReportViewer.ShowWaitControlCancelLink = false;
        mainReportViewer.ShowBackButton = false;
        mainReportViewer.ShowCredentialPrompts = false;
        var parametersCollection = new List<ReportParameter>();
        //parametersCollection.Add(new ReportParameter("Snapshot", "##", false));
        mainReportViewer.ServerReport.SetParameters(parametersCollection);
        mainReportViewer.ServerReport.Refresh();
    }
}

#3


-1  

Just use IFRAME. Create another web site or virtual directory, create application using Web Forms and then show his report viewer pages inside IFRAME on MVC application. You can set report parameters using query string. I have many times placed the report viewer into different systems using this way.

只使用IFRAME。创建另一个web站点或虚拟目录,使用web表单创建应用程序,然后在MVC应用程序的IFRAME中显示他的报表查看器页面。可以使用查询字符串设置报表参数。我多次使用这种方法将报表查看器放置到不同的系统中。