Есть ли способ разместить средство просмотра отчетов отчетов служб отчетов SQL Server в представлении MVC ASP.net? Если нет... что это лучший способ сделать это?
Просмотр отчетов SSRS на сайте ASP.net MVC
Ответ 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.
Ответ 4
Реализация элемента управления SSRS ReportViewer в MVC состоит из двух проблем:
- Как минимум, вам необходимо добавить правильные зависимости, обработчики и конфигурацию для элемента управления ReportViewer (независимо от типа проекта).
- Более сложное препятствие заключается в смешивании веб-форм и MVC. Нам нужен способ отрисовки и маршрутизации входящих запросов, чтобы они обрабатывались страницами, элементами управления и действиями WebForms.
Проблема 1 - Настройка ReportViewer
Если вы уже много сделали с настройкой элементов управления ReportViewer в прошлом, это может быть старая проблема, и вы можете перейти к разделу 2.
-
Добавить пакет/ссылку. Элемент управления
ReportViewer
вMicrosoft.ReportViewer.WebForms.dll
. Вы можете включить в свой проект, добавив пакетMicrosoft.ReportViewer.WebForms
из nuget: -
Обработчики 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
Проблема 2 - Смешивание веб-форм и MVC
Во-первых, давайте быстро разберем различия в маршрутизации между тем, как эти элементы управления загружаются и впоследствии обновляются.
-
Маршруты MVC будут выглядеть примерно так:
{controller}/{action}/{id}
где механизм маршрутизации автоматически найдетController
иAction
с указанным именем, и входящие запросы будут обрабатываться этим методом. При любом запросе страницы, будь то загрузка страницы, отправка формы, нажатие кнопки, навигация по привязке или вызовы ajax, точный выполняемый метод всегда указывается в url{action}
. -
WebForms направляет к коду, находя физический адрес страницы .aspx, а затем использует ViewState & PostData для подключения и запуска событий на этой странице/элементе управления.
Вот иллюстрация различных форматов маршрутизации в WebForms. А здесь простое событие нажатия кнопки, которое отправит сообщение обратно на родительскую страницу и вызовет соответствующие события на странице на основе отправленных данных события:
Это довольно большое ограничение на наши доступные решения. В элементе управления 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 или передаваться косвенно через сеанс (в отличие от гидратации непосредственно на объект).
- Кажется, что большая часть маршрутизации работает по умолчанию, и элементы управления AJAX работают нормально, поэтому вы можете установить
-
Вариант 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