Как сделать удаленную страницу aspx ReportViewer в MVC4?
Я работаю над приложением MVC4, которое должно отображать удаленный отчет из SSRS с помощью ReportViewer. С помощью этого форума мне удалось отобразить страницу под MVC, но обратные вызовы не будут работать (загружает начальную страницу). Экспорт отчета работает отлично (и дает все страницы). Когда я проверяю страницу, я заметил следующую ошибку после смены страниц:
Uncaught Sys.WebForms.PageRequestManagerParserErrorException: Sys.WebForms.PageRequestManagerParserErrorException: сообщение, полученное с сервера, не может быть проанализировано.
Я нашел эту статью о совмещении MVC и веб-форм, но он устарел, поскольку больше нет страниц макета макета. Это связано с, но не с дубликатом Как я могу использовать элемент управления reportviewer в представлении asp.net mvc 3 бритвы?, поскольку эта статья предназначена только для локальных отчетов. Я попытался изменить AsyncRendering на true и false. Когда оно истинно, оно вообще не загружается. Любые предложения были бы с благодарностью.
Обновление: поведение AsyncRendering изменилось между предыдущими версиями Visual Studio.
Ответы
Ответ 1
В конце концов, мне пришлось отказаться от моего первоначального ответа и критериев обратных вызовов из-за неприемлемых рисков безопасности. В моем случае я написал код контроллера, отображающий отчет как HTML в массив байтов, а оттуда - в FileContentResult, который MVC был достаточно любезен, чтобы отображать как статическую HTML-страницу. Экспорт в виде PDF, Excel или любых других вариантов в конечном итоге будет реализован аналогичным методом, изменив параметр Render с HTML4.0 на все, что подходит (PDF, XLS) и тип MIME. Этот подход работает с SQL Server 2008R2 и далее. Я не пробовал это с предыдущими версиями SQL Server.
[OutputCache(Duration = 120, VaryByParam = "id")]
public ActionResult ExportHTML(int id)
{
// we need to add code to check the user 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
Я все еще надеюсь на лучший ответ, но тем временем мое решение, похоже, удовлетворяет критериям. Он использует веб-окно Kendo (поэтому я предполагаю, что вы теоретически можете написать свой собственный, используя jQuery). Я еще не изменил его, чтобы передать параметры, но это начало. Я также не обеспечил действие перенаправления, поэтому в настоящее время пользователь может просмотреть источник, захватить URL-адрес из загрузки jQuery, перейти к этому адресу и получить от него основной URL-адрес отчета. Я собираюсь разглядеть его как ChildActionOnly или некоторые другие способы гарантировать, что действие доступно только для моего окна. Я также обнаружил, что могу отобразить отчет в формате HTML4.0, что в FileResult и загрузить контент таким же образом, - но тогда отчет является статическим HTML.
Вид:
@(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:
public ActionResult Redir()
{
return RedirectPermanent("../ASPReports/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):
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
Просто используйте IFRAME. Создайте другой веб-сайт или виртуальный каталог, создайте приложение с помощью веб-форм, а затем покажите его страницы просмотра отчетов внутри IFRAME в приложении MVC. Параметры отчета можно задать с помощью строки запроса. Я много раз размещал средство просмотра отчетов в разных системах, используя этот способ.