ssrs services reportes net mvc integrar create asp c# asp.net-mvc reportviewer reporting-services

c# - services - Visualización de informes de SSRS en un sitio MVC de ASP.net



reporting services mvc 5 (6)

Ahora hay un ayudante de MvcReportViewer. Podemos obtenerlo de NuGet.

Sitio del proyecto en GitHub

Paquete NuGet

¿Hay alguna manera de poner un control de visor de informes de SQL Server Reporting Services en una vista MVC de ASP.net? Si no ... ¿cuál es la mejor manera de lograr esto?


Esto es un poco simple y requerirá un poco de fijación para pasar algo decente a una vista en 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(); }


Implementar un control ReportViewer de SSRS en MVC consta de dos problemas:

  1. Como mínimo, deberá agregar las dependencias, los controladores y la configuración correctos para el control ReportViewer (independientemente del tipo de proyecto).
  2. El obstáculo más complicado está en Mixing WebForms y MVC . Necesitamos una forma de procesar y enrutar las solicitudes entrantes para que sean manejadas por las páginas, controles y acciones de WebForms.

Problema 1 - Configurar el ReportViewer

Si ha hecho mucho con la configuración de los controles ReportViewer en el pasado, esto podría ser viejo y puede saltar a la sección 2.

  1. Agregar paquete / referencia : el control ReportViewer vive en Microsoft.ReportViewer.WebForms.dll . Puede incluir en su proyecto agregando el paquete Microsoft.ReportViewer.WebForms de nuget:

  2. Controladores de Web.config : según este artículo sobre la configuración de Web.config para ReportViewer , y esta pregunta de SO , deberá agregar lo siguiente a su 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>

    Según esta pregunta sobre claves duplicadas , normalmente es más fácil de eliminar y luego volver a agregar las configuraciones del servidor web

  3. Repara solicitudes de imágenes rotas : hay un defecto conocido en ReportViewer con imágenes en blank.gif no se están cargando, por lo que puede agregar la siguiente solución a su 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 : si aún no está allí, asegúrese de permitir ScriptResources en su RouteConfig.cs :

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  5. Agregar ReportViewerPage.aspx : agregue una página WebForm que contendrá una instancia del control ReportViewer. Para funcionar, ese control necesita encontrar un control ScriptManager y colocarse dentro de un <form runat="server" > .
    Por lo tanto, su nueva página .aspx debería verse más o menos así:

    <%@ 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>

  6. Transmita ReportViewer en Page_Load - Suponiendo que ya tiene un informe SSRS completamente implementado en un servidor de informes que está disponible en una dirección como esta:

    http:// ReportServerName /Reports/Pages/Report.aspx?ItemPath= %2fCompany%2f ClientReport

    Entonces, su código subyacente en su nueva página WebForm debería verse así:

    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($@"http://{reportServer}/ReportServer"); serverReport.ReportPath = $@"{reportPath}{reportName}"; // report input var parameters = new List<ReportParameter>(); parameters.Add(new ReportParameter("User_uid", "1")); serverReport.SetParameters(parameters); // run report serverReport.Refresh(); } } }

  7. Ver informe : en este punto, debería poder ver su informe por sí mismo seleccionando Ver en el navegador o Ctrl + Mayús + W

Problema 2 - Mezcla de WebForms y MVC

Primero, analicemos rápidamente las diferencias de enrutamiento entre cómo se cargan estos controles y luego se actualizan

  • Las rutas de MVC se parecerán a este {controller}/{action}/{id} donde el motor de enrutamiento encontrará automáticamente un Controller y Action con el nombre especificado y las solicitudes entrantes serán manejadas por ese método. En cualquier solicitud de página, ya sea desde carga de página, envío de formulario, clics de botón, navegación de anclaje o llamadas ajax, el método exacto que se ejecuta siempre se especifica en url {action} .

  • WebForms enruta el código buscando la dirección física de la página .aspx y luego usa ViewState y PostData para conectar y activar eventos en esa página / control.

    Aquí hay una ilustración de diferentes formatos de enrutamiento en WebForms . Y aquí hay un simple evento de clic de botón que enviará una publicación a la página principal y levantará los eventos apropiados dentro de la página según los datos del evento enviados:

Esta es una restricción bastante grande en nuestras soluciones disponibles. Nada es especial sobre el control ReportViewer . Es solo un conjunto sofisticado de clases UserControl que responde al clic y a otros eventos de entrada publicando la dirección actual junto con el ViewState y la información del evento. Por lo tanto, cualquiera que sea la suposición incluida en el enrutamiento y la navegación del ReportViewer deberá persistir en nuestro contenedor MVC.

  1. Opción 1 - Agregar ruta para la página .aspx

    A partir de MVC 4.0+, puede usar weblogs.asp.net/scottgu/archive/2009/10/13/… . Esto se combina bien con MVC agregando una MapPageRoute (observe la parte de página ) para asignar una ruta a un archivo físico. Añada lo siguiente a su RouteConfig.cs :

    routes.MapPageRoute( routeName: "ReportViewer", routeUrl: "ReportViewer/{reportName}", physicalFile: "~/ReportViewerPage.aspx" );

    El informe se ejecutará cuando navegue a la dirección ~/Reports/reportName . Probablemente se invocará desde dentro de una acción del controlador, quizás con algunos parámetros ingresados ​​por el usuario o cadenas de conexión web.config. Hay muchas formas de administrar el estado en ASP.NET y Pasar valores a páginas de formularios web ASP.NET . Una opción sería esconder la información en la sesión y redirigir de esta manera en su controlador:

    HttpContext.Session[reportSetup.ReportName] = new ReportSetup() {ReportName = "ClientReport"}; //reportSetup;} return RedirectToRoute("ReportViewer", new { reportName = reportSetup.ReportName});

    Luego, dentro de la página .aspx, y puede obtener el reportName de los valores de RouteData y los parámetros de configuración de la sesión:

    // 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];

    Pros :

    • La mayoría del enrutamiento parece funcionar por defecto, y los controles AJAX funcionan bien, por lo que puede establecer AyncRendering=True

    Contras :

    • Es difícil utilizar un formulario web ASP con un diseño Razor MVC, por lo que el renderizado sacará a los usuarios del flujo del resto de la aplicación.
    • Además, los valores del informe deben exponerse como parte de la URL o pasarse indirectamente a través de la sesión (en lugar de hidratarse directamente sobre el objeto).
  2. Opción 2: Nest .ascx dentro de PartialView en tu página

    Adaptado de ¿Cómo puedo usar un control ReportViewer con Razor? , puede consumir controles .ascx en PartialViews siempre que hereden de System.Web.Mvc.ViewUserControl .

    Cree un nuevo control de usuario de formularios web llamado ReportViewerControl.ascx que se ve así:

    <%@ 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>

    Nota : debe establecer AsyncRendering="False" y EnablePartialRendering="false"

    En el código subyacente, deberá reemplazar el tipo de herencia de System.Web.UI.UserControl a System.Web.Mvc.ViewUserControl .

    Y en Page_Init , tendrá que configurar Context.Handler a la Page para que los eventos se registren correctamente.

    Entonces, ReportViewerControl.ascx.cs debería verse así:

    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(); } } }

    Para presentar el informe, agregue lo siguiente a su vista de controlador:

    @Html.Partial("ReportViewerControl", Model)

    Y luego en el evento ReportViewerControl.ascx.cs Page_Load, puede recuperar el modelo pasado en la propiedad ViewUserControl.Model esta manera:

    ReportSetup setup = (ReportSetup)Model;

    Pros :

    • Se puede construir en master _layout.cshtml y consumir en vistas regulares
    • Puede pasar el modelo directamente

    Contras :

    • AsyncRendering debe establecerse en falso, por lo que las interacciones como la paginación y la clasificación causan actualizaciones completas de la página y, a veces, son poco claras. Brian Hartman''s tiene un blog solo para ReportViewer y habla sobre AsyncRendering y todo el equipaje que viene con él .

Lectura adicional :

  • ¿Cómo puedo usar un control reportviewer en una vista de navaja ASP.NET MVC 3?
  • ¿Cómo presento una página aspx de ReportViewer remota en MVC 4?
  • MVC 5 y SSRS ReportViewer - ¿Cómo implementar?

No, el control ReportViewer no funcionará si lo coloca en una vista MVC, ya que requiere ViewState. Deberá crear un formulario web antiguo y colocar el ReportViewer en su lugar.

Una solución que utilicé en un proyecto en el que trabajé fue crear un controlador de ruta personalizado, por lo que todavía podía hacer uso del enrutamiento de URL. El manejador de ruta tomaría parámetros como el nombre del informe de la colección RouteData, crearía una instancia de mi formulario web y le pasaría los parámetros a través de propiedades públicas. El formulario web los leería en Page_Load y configuraría el control 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; } }

Este código es solo un punto de partida si decides usar este enfoque, por supuesto. El que creé también realizó una autenticación de usuario y validación de parámetros antes de volver.

Actualización : parece que si está utilizando ASP.NET 4.0, ¡la weblogs.asp.net/scottgu/archive/2009/10/13/… !


No, no en una vista de MVC. Pero puede tener páginas de formularios web que tengan controles de servidor mezclados con su sitio MVC.

Hmm, simplemente busqué en Google "mix asp.net mvc y formularios web" para encontrar algunos ejemplos, y google me preguntó si soy humano o no :)

De todos modos, aquí hay un enlace - http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc - hay algunos por ahí. También hice esto en un sitio de MVC por el mismo motivo: el control de informes.


Una solución simple es agregar un marco flotante a su vista de MVC que abre el informe que desea del servicio web de servicios de informes. El iframe estará en pleno funcionamiento con los componentes de los servicios de informes. Los parámetros utilizados para la url en el iframe también se pueden controlar dinámicamente (por ejemplo, con ajax) si desea mover los componentes a su vista MVC.

Aunque esto funciona, igual tendrá que iniciar sesión en el servicio de informes web (el iframe abrirá un diálogo de inicio de sesión). Para IE, esto se hace "automágicamente" usando sus credenciales de inicio de sesión de Windows.