Category Archives: 4294

Recursos destacados en MSDN ASP.NET Home

Me ha tocado la grata tarea de seleccionar y promover los links que se listan en la sección de Recursos Destacados de MSDN ASP.NET Home.

La idea es promover artículos originales de autores de la comunidad de habla hispana, sobre temas de desarrollo Web. Estaré seleccionando unos 10 artículos al mes.

Algunos temas de ejemplo: ASP.NET, Silverlight, IIS, Seguridad, AJAX, IE, ASP.NET MVC, ASP.NET 4.0

Si encuentras algún artículo interesante o quieres promover el tuyo, comunícate conmigo vía http://twitter.com/cwalzer.

Saludos

Conferencia: IIS 7 para Desarrolladores

En esta presentación online de MSDN (20/mayo/08) que realizamos con José Marcenaro, destacamos algunos de los aspectos de la nueva plataforma de hosting en Windows Server 2008 y Windows Vista, enfocados desde la óptica de los desarrolladores.

Puede descargar aquí la presentación (.PPTX) y el ejemplo de código WAS (Windows Service Activation Process) que muestran servicio WCF accedido por protolos non-http.

Próximamente podrán ver la presentación por demanda aquí.

Diagnóstico de caída del w3wp.exe con ASP.NET 2.0 y WCF

La información de este post está basada en el uso empírico del siguiente artículo “Las excepciones no controladas hacen aplicaciones que se las cierran inesperadamente en el .NET Framework, 2,0, basadas en ASP.NET”.

Cuando nos enfrentamos a caídas del worker process en Internet Information Server, la información que encontramos en el Event Log es una de las puntas para empezar la investigación.Ante una caída (crash) del proceso w3wp.exe  (worker process) el sistema operativo informa el hecho en el Event Viewer con 3 entradas.
A continuación un ejemplo muestra los eventos sucedidos en forma cronológica:

Sección Application
Event Type:        Error
Event Source:        .NET Runtime 2.0 Error Reporting
Event Category:        None
Event ID:        5000
Date:                1/8/2008
Time:                7:23:11 AM
User:                N/A
Computer:        PC
Description:
EventType clr20r3, P1 w3wp.exe, P2 6.0.3790.3959, P3 45d6968e, P4 mscorlib, P5 2.0.0.0, P6 46b3e871, P7 331e, P8 21c, P9 system.io.ioexception, P10 NIL.

Event Type:        Error
Event Source:        Application Error
Event Category:        (100)
Event ID:        1000
Date:                1/8/2008
Time:                7:23:32 AM
User:                N/A
Computer:        PC
Description:Faulting application w3wp.exe, version 6.0.3790.3959, faulting module kernel32.dll, version 5.2.3790.3959, fault address 0x0000bee7.

Sección System
Event Type:        Warning
Event Source:        W3SVC
Event Category:        None
Event ID:        1011
Date:                1/8/2008
Time:                7:23:35 AM
User:                N/A
Computer:        PC
Description:A process serving application pool ‘MiSistema.AppPool’ suffered a fatal communication error with the World Wide Web Publishing Service. The process id was ‘10232’. The data field contains the error number.

La única punta que tenemos hasta el momento es que el tipo de la Excepción que produjo la caída es System.IO.IOException, pero necesitaríamos el stack trace para poder hacer un diagnóstico.

¿Porque se produce una caída del w3wp.exe?

Conocer porqué se produce una caída del worker process nos dará un indicio por dónde empezar a buscar.Una Excepción no atrapada en nuestro código cuyo código corre en un hilo del thread pool de ASP.NET será atrapada por el mismo ASP.NET, formateada en la típica pantalla naranja y mostrada al usuario. Lo mismo sucede con un servicio WCF que corre en IIS, la Excepción no atrapada será lanzada al invocador o en el mejor de los casos podemos atraparla centralizadamente en un behavior implementado la interfaz System.ServiceModel.Dispatcher.IErrorHandler.

La caída se produce entonces cuando la excepción no es atrapada en un hilo secundario al del thread pool de ASP.NET, o cualquier otro hilo que no corra dentro del pipeline de ASP.NET. Podría ser el caso de una excepción no atrapada en:
·         Finalizer (cuyo código se ejecuta en un hilo del GC)
·         Código ejecutado asinrcónicamente mediante un delegado
·         Algún componente que utilice un thread pool propio.
·         Etc.

En la versión de ASP.NET 2.0 el comportamiento por defecto de que sucede cuando una excepción no es atrapada en un hilo que no pertenece el thread pool es producir la caída del worker process.  Esto no sucedía en versiones anteriores ASP.NET 1.0 y 1.1, donde el comportamiento es el contrario. Este cambio se debe a que una excepción no atrapada no permite la ejecución de código que en situaciones normales hubiese liberado recursos. De esta forma se evita la degradación del equipo o el abandono de locks.

Evitar caída del Worker Process (no recomendable)

En ASP.NET 2.0 es posible controlar este comportamiento modificando la entrada del aspnet.config

<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled=true />
  </runtime>
</configuration>

Demás está decir que esta práctica no es recomendable.

Como información agregada he aquí un extracto del documento CLR Run-Time Breaking Changes

Short Description Unhandled exceptions will always be fatal to a process
Affected APIs N/A Severity Medium Compat Switch Available No

Description Unhandled exceptions will always be fatal to the process. They weren’t necessarily always fatal in V1.0/V1.1.

User Scenario Applications that throw unhandled exceptions on threads other than the main thread (or ones that come into the runtime from the outside) will crash rather than continue running (when they are potentially in an invalid state)

Work Around

Put a catch block at the top of your non-main thread, threadpool workitem, or finalizer. (Or else fix the bug that led to the exception.)

Alternatively, in the section of the application’s config file, add the following:<legacyUnhandledExceptionPolicy enabled="1"/>

Como registrar Excepciones que producen caídas del w3wp.exe

Una forma no tan simple, pero certera de diagnosticar el problema es hacer un dump del proceso con la herramienta debugdiag.exe al momento de la caída. Pero claro no es una tarea sencilla…

Tal como lo indica el artículo, es posible registrar las excepciones que producen la caída del worker process, agregando un HttpModule de ASP.NET.
La primera ventaja que encontramos aquí es que un HttpModule se puede agregar por configuración sin necesidad de recompilar.
La segunda es que este funciona para cualquier código que corra por el pipeline de ASP.NET, ya sea código ASP.NET, un ASMX o un servicio WCF.
La clave de este module es suscribirse al evento AppDomain.CurrentDomain.UnhandledException que será lanzado frente a una First Chance Exception, y el cual no modifica el curso, con lo cual luego se lanzará la Second Chance Exception, que producirá la caída.
Es aquí entonces donde recibimos por parámetro la excepción ocurrida y la registramos en el Event Log por ejemplo.De esta forma podremos obtener información detallada de la excepción, como ser el mensaje y el stack trace.

Nota: El hecho de agregar el HttpModuile, no evita la caída del w3wp.exe.

Como probar este funcionamiento

Basta con lanzar una Exception desde un finalizer para producir la caída del worker process.

Código

El código está disponible en este artículo

Conferencia Online MSDN: Desarrollando aplicaciones bajo la plataforma Internet Information Services 7.0.

Conferencia Online MSDN: Desarrollando aplicaciones bajo la plataforma Internet Information Services 7.0 (nivel 200).

Duración: 45 Minutos
Fecha de Inicio: martes, 26 de febrero de 2008 11:00 a.m. Atlántico Central
Información general del Evento
La última versión de Internet Information Services disponible en Windows Server 2008 incluye grandes cambios con respecto a sus versiones precedentes. En esta sesión exploraremos algunos aspectos técnicos como su nueva arquitectura, el pipeline integrado de ASP.NET, y su nueva consola de administración, pero también conoceremos las forma en que la plataforma puede ser extendida para el soporte de distintas tecnologías.

Oradores: Carlos Walzer – Miguel Angel Saez.

Registración

Scroll completo para la grilla de ASP.NET


Introducción

Realmente el control del servidor DataGrid que provee el Visual Studio para ASP.NET es muy fácil y cómodo de usar.  Con simplemente establecer un par de propiedades podemos generar un tag <table> con todos sus <tr> y sus <td> a partir de una fuente de datos. Recuerden el trabajo que debíamos tomarnos anteriormente, abrir un recordset, recorrerlo en un bucle y ejecutar Response.Write de cada uno de los tags. Ahora con un simple arrastrar y soltar sobre la página aspx tenemos una tabla con la posibilidad de ordenamiento, paginado, filtrado, edición, etc.


Sin embargo, si decidimos no usar la paginación para evitarnos los round-trips, y la cantidad de registros es considerable, haremos que el usuario necesite desplazar la página para ver la totalidad de los registros.  Esto es contraproducente, ya que el usuario pierde la referencia de la cabecera de la tabla, o podría dejar de ver cierta información relevante como ser un menú ubicado al principio de la página.


Lo ideal es poder darle a la grilla las típicas barras de desplazamiento (scroll) que toda grilla de Windows Forms posee.


Veremos paso a paso la evolución que lleva al resultado final.


Solución


Para agregar barras de scroll, debemos encerrar la grilla en un tag <DIV>, especificar el tamaño de la caja y establecer la propiedad Overflow = auto de CSS (hojas de estilo en cascada), la cual añadirá las barras horizontal y/o vertical según sean necesarias.

<div style=”overflow:auto; width:400px; height:201px” >
    <asp:datagrid id=“DataGridFilas” runat=”server” DataSource=”<%# dataSet11 %>“></asp:datagrid>
<
div/>

El resultado obtenido es el siguiente



A simple vista parece que hemos encontrado la solución, pero no…  Si el usuario desplaza la barra vertical, inmediatamente perderá la referencia a la cabecera de la grilla, como muestra la siguiente figura.



Lo que propongo entonces, es separar la cabecera de las filas usando 2 grillas.  La grilla de la cabecera, DataGridCabecera, estará contenida por un <div> del mismo tamaño de la grilla inferior y tendrá ocultas las barras de desplazamiento.  Dejando habilitadas las barras de desplazamiento para la grilla que contiene las filas solamente, DataGridFilas,

<div style=”overflow: hidden; width: 400px”>
   
<asp:datagrid id=“DataGridCabecera” runat=”server” DataSource=”<%# dataSet11 %>“></asp:datagrid>
</
div>
<div style=”overflow: auto; width: 400px; height: 201px” >
   
<asp:datagrid id=“DataGridFilas” runat=”server” DataSource=”<%# dataSet11 %>“></asp:datagrid>
<
div/>

Debemos definir un ancho fijo para las columnas de ambas grillas, ya que generaremos 2 tags <table> distintos.

<div style=”overflow: hidden; width: 400px”>
    <
asp:datagrid id=“DataGridCabecera” runat=”server” DataSource=”<%# dataSet11 %>“>
       
<Columns>
            <
asp:BoundColumn DataField=”ProductID” SortExpression=”ProductID” HeaderText
=”ProductID”>
               
<HeaderStyle Width=”80px”></HeaderStyle
>
           
</asp:BoundColumn
>
           
<asp:BoundColumn DataField=”ProductName” SortExpression=”ProductName” HeaderText
=”ProductName”>
               
<HeaderStyle Width=”250px”></HeaderStyle
>
           
</asp:BoundColumn
>
              
….
        
</Columns
>
    </
asp:datagrid>
</
div>

<div style=”overflow: auto; width: 400px; height: 201px” >
     <
asp:datagrid id=“DataGridFilas” runat=”server” DataSource=”<%# dataSet11 %>“>
         
<Columns>
               <
asp:BoundColumn DataField=”ProductID” SortExpression=”ProductID” HeaderText
=”ProductID”>
                  
<HeaderStyle Width=”80px”></HeaderStyle
>
              
</asp:BoundColumn
>
              
<asp:BoundColumn DataField=”ProductName” SortExpression=”ProductName” HeaderText
=”ProductName”>
                  
<HeaderStyle Width=”250px”></HeaderStyle
>
               
</asp:BoundColumn
>
              
….
         
</Columns
>
    </
asp:datagrid>
<
div/>


La grilla original DataGridFilas, debe ocultar la cabecera para no mostrarse 2 veces; para ello crearemos una clase de CSS llamada Esconder, que reduce el tamaño al 1%.

<STYLE>
   
.Esconder {zoom=1%;}
</STYLE>

Y se la aplicaremos al HeaderStyle de la grilla:

<div style=”overflow: hidden; width: 400px”>
    <
asp:datagrid id=“DataGridCabecera” runat=”server” DataSource=”<%# dataSet11 %>“>
       
<Columns>
            <
asp:BoundColumn DataField=”ProductID” SortExpression=”ProductID” HeaderText=”ProductID”>
               
<HeaderStyle Width=”80px”></HeaderStyle>
           
</asp:BoundColumn>
           
<asp:BoundColumn DataField=”ProductName” SortExpression=”ProductName” HeaderText=”ProductName”>
               
<HeaderStyle Width=”250px”></HeaderStyle>
           
</asp:BoundColumn>
              
….
        
</Columns>
    </
asp:datagrid>
</
div>

<div style=”overflow: auto; width: 400px; height: 201px” >
     <
asp:datagrid id=“DataGridFilas” runat=”server” DataSource=”<%# dataSet11 %>“>
         <HeaderStyle CssClass=”Esconder”></HeaderStyle>
         
<Columns>
               <
asp:BoundColumn DataField=”ProductID” SortExpression=”ProductID” HeaderText=”ProductID”>
                  
<HeaderStyle Width=”80px”></HeaderStyle>
              
</asp:BoundColumn>
              
<asp:BoundColumn DataField=”ProductName” SortExpression=”ProductName” HeaderText=”ProductName”>
                  
<HeaderStyle Width=”250px”></HeaderStyle>
               
</asp:BoundColumn>
              
….
         
</Columns>
    </
asp:datagrid>
<
div/>


La nueva grilla DataGridCabecera que muestra la cabecera no se vinculará a la fuente de datos, de forma tal de no crear las filas que muestran los registros. Este es el código asociado a la carga de la página.  Las 2 grillas están asociadas al dataSet11, sin embargo solo DataGridFilas mostraré las filas ya que el DataSet no esta caragado aún cuando DataGridCabecera.DataBind() es ejecutado.


private void Page_Load(object sender, System.EventArgs e)
{
    DataGridCabecera.DataBind();
    sqlDataAdapter1.Fill(dataSet11);
    DataGridFilas.DataBind();
}


Este es el resultado obtenido:



¿Qué pasa, si el usuario mueve la barra de deslizamiento horizontal?  Se moverán las filas lateralmente y quedará fija la cabecera. ¡Que feo!.



Completemos la solución: lo que necesitamos es poder desplazar la cabecera, DataGridCabecera, tantos píxeles como la barra de desplazamiento que contiene a la grilla DataGridFilas se deslice.


En el evento onscroll del <div> que muestra las barras de desplazamiento, agregaremos código Javascript para sincronizar el movimiento lateral de las filas con la cabecera, de forma tal de mover la cabecera tantos píxeles como lo haga la barra de desplazamiento horizontal. Es necesario entonces que la grilla cabecera DataGridCabecera tenga una posición relativa al <div> que la contiene para poder moverla: style=”position: relative”.


<STYLE>
   
.Esconder {zoom=1%;}
</STYLE>


<script language=”JScript”>
   
function DoScroll()
    {
        document.all(
“DataGridCabecera”).style.pixelLeft = divScroll.scrollLeft * -1;
    }
</script>

<div style=”overflow: hidden; width: 400px”>
    <
asp:datagrid id=“DataGridCabecera” runat=”server” style=”position:relative” DataSource=”<%# dataSet11 %>“>
       
<Columns>
            <
asp:BoundColumn DataField=”ProductID” SortExpression=”ProductID” HeaderText=”ProductID”>
               
<HeaderStyle Width=”80px”></HeaderStyle>
           
</asp:BoundColumn>
           
<asp:BoundColumn DataField=”ProductName” SortExpression=”ProductName” HeaderText=”ProductName”>
               
<HeaderStyle Width=”250px”></HeaderStyle>
           
</asp:BoundColumn>
              
….
        
</Columns>
    </
asp:datagrid>
</
div>
<div style=”overflow: auto; width: 400px; height: 201px” id=”divScroll” onscroll=”DoScroll()”>
     <
asp:datagrid id=“DataGridFilas” runat=”server” DataSource=”<%# dataSet11 %>“>
         <HeaderStyle CssClass=”Esconder”></HeaderStyle>
         
<Columns>
               <
asp:BoundColumn DataField=”ProductID” SortExpression=”ProductID” HeaderText=”ProductID”>
                  
<HeaderStyle Width=”80px”></HeaderStyle>
              
</asp:BoundColumn>
              
<asp:BoundColumn DataField=”ProductName” SortExpression=”ProductName” HeaderText=”ProductName”>
                  
<HeaderStyle Width=”250px”></HeaderStyle>
               
</asp:BoundColumn>
              
….
         
</Columns>
    </
asp:datagrid>
<
div/>

De esta forma tendremos una grilla con la funcionalidad de desplazamiento idéntica a un control Windows Forms.



Descargar codigo completo


Conclusión


El uso de herramientas como CSS (Hojas de estilo en cascada) y DHTML son perfectamente factibles de combinar con los nuevos elementos que introduce ASP.NET permitiéndonos crear interfaces de usuario mas amigables.


Este artículo fue publicado originalmente en la revista MTJ.NET de MSDN Latinoamérica en Diciembre del 2003

digg_url = ‘http://msmvps.com/blogs/cwalzer’;
digg_bgcolor = ‘#ff9900’;
digg_skin = ‘compact’;
digg_window = ‘new’;

Agregar a Technorati

MSDN Radio en Vivo: Discusión: Técnicas y Herramientas para Mejorar el Rendimiento de Aplicaciones y Bases de Datos

Durante el último mes los expertos de Solid Quality Mentors han estado discutiendo técnicas para medir y mejorar el rendimiento de las aplicaciones. Durante este show de MSDN Radio únase a una discusión en vivo sobre cómo optimizar sus aplicaciones, herramientas para medir el rendimiento, mejores técnicas de acceso a datos, tips de optimización de código en SQL Server y cómo mejorar el rendimiento de OLAP y Analysis Server.

Te esperamos para que puedas evacuar tus dudas y debatir acerca de como mejorar el rendimiento de tus aplicaciones .NET y bases de datos.
http://msevents.microsoft.com/cui/WebCastEventDetails.aspx?EventID=1032357579&EventCategory=4&culture=es-AR&CountryCode=AR

Aprovecho la oportunidad para invitarlos a que vean el WebCast de Gustavo Larriera sobre el tema:
Técnicas de ajuste de rendimiento en SQL Server 2005