Просмотр отчетов SSRS на сайте ASP.net MVC

Есть ли способ разместить средство просмотра отчетов отчетов служб SQL Server в представлении ASP.net MVC? Если нет … что это лучший способ сделать это?

    Нет, не в режиме MVC. Но у вас могут быть страницы веб-форм, в которых у них есть серверные элементы, смешанные с вашим сайтом MVC.

    Хм, просто поиграл в Google «mix asp.net mvc и веб-формы», чтобы найти несколько примеров, и google спросил, я человек или нет 🙂

    В любом случае, вот ссылка – http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc – там есть несколько. Я также сделал это на сайте MVC по той же причине – контроль отчета.

    Нет, элемент управления 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, большую часть этого можно сделать автоматически !

    Теперь есть помощник MvcReportViewer. Мы можем получить его от NuGet.

    Сайт проекта на GitHub

    Пакет NuGet

    Реализация управления SSRS ReportViewer в MVC состоит из двух проблем:

    1. Минимально вам нужно добавить правильные зависимости, обработчики и конфигурацию для элемента управления ReportViewer (независимо от типа проекта).
    2. Более сложное препятствие заключается в перемещении WebForms и MVC . Нам нужен способ рендеринга и маршрутизации входящих запросов, чтобы они обрабатывались страницами, элементами управления и действиями WebForms.

    Проблема 1 – Настройка ReportViewer

    Если вы уже много сделали с настройкой элементов управления ReportViewer в прошлом, это может быть старая шляпа, и вы можете перейти к разделу 2.

    1. Добавить пакет / ссылку – элемент управления ReportViewer Microsoft.ReportViewer.WebForms.dll . Вы можете включить в свой проект, добавив пакет Microsoft.ReportViewer.WebForms из nuget:

      Nuget - Microsoft.ReportViewer.WebForms

    2. Обработчики Web.config. В этой статье о настройках Web.config для ReportViewer и этом вопросе SO вам нужно добавить следующее к вашему web.config :

                  

      По этому вопросу о дублирующих ключах , как правило, проще всего удалить, а затем повторно добавить конфигурации веб-сервера

    3. Исправить сломанные запросы на изображение. В ReportViewer есть известный дефект с изображениями blank.gif которые не загружаются, поэтому вы можете добавить следующее исправление к вашему 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 – Если этого еще нет, убедитесь, что ScriptResources разрешено использовать в RouteConfig.cs :

       routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    5. Добавить ReportViewerPage.aspx – добавьте страницу WebForm, в которой будет храниться экземпляр элемента управления ReportViewer. Чтобы работать, этот элемент управления должен найти элемент управления ScriptManager и быть размещен внутри

      .
      Поэтому ваша новая страница .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" %>    Report Viewer   
    6. Подключите 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(); parameters.Add(new ReportParameter("User_uid", "1")); serverReport.SetParameters(parameters); // run report serverReport.Refresh(); } } } 
    7. Просмотр отчета – на этом этапе вы сможете просмотреть свой отчет самостоятельно, выбрав « Просмотр в браузере» или « Ctrl + Shift +

      Просмотр в браузере

    Проблема 2 – Смешивание WebForms и MVC

    Во-первых, давайте быстро проанализируем различия в маршрутизации между загрузкой этих элементов управления и последующим обновлением

    • Трассы MVC будут выглядеть примерно так: {controller}/{action}/{id} где механизм маршрутизации автоматически найдет Controller и Action с указанным именем, и входящие запросы будут обработаны этим методом. При запросе любой страницы, будь то от загрузки страницы, отправки формы, нажатия кнопок, привязки навигации или вызовов ajax, точный метод, который выполняется, всегда указывается в URL-адресе {action} .

    • WebForms маршрутизирует код, находя физический адрес страницы .aspx, а затем использует ViewState & PostData для подключения и запуска событий на этой странице / контроле.

      Вот иллюстрация различных форматов маршрутизации в WebForms . И вот простое событие нажатия кнопки, которое отправит сообщение на родительскую страницу и поднимет соответствующие события на странице на основе представленных данных события:

      ASP.NET WebForms - обратная передача

    Это довольно большое ограничение на доступные наши решения. Ничего особенного в элементе управления ReportViewer . Это просто сложный набор classов UserControl, которые реагируют на клики и другие входные события, отправив обратно текущий адрес вместе с информацией о ViewState и событии. Поэтому любые предположения, которые были испечены в маршрутизации и навигации ReportViewer, должны будут сохраняться в нашей оболочке MVC.

    1. Вариант 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 . Это, вероятно, будет вызвано изнутри действия controllerа, возможно, с некоторыми введенными пользователем параметрами или строками соединения web.config. Существует множество способов управления состоянием в ASP.NET и передача значений на страницы веб-форм ASP.NET . Один из вариантов заключается в том, чтобы скрыть информацию в сеансе и перенаправить, как это в вашем controllerе:

       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, поэтому рендеринг приведет пользователей к streamу остальной части приложения.
      • Кроме того, значения отчета должны отображаться как часть URL-адреса или передаваться косвенно через сеанс (в отличие от увлажнения непосредственно на объект).
    2. Вариант 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" %> 
      AsyncRendering="False" /> EnablePartialRendering="false" />

      Примечание . Вы должны установить 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(); } } } 

      Чтобы сделать отчет, добавьте следующее в представление controllerа:

       @Html.Partial("ReportViewerControl", Model) 

      А затем в событии ReportViewerControl.ascx.cs Page_Load вы можете получить переданную в модели свойство ViewUserControl.Model следующим образом:

       ReportSetup setup = (ReportSetup)Model; 

      Плюсы :

      • Может встраиваться в master _layout.cshtml и потреблять в обычных представлениях
      • Может передавать модель напрямую

      Минусы :

      • AsyncRendering должен быть установлен на false, поэтому взаимодействия, такие как разбиение на страницы и сортировку, вызывают полное обновление страниц и иногда неаккуратные. Брайан Хартман имеет блог только для ReportViewer и рассказывает об AsyncRendering и обо всем Багаже, который приходит с ним .

    Дальнейшее чтение :

    • Как я могу использовать элемент управления reportviewer в представлении бритвы ASP.NET MVC 3?
    • Как сделать удаленную страницу aspx ReportViewer в MVC 4?
    • MVC 5 & SSRS ReportViewer – как реализовать?

    Это немного просто и потребует немного исправления, чтобы передать что-то приличное для просмотра в 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(); } , 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(); } 

    Простым решением является добавление iframe в ваше представление MVC, которое открывает отчет, который вы хотите, из веб-службы служб отчетов. IFrame будет полностью работать с компонентами от служб отчетности. Параметры, используемые для url в iframe, также могут управляться динамически (например, с помощью ajax), если вы хотите переместить компоненты в свой MVC-просмотр.

    Хотя это работает, вам все равно придется войти в службу веб-отчетов (iframe откроет диалоговое окно входа в систему). Для IE это «автоматически» выполняется с использованием учетных данных входа в Windows.

    Давайте будем гением компьютера.