Просмотр отчетов SSRS на сайте ASP.net MVC
Есть ли способ разместить средство просмотра отчетов отчетов служб отчетов SQL Server в представлении MVC ASP.net? Если нет... что это лучший способ сделать это?
Ответы
Ответ 1
Нет, не в представлении MVC. Но вы можете иметь страницы веб-форм, в которых у них есть серверные элементы, смешанные с вашим сайтом MVC.
Хм, просто запустил "mix asp.net mvc и веб-формы", чтобы найти несколько примеров, и google спросил, я человек или нет:)
В любом случае, здесь ссылка - http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc - там несколько. Я также сделал это на сайте MVC по той же причине - контроль отчета.
Ответ 2
Нет, элемент управления ReportViewer не будет работать, если вы разместите его в представлении MVC, поскольку для него требуется ViewState. Вам нужно будет создать веб-форму старой школы и вместо этого поставить ReportViewer.
Решением, которое я использовал в проекте, над которым я работал, было создание настраиваемого обработчика маршрутов, поэтому я все же мог использовать маршрутизацию URL. Обработчик маршрута принимает такие параметры, как имя отчета из коллекции RouteData, создает экземпляр моей веб-формы и передает параметры ему через общедоступные свойства. Веб-форма будет читать их в 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, большая часть этого может быть выполнена автоматически
Ответ 3
Теперь есть помощник MvcReportViewer. Мы можем получить его от NuGet.
Сайт проекта на GitHub
Пакет NuGet
Ответ 4
Реализация элемента управления SSRS ReportViewer в MVC состоит из двух проблем:
- Как минимум, вам необходимо добавить правильные зависимости, обработчики и конфигурацию для элемента управления ReportViewer (независимо от типа проекта).
- Более сложное препятствие заключается в смешивании веб-форм и MVC. Нам нужен способ отрисовки и маршрутизации входящих запросов, чтобы они обрабатывались страницами, элементами управления и действиями WebForms.
Проблема 1 - Настройка ReportViewer
Если вы уже много сделали с настройкой элементов управления ReportViewer в прошлом, это может быть старая проблема, и вы можете перейти к разделу 2.
-
Добавить пакет/ссылку. Элемент управления ReportViewer
в Microsoft.ReportViewer.WebForms.dll
. Вы можете включить в свой проект, добавив пакет Microsoft.ReportViewer.WebForms
из nuget:
![Nuget - Microsoft.ReportViewer.WebForms]()
-
Обработчики Web.config. В соответствии с этой статьей, посвященной настройкам Web.config для ReportViewer, и на этот вопрос SO вам необходимо добавить в файл 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>
В ответ на этот вопрос о дубликатах ключей, как правило, легче всего удалить, а затем повторно добавить настройки веб-сервера.
-
Исправьте испорченные запросы изображений - в ReportViewer обнаружен дефект с blank.gif
изображениями global.asax.cs
поэтому вы можете добавить следующее исправление в ваш 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 - если его там еще нет, обязательно разрешите ScriptResources в вашем RouteConfig.cs
:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
-
Добавить ReportViewerPage.aspx - добавить страницу WebForm, которая будет содержать экземпляр элемента управления ReportViewer. Для работы этому <form runat="server" >
управления необходимо найти элемент управления ScriptManager
и поместить его в <form runat="server" >
.
Итак, ваша новая страница .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>
-
Подключите ReportViewer к 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([email protected]"http://{reportServer}/ReportServer");
serverReport.ReportPath = [email protected]"{reportPath}{reportName}";
// report input
var parameters = new List<ReportParameter>();
parameters.Add(new ReportParameter("User_uid", "1"));
serverReport.SetParameters(parameters);
// run report
serverReport.Refresh();
}
}
}
-
Просмотр отчета - на этом этапе вы сможете просматривать свой отчет самостоятельно, выбрав " Просмотр в браузере" или Ctrl + Shift + W
![View in Browser]()
Проблема 2 - Смешивание веб-форм и MVC
Во-первых, давайте быстро разберем различия в маршрутизации между тем, как эти элементы управления загружаются и впоследствии обновляются.
-
Маршруты MVC будут выглядеть примерно так: {controller}/{action}/{id}
где механизм маршрутизации автоматически найдет Controller
и Action
с указанным именем, и входящие запросы будут обрабатываться этим методом. При любом запросе страницы, будь то загрузка страницы, отправка формы, нажатие кнопки, навигация по привязке или вызовы ajax, точный выполняемый метод всегда указывается в url {action}
.
-
WebForms направляет к коду, находя физический адрес страницы .aspx, а затем использует ViewState & PostData для подключения и запуска событий на этой странице/элементе управления.
Вот иллюстрация различных форматов маршрутизации в WebForms. А здесь простое событие нажатия кнопки, которое отправит сообщение обратно на родительскую страницу и вызовет соответствующие события на странице на основе отправленных данных события:
![ASP.NET WebForms - Postback]()
Это довольно большое ограничение на наши доступные решения. В элементе управления ReportViewer
нет ничего особенного. Это просто сложный набор классов UserControl, которые реагируют на нажатия и другие входные события, отправляя обратно текущий адрес вместе с ViewState и информацией о событии. Поэтому любые предположения, которые были включены в маршрутизацию и навигацию ReportViewer, должны сохраняться в нашей оболочке MVC.
-
Вариант 1 - Добавить маршрут для страницы .aspx
Начиная с MVC 4. 0+ вы можете использовать URL-маршрутизацию с WebForms. Это хорошо сочетается с MVC, добавляя Map Page Route
(обратите внимание на часть страницы), чтобы сопоставить маршрут с физическим файлом. Поэтому добавьте следующее в ваш RouteConfig.cs
:
routes.MapPageRoute(
routeName: "ReportViewer",
routeUrl: "ReportViewer/{reportName}",
physicalFile: "~/ReportViewerPage.aspx"
);
Отчет будет запущен при ~/Reports/reportName
по адресу ~/Reports/reportName
. Это, вероятно, будет вызываться изнутри действия контроллера, возможно, с некоторыми введенными пользователем параметрами или строками соединения web.config. Существует множество способов управления состоянием в ASP.NET и передачи значений на страницы веб-форм ASP.NET. Один из вариантов - сохранить информацию в сеансе и перенаправить, например, в свой контроллер:
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
Минусы:
- Трудно использовать веб-форму ASP с макетом Razor MVC, поэтому рендеринг выведет пользователей из потока остальной части приложения.
- Кроме того, значения отчета должны быть представлены как часть URL или передаваться косвенно через сеанс (в отличие от гидратации непосредственно на объект).
-
Вариант 2. .ascx
в PartialView
на своей странице
Адаптировано из Как я могу использовать элемент управления ReportViewer с Razor? , вы можете использовать .ascx
управления .ascx
в PartialViews, если они наследуются от System.Web.Mvc.ViewUserControl
.
Создайте новый пользовательский элемент управления Web Forms с именем 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)
А затем в событии Page_Load ReportViewerControl.ascx.cs вы можете получить переданную модель из свойства ViewUserControl.Model
например:
ReportSetup setup = (ReportSetup)Model;
Плюсы:
- Можно встроить в мастер
_layout.cshtml
и использовать в обычных представлениях - Может пройти модель напрямую
Минусы:
-
AsyncRendering
должно быть установлено значение false, поэтому такие взаимодействия, как разбиение на страницы и сортировка, вызывают полное обновление страницы и иногда являются неудачными. Брайан Хартман имеет блог только для ReportViewer и рассказывает об AsyncRendering и обо всем, что с ним связано.
Дальнейшее чтение:
Ответ 5
Это немного просто и потребует немного исправления, чтобы передать что-то приличное для представления в 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
Простым решением является добавление iframe к вашему представлению MVC, который открывает отчет, который вы хотите, из веб-службы служб отчетов. IFrame будет полностью работать с компонентами от служб отчетности. Параметры, используемые для url в iframe, также могут управляться динамически (например, с помощью ajax), если вы хотите переместить компоненты в свой MVC-просмотр.
Хотя это работает, вам все равно придется войти в службу веб-отчетов (iframe откроет диалоговое окно входа в систему). Для IE это "автоматически" выполняется с использованием учетных данных входа в Windows.
Ответ 7
Я использую эту ссылку ниже в качестве ссылки и она работает в нашей среде Prod
https://github.com/GaoxinHuang/SSRSDemo