OutOfMemoryException con RDLC, LocalReport, Microsoft.Reporting.WebForms

2,452 views
Skip to first unread message

Kiquenet

unread,
Oct 26, 2015, 6:30:08 AM10/26/15
to AltNet-Hispano
Hola a todos,

tengo una aplicación ASP.NET que utiliza informes locales RDLC con ReportViewer ( ).

En Preproducción no he conseguido reproducir el error, y va funcionando bien. En Producción aparecen errores de OutOfMemory justo en la llamada:

byte[] renderedBytes = localReport.Render(reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings);


Dicha llamada está en un método estático.  Igual es mejor hacer una clase IDisposable

Alguna sugerencia para evitar el error ?

En la MSDN comentaban una sobrecarga del método Render, con un CreateStream callback, más no vi ejemplo al respecto


Muchas gracias de antemano.

Código aquí

protected void BtnExcel_Click(object sender, EventArgs e)

{

            var lstClient = GetDatosInfome();

Session["lstClient"] = lstClient;

if (lstClient.Count <= 0) return;

var localReport = new LocalReport

{

ReportPath = HttpContext.Current.Server.MapPath("~/Informes/Clientes/ListadoClientes.rdlc")

};

 

var reporteDataSourceClientes = new ReportDataSource("ClientesInforme", lstClient);

localReport.DataSources.Add(reporteDataSourceClientes);

Informe.GeneraInforme(TipoSalida.Excel, localReport, "Listado Clientes");

}


protected void BtnPdf_Click(object sender, EventArgs e)

{

            var lstClient = GetDatosInfome();

            Session["lstClient"] = lstClient;

            if (lstClient.Count <= 0) return;

            var localReport = new LocalReport { ReportPath = HttpContext.Current.Server.MapPath("~/Informes/Clientes/ListadoClientes.rdlc") };

            var reporteDataSourceClientes = new ReportDataSource("ClientesInforme", lstClient);

            localReport.DataSources.Add(reporteDataSourceClientes);

            Informe.GeneraInforme(TipoSalida.Pdf, localReport, "Listado Clientes");

}




public static void GeneraInforme(TipoSalida tipoSalida, LocalReport localReport, string tituloInforme)




{



try




{



string reportType = tipoSalida.ToString();


string mimeType;


string encoding;


string fileNameExtension;


Warning[] warnings;


string[] streams;


string deviceInfo = "<DeviceInfo><SimplePageHeaders>False</SimplePageHeaders></DeviceInfo>";


// TODO: Buscar Solución OutOfMemoryException


// Problemas de OutOfMemory


byte[] renderedBytes = localReport.Render(reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings);

TransmitReport(tipoSalida, tituloInforme, fileNameExtension, renderedBytes);


}



catch (LocalProcessingException ex)




{



throw ex;




}



catch (Exception ex)




{



throw ex;




}


}



private static void TransmitReport(TipoSalida tipoSalida, string tituloInforme, string fileNameExtension, byte[] renderedBytes)

{



HttpContext.Current.Response.Clear();


switch (tipoSalida)

{


case TipoSalida.Pdf:HttpContext.Current.Response.ContentType = "application/pdf";


break;


case TipoSalida.Excel:HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";


break;

}



HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + tituloInforme + "." + fileNameExtension);


HttpContext.Current.Response.BinaryWrite(renderedBytes);


HttpContext.Current.Response.End();


//HttpContext.Current.Response.Flush();


//HttpContext.Current.Response.Close();




}

Diego Jancic

unread,
Oct 26, 2015, 11:11:40 AM10/26/15
to AltNet-Hispano
Hola Kiquenet,

Nosotros estamos teniendo un problema similar usando el ReportServer, es decir que los reportes se ejecutan en en SSRS y se genera un PDF.  Con el ReportViewer creo que el proceso es similar aunque hace años que no lo utilizo.

En nuestro caso no sucede siempre si no que a veces "se cuelga" y empieza a tirar OutOfMemory a todos los reportes.

De cualquier forma, luego de investigar bastante la solucion que todos recomiendan es "agrega memoria". 

Si queres podes ejecutar:
Use ReportServer
select * from ExecutionLog3 order by TimeStart DESC

Para poder ver cuanto tiempo estan tardando los reportes y cuanta memoria esta consumiendo:

La informacion sobre la memoria esta en la columna AdditionalInfo y solo se incluye si es significativa (mas de un par de Mb).  

- Si ves que realmente consumen mucha memoria quizas deberias reveer los reportes y los queries.
- Si el server es muy chico, entonces deberias cambiarte de server.
- Si el server es relativamente potente como el nuestro, entonces la unica solucion que nosotros encontramos es capturar ese error y reiniciar el proceso del SSRS cuando sucede.

Espero que te sirva.

Un abrazo!
Diego


--
Has recibido este mensaje porque estás suscrito al grupo "AltNet-Hispano" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a altnet-hispan...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a altnet-...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/altnet-hispano.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

Kiquenet

unread,
Oct 27, 2015, 3:14:09 PM10/27/15
to AltNet-Hispano
Muchas gracias Diego.

Nos estamos planteando también migrar de RDLC (Local REport) a RDL (Remote Reports en servidor SSRS). Tendremos en cuenta también esos temas de rendimiento que comentas y OutOfMemory.

De RDL no había visto nada hasta ahora, no sé si será fácil la migración de RDLC a RDL.


En RDL creo que se manejan DataSources, en cambio para RDLC tenemos una lista de entidades, que se asigna a la lista de  localReport.DataSources

           var reporteDataSourceClientes = new ReportDataSource("ClientesInforme", lstClient);

           localReport.DataSources.Add(reporteDataSourceClientes);


además, me interesaría saber cuál es la mejor manera de renderizar en u na página aspx el resultado de una llamada a un RDL.

Con un RDLC, con el método Render obtenemos un array de bytes para enviar al cliente  vía HttpContext.Current.Response.BinaryWrite(renderedBytes);
byte[] renderedBytes = localReport.Render

Agradecería mucho si podéis comentar vuestras experiencias con informes RDL ( servidor SSRS) y ASP.NET en ese sentido.

Muchas gracias
...

Diego Jancic

unread,
Oct 27, 2015, 3:25:44 PM10/27/15
to AltNet-Hispano
Segun recuerdo, no hay mucha diferencia entre RDLC y RDL, aunque hace mucho que no veo RDLC.  Si usas SSRS, los reportes se ejecutan en el servidor y vos le decis en que formato queres el resultado.  La mejor salida la tenes con PDF, pero tambien soporta Excel, HTML, Word, XML.  Si queres podes probar con HTML y quizas lo puedas renderizar bien el browser.

De cualquier forma, si son muy exquisitos con el diseño no es bueno.

En los nuevos proyectos yo decidi no usar mas Reporting Services.  Si estan recien empezando podrian buscar otra solucion. Dependiendo de que tipos de reportes esten haciendo, hacer el query en SQL y con eso generar un HTML (o PDF o Excel) programaticamente es bastante sencillo.

Por ejemplo aca tenes el mismo reporte, hecho a mano y "renderizado" a HTML y a PDF:





Tambien agregamos CSV y Excel bastante facil.  Otros reportes incluso tienen graficos.  Pero bueno, depende de lo que necesites y el tiempo que tengas :)


Carlos Admirador

unread,
Oct 27, 2015, 5:46:05 PM10/27/15
to AltNet-Hispano

A nivel de código se puede utilziar un ReportExecution.ReportExecutionService

Las diferencias con con elemento Query, y DataSet y Data Source utilizandos en RDLC y RDL respectivamente.

Desconozco si a nivel programático es posible establecer Data Sources - fuentes de datos- al RDL, o debe hacerse exclusivamente en el report designer del RDL.

[Converting RDL and RDLC Files][1] 

  [1]: http://msdn.microsoft.com/en-us/library/ms252109%28v=vs.80%29.aspx "Converting RDL and RDLC Files"

http://www.gotreportviewer.com/

http://stackoverflow.com/questions/14479144/programmatically-export-ssrs-report-from-sharepoint-using-reportservice2010-asmx/14492191#14492191


https://hajloo.wordpress.com/2010/05/06/how-to-convert-rdl-files-to-rdlc-files/

2 – “The ReportViewer control, which processes .rdlc files, ignores the <Query> element of RDL. If a report definition contains a query, the control will not process it. So A client report definition (.rdlc) file will only contain a query if it originated as a .rdl file.” MSDN said.

3 – DataSet and Data Source which used in RDLC and RDL files are totally different. RDLC (Client reports) use DataSet which actually is a DataTable and RDL (SQL Server Report) use DataSource which consist of a Data Source (actually connection String). Some Credential Information which used to access Database mentioned in Data Source and finally a SQL Command (StoreProcedure – Function …) or a Query which retrieve data from Database.




var rs = new ReportExecution.ReportExecutionService();
 
            rs.Credentials = new System.Net.NetworkCredential(System.Configuration.ConfigurationManager.AppSettings.Get("ReportBrowserUser"),
                                                               System.Configuration.ConfigurationManager.AppSettings.Get("ReportBrowserPass"),
                                                                System.Configuration.ConfigurationManager.AppSettings.Get("ReportBrowserDomain"));

            rs.Url = System.Configuration.ConfigurationManager.AppSettings.Get(
"ReportExecutionService");          
 
            byte[] result = null;
            string reportPath = rutaReport;
            string format = (formato == "I" ? "PDF" : (formato == "E" ? "EXCEL" : (formato == "F" ? "CSV" : "")));
            string historyID = null;
            string devInfo = @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>";
            // Prepare report parameter.
            ReportExecution.ParameterValue[] parameters = new ReportExecution.ParameterValue[valores.Count()];
 
            for (int i = 0; i < valores.Count(); i++)
            {
                string[] separacion = valores[i].Split('=');
 
                parameters[i] = new ReportExecution.ParameterValue();
                parameters[i].Name = separacion[0];
                parameters[i].Value = (separacion[1] == "null" ? null : separacion[1]);
            }
 
            //ReportExecution.DataSourceCredentials[] credentials = null;
            string encoding = string.Empty;
            string mimeType;
            string extension;
            ReportExecution.Warning[] warnings = null;
            string[] streamIDs = null;
 
            ReportExecution.ExecutionInfo execInfo = new ReportExecution.ExecutionInfo();
            ReportExecution.ExecutionHeader execHeader = new ReportExecution.ExecutionHeader();
 
            try
            {
                rs.ExecutionHeaderValue = execHeader;
                execInfo = rs.LoadReport(reportPath, historyID);
 
                result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
                Monitor.FechaFin = DateTime.Now;
            }
            catch (Exception e)
            {
                LanzaError(e.Message, true);
                return;
            }
 

Kiquenet

unread,
Oct 30, 2015, 8:42:24 AM10/30/15
to AltNet-Hispano

En PRO, en el mismo servidor

en versión v2 de la aplicación (https://server/v2/Ventas.aspx da error OutOfMemoryException

 

en versión v1, vS 2008 , .NET 3.5, https://server/v1/Ventas.aspx  Genera bien informe en PRO

 


No sé dónde estará el problema:  Configuración del IIS , del pool, del site,  web.config, HttpContext.Current.Response.BinaryWrite(renderedBytes);??

Pool así: 

v1 >-  APPPOOL "xxx2001Pool" (MgdVersion:v2.0,MgdMode:Classic,state:Started) Cuenta: domain\MyAppPool

 

v2- >APPPOOL "xxx2015Pool" (MgdVersion:v4.0,MgdMode: Classic,state:Started). Cuenta: ApplicationPoolIdentity.



 

Mismo código en ambos…

 

public class InformeVentas : IHttpHandler

    {

 

        public void ProcessRequest(HttpContext context)

        {

            LocalReport localReport = new LocalReport

            {

                ReportPath = HttpContext.Current.Server.MapPath("~/Informes/InformeVentas.rdlc")

            };

 

            List<TablaEvolucionValorAnterior> listaPolizas = DatosGrafica.GetTablaEvolucionPolizasVentas(Convert.ToInt32(context.Request["empresa"]), Convert.ToInt32(context.Request["mediador"]));

            ReportDataSource reportDataSourcePolizas = new ReportDataSource("TablaEvolucionVentasPolizas", listaPolizas);

            localReport.DataSources.Add(reportDataSourcePolizas);

 

            List<TablaEvolucionValorAnterior> listaPrimas = DatosGrafica.GetTablaEvolucionPrimasVentas(Convert.ToInt32(context.Request["empresa"]), Convert.ToInt32(context.Request["mediador"]));

            ReportDataSource reportDataSourcePrimas = new ReportDataSource("TablaEvolucionVentasPrimas", listaPrimas);

            localReport.DataSources.Add(reportDataSourcePrimas);

 

            List<TablaRamosVentas> listaRamos = DatosGrafica.GetTablaRamosVentas(Convert.ToInt32(context.Request["empresa"]), Convert.ToInt32(context.Request["mediador"]));

            ReportDataSource reportDataSourceRamos = new ReportDataSource("TablaRamosVentas", listaRamos);

            localReport.DataSources.Add(reportDataSourceRamos);

 

            List<ReportParameter> parameters = new List<ReportParameter>

            {

                new ReportParameter("FechaDatos", DatosGrafica.GetFechaActualizacionDatos().ToShortDateString())

            };

            localReport.SetParameters(parameters);

 

            Informe.GeneraInforme((TipoSalida)Convert.ToInt32(context.Request["tipoSalida"]), localReport, "InformeVentas");

        }



public static void GeneraInforme(TipoSalida tipoSalida, LocalReport localReport, string tituloInforme)

{

string reportType = tipoSalida.ToString();

string mimeType;

string encoding;

string fileNameExtension;

Warning[] warnings;

string[] streams;

string deviceInfo = "<DeviceInfo><SimplePageHeaders>False</SimplePageHeaders></DeviceInfo>";

byte[] renderedBytes = localReport.Render(reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings);

HttpContext.Current.Response.Clear();

switch (tipoSalida)

{

case TipoSalida.Pdf:

HttpContext.Current.Response.ContentType = "application/pdf";

break;

case TipoSalida.Excel:

HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";

break;

}

HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + tituloInforme + "." + fileNameExtension);

HttpContext.Current.Response.BinaryWrite(renderedBytes);

HttpContext.Current.Response.End();

}

 

Qué troubleshooting podría hacer para tener más datos y qué poder  hacer?

Muchas gracias de antemano.

Kiquenet

unread,
Nov 3, 2015, 4:53:00 PM11/3/15
to AltNet-Hispano
En una prueba rápida en el entorno de Producción , utilizando GC.Collect() se ha conseguido generar el Report.
try
{
    CallToRenderReport(....);
}
catch (OutOfMemoryException)
{
    GC.Collect(),
    CallToRenderReport(....);
}


Una llamada a GC.Collect() me ha funcionado como workaround, pero es una buena práctica?

http://stackoverflow.com/questions/6053036/diagnosing-net-outofmemoryexception-when-generating-reports 

En algún caso, comentan que hay que realizar la llamada a GC.Collect() dos veces:
http://stackoverflow.com/questions/3829928/under-what-circumstances-we-need-to-call-gc-collect-twice



En foros y MSDN hablan de ciertos cambios en .NET 4.5 en relación al Garbage Collector:


More common reason to get  System.OutOfMemoryException is due to memory fragmentation - there is no large enough continuous space in memory. You should install a memory profiler to verify that - then you can also try to find out which objects take up the memory.

If possible, you might want to test .NET 4.5 - Microsoft has made changes to the Garbage Collector so that LOH is automatically defragmented for server applications (such as IIS): http://blogs.msdn.com/b/dotnet/archive/2011/10/04/large-object-heap-improvements-in-net-4-5.aspx


performanceScenario ?

http://www.asp.net/aspnet/overview/aspnet-and-visual-studio-2012/whats-new#_Toc_perf

http://docs.sitefinity.com/recommended-environment-settings


Aún tengo cierta confusión al respecto.

Carlos Peix

unread,
Nov 4, 2015, 5:15:47 AM11/4/15
to altnet-hispano
En general es riesgoso llamar a GC.Collect(), más aún llamarlo dos veces seguidas (acelera la obsolescencia de dos generaciones de referencias, siempre y cuando siga funcionando de esa manera).

----------------------------------
Carlos Peix

--

Kiquenet

unread,
Nov 4, 2015, 10:40:58 AM11/4/15
to AltNet-Hispano
Gracias Carlos.

Qué riesgos puede ocasionar utilizar GC.Collect en los try-catch ?

Es un sitio con 3 nodos (servidores IIS) y creo que aproximadamente 100 sesiones concurrentes puede haber en el entorno de Producción.

No he podido encontrar otro "workaround" al respecto de los Reports RDLC y ASP.NET 4.5.



renderer.Generate(format, title);

                   



}

}

catch (Exception ex)

{

   OutOfMemoryHandling(ex, (title + " - " + reportPath), outOfMemoryHandling, () =>

   {

       DoGenerateRDLC(reportPath, title, format, parametros, false);

   });

}



internal static void OutOfMemoryHandling(Exception ex, string tituloInforme, bool outOfMemoryHandling, Action actionRetryIfExceptionIsOutOfMemory)

{

     var msg = "Error " + ex.Message + " para Informe " + tituloInforme;

     msg += ". Retry Handling OutOfMemory " + outOfMemoryHandling;

     LoggerReporting.Trace(msg);

     if (!outOfMemoryHandling) throw ex;

     var okOutOfMemory = DoOutOfMemoryHandling(ex);

     if (okOutOfMemory)

     {

       actionRetryIfExceptionIsOutOfMemory();

       return;

     }

     throw ex;

}

private static bool DoOutOfMemoryHandling(Exception ex)

{

var exceptionCurrent = ex;

if (exceptionCurrent is LocalProcessingException)

{

exceptionCurrent = ex.InnerException;

while (exceptionCurrent.InnerException != null)

exceptionCurrent = exceptionCurrent.InnerException;

}

if (exceptionCurrent is OutOfMemoryException)

{

GC.Collect();

//GcHelper.AggressivelyCollect();

return true;

}

return false;


Ale Miralles

unread,
Nov 4, 2015, 11:22:27 AM11/4/15
to altnet-...@googlegroups.com
Creo que lo menciona en uno de los enlaces que copiaste. Pero basicamente:
1. 64 bits (mas address space, menos chances de que la fragmentacion del heap te pegue de forma directa).
2. Server Side GC.
Si ninguna de las dos hace el truco, me parece que no te va a quedar otra que recurrir a un profiler y tratar de detectar algun patron de alocacion. La macana es 

Ale Miralles

unread,
Nov 4, 2015, 11:22:59 AM11/4/15
to altnet-...@googlegroups.com
que si esto pasa en prod. probablemente no puedas correr un profiler.

Alejandro Nelis

unread,
Nov 4, 2015, 9:17:58 PM11/4/15
to altnet-...@googlegroups.com
Diego, me interesa este camino, que es lo que me recomendarías para ir hacia ese camino.
Desde ya muchas gracias.

Saludos
Alejandro Nelis 
Antes de imprimir este mail piense en su compromiso con el medio ambiente.

Diego Jancic

unread,
Nov 4, 2015, 9:53:36 PM11/4/15
to AltNet-Hispano
Hola Ale,

La verdad que no hay mucha recomendacion que te pueda hacer.  Hice todo a manopla y quedo mucho mejor que cualquier otra cosa que haya probado. Algunos detalles:

- Fuente de datos: Puede ser lo que quieras, un SQL Server, un cubo, MongoDB, etc. Incluso los podes mezclar. En general yo devuelvo 1 tabla como minimo para hacer el listado. A veces mas de una si el reporte tiene por ejemplo un encabezado de resumen, o graficos.

- Renderer: Lo que hice fue definir varios "Renderers". El primero es el mas dificil, el resto son triviales. Podes hacer JSON, HTML, XLSX, PDF y CSV, por ejemplo.  Para PDF use PdfSharp/MigraDoc y para XLSX EPPlus, para JSON Newtonsoft JSON.
** En todos los renderers, lo que hice fue pasarle algunos parametros, por ejemplo porque columnas agrupar y que columnas incluir.  Entonces por ejemplo si el query retorna las columnas Name, Email, Time In, yo puedo poner agrupar por Name e incluir Email en el encabezado.  De esa forma me mostrara "Alejandro (a...@gmail.com)" en el encabezado y despues todas las filas hasta que el Name cambie.  Como esto se hace en un stream es bastante rapido y no consume nada de memoria.  De hecho, hice otra libreria para calcular estadisticas con ese stream de datos, pero esa es otra historia.
** Tambien lo que hice para el JSON, es paginarlo, porque a veces los reportes eran muy grandes (lamentablemente es un requerimiento que por mas que sean 1000 paginas tiene que funcionar). Entonces podes ir cortando el JSON en archivos de N cantidad de filas y lo bajas en partes. El problema en si no fue la transferencia de datos sino el tiempo de renderizado en el cliente, porque no se baja el HTML sino el JSON:  si lo tuviese que hacer de nuevo mandaria el HTML directamente supongo.

Y listo, eso es basicamente todo. Despues lo vas ajutando a tus necesidades. En mi caso todos los reportes son similares, pero claro que se podrian manejar casos especiales por cada caso.  

Abrazo



Kiquenet

unread,
Nov 5, 2015, 10:46:31 AM11/5/15
to AltNet-Hispano
Muchas gracias Ale.

Me viene algo grande, lo investigaré en detalle.

De Server Side GC vi en algún foro, que añadían esta configuración

<´runtime >
    < gcAllowVeryLargeObjects enabled="true" / >   
< / runtime >

No sé las implicaciones que tendrá.

Saludos.

Ale Miralles

unread,
Nov 5, 2015, 1:09:48 PM11/5/15
to altnet-...@googlegroups.com
Aca hay una explicacion (extensa) sobre los distintos modos que soporta .NET 4.5

De todas formas, si queres hacer una prueba rapida...
<gcServer enabled="true"/>
Puede ser que modificando el modo de garbage collection el sitio salga andando y el tema profiler quede como tarea para el hogar ;)

Saludos, Ale Miralles

--

Kiquenet

unread,
Nov 5, 2015, 2:19:51 PM11/5/15
to AltNet-Hispano
Muchas gracias Ale! Ya me va quedando algo más claro estos nuevos cambios del .NET 4.5 y el Server GC. Le echaré un vistazo en detalle.
Lo del profiler lo desconozco totalmente, me queda muy a bajo nivel; ¿son como herramientas tipo WinDbg ?

Saludos y muchas gracias!

Carlos Peix

unread,
Nov 5, 2015, 2:52:10 PM11/5/15
to altnet-hispano
Quizás esto te aclare algo...


----------------------------------
Carlos Peix

2015-11-04 12:40 GMT-03:00 Kiquenet <kiqu...@gmail.com>:

Ale Miralles

unread,
Nov 5, 2015, 3:20:56 PM11/5/15
to altnet-...@googlegroups.com
Yo probaria con http://memprofiler.com
Hasta ahora, nunca me ha dejado a pie.
Alguna que otra vez utilice WinDbg, pero es super duro comparado a .NET Memprofiler. Tambien hay un profiler de Jetbrains (son los que hacen R#) pero no te lo recomiendo para nada. Las pocas veces que lo utilice "crasheaba" por todos lados, un desastre. Cuando ves sus profilers te das cuenta que son buenos escribiendo analizadores sintacticos ;)

Saludos, Ale Miralles.



--

Kiquenet

unread,
Nov 12, 2015, 7:15:32 AM11/12/15
to AltNet-Hispano
Muchas gracias. Nunca utilice profilers del estilo que comentas http://memprofiler.com ni mucho menos WinDbg, me parece duro, desde mi desconocimiento.  Yo me quedé en alguna charla de Pablo Doval, que me vienen muy grandes http://www.slideshare.net/padoval/depuracin-avanzada-con-windbg-y-vs-2010-bsica y http://docslide.us/documents/depuracion-avanzada-con-win-dbg-y-vs-2010-extendida.html

Y en ese caso, me impondría utilizarlos en producción. Aquí lo comentan para Cpu Profilers (http://mvolo.com/when-cpu-profiling-goes-bad-in-production/ , https://www.leansentry.com/HowTo/Recover-Hung-Process-Cpu-Profiler-Attach)

En todo caso, profundizando en el problema de RDLC y OutOfMemory, viendo foros, aún estoy intentando procesar todo esto, y ver si tiene sentido.

Primero, miré que podía ser configuración Server GC, y que puede permitir optimizar sitios web con CLR 4.0 - ASP.NET 4.5
Por lo que vi, hay dos modos GC: workstation and server. Server si tiene varios procesadores interesa activar gcServer enabled="true" (GCSettings.IsServerGC property to determine if server garbage collection is enabled.) y otras opciones como gcConcurrent enabled="true|false" y otras como gcTrimCommitOnLowMemory


If you are the administrator for a server that is shared by hosting several small Web sites, you can optimize performance and increase site capacity by adding the following gcTrimCommitOnLowMemory setting to the runtime node in the Aspnet.config file in the .NET Framework directory:

<gcTrimCommitOnLowMemory enabled="true|false"/>



Hoy he descubierto que también puede influir los cambios de CAS en CLR 4.0 (aún estoy procesándolo).

can custom CAS security settings in separated AppDomain directly in original  application, and implement a very simple AppDomain recycle policy just to contain memory leaks.



For a WinForms application you can use <NetFx40_LegacySecurityPolicy enabled="true" /> in the configuration -> runtime section of the app.config file which forces the usage of the current AppDomain. Although the MS documentation for this property does not indicate it, this tag only has an effect in WinForms applications.
  • In an ASP Net application you can use <trust legacyCasModel="true" level="Full"/>  in the system.web section of the web.config file to achieve the same result. 

Workarounds:

You can compile your application in Net 3.5 and avoid all performance problems with the Report Viewer (which is multi- targeted for 3.5 and 4.0). If you do so, DO NOT use the viewer option "ExecuteReportInSandboxDomain" since that will bring back the problem (duh). You are then running in the current AppDomain, could have memory leak problems with an ASPNET application, and of course abandon any use of other Net 4.0 features.  Loading the old viewer (can be done) does allow the use of the sandbox domain but would possibly bring back the problem of the sandbox domain not unloading properly. It's a no win situation I think.

Alternatively you can stay with Net 4.0 but force the use of´ legacy CAS security.



I experienced the same problem in .NET 4.5 in ASP.NET based application with heavy use of dynamic types for serialization and deserialization.  So I could not use < trust legacyCasModel="true" level="Full"/>, 

I managed to create another workaround based on custom CAS security settings in separated AppDomain directly in original application without the need to deploy reports to RS, or to create some stand alone application/web service based on .NET3.5 or settings mentioned in previous replies.

My reports went down from 18s to 2s


Local report processing requires full trust for an ASP.Net 4 site, at least if there are any expressions or parameters. Remote report processing (with the reports hosted on a SQL Server Report Services server) works in medium trust even for reports with expressions and parameters.




http://blogs.msdn.com/b/brianhartman/archive/2010/02/18/expression-evaluation-in-local-mode.aspx


The ReportViewer in VS 2010 is a multi-targeted assembly.  That means that is can be loaded into a .Net 3.5 or a .Net 4.0 application.  When running under .Net 3.5, all of the same rules and methods noted above are applicable.  However, the CLR security team made changes to code access security in .Net 4.0, so there are corresponding changes in the ReportViewer as well:

  • Executing in the current AppDomain is no longer supported, so using a sandbox is the default mode when running in .Net 4.0.  Two new methods have been added to better control the permissions of the sandbox AppDomain so that you don’t see any loss of functionality:  AddFullTrustModuleInSandboxAppDomain and SetBasePermissionsForSandboxAppdomain.
  • ExecuteReportInCurrentAppDomain, AddTrustedCodeModuleInCurrentAppDomain, and ExecuteReportInSandboxAppDomain have been marked as obsolete.  While it is perfectly acceptable to use them in a .Net 3.5 application, they won’t have any effect when you compile for .Net 4.0.  Going forward, we recommend using the sandbox AppDomain even under .Net 3.5 because setting the correct security policy on the current AppDomain is an error prone task.  The new methods will work under both frameworks and is the best approach if you want to write in a framework agnostic way.
As part of the security changes to the CLR in .Net 4.0, an application configuration flag, NetFx40_LegacySecurityPolicy, can be specified to use the .Net 3.5 security model in .Net 4.0.  If this flag is specified, the report viewer will behave just as it would under .Net 3.5, meaning that the obsolete methods will function correctly.


¿Pueden compartir sus experiencias con CAS en .NET 4.0 ?

  •  Muchas gracias por sus comentarios.
Reply all
Reply to author
Forward
0 new messages