Tuesday, July 29, 2008

[ASP.NET2.0] Está viva tu aplicación web?

por Ing. Juan Pablo Ibañez
http://ing.juanpablo.googlepages.com

ASP.NET 2.0 está provisto de una funcionalidad que nos permite supervisar el estado de las aplicaciones ASP.NET implementadas, brindándonos información en tiempo de ejecución detallada. Con esta funcionalidad podemos loguear todos los acontecimientos (eventos, errores, etc.) de nuestra aplicación a un archivo de texto, al Event Viewer, a una casilla de mail, etc.

Esta funcionalidad se llama healthMonitoring y para hacer uso de ella basta en la mayoría de los casos con agregar una serie de entradas en el web.config.

En este artículo vamos a ver principalmente un evento de healthMonitoring que puede ser capturado llamado WebHeartbeatEvent. Este evento puede ser configurado para que de dispare cada un cierto tiempo, lo que provoca un efecto de latido. Mientras el servidor y nuestra aplicación estén up cada cierto tiene se disparará este "latido" y podremos saber que nuestra aplicación está en funcionamiento. Se puede configurar este evento para que grabe un log en el EventViewer, en un archivo de texto, o mande un mail.

A continuación vemos las entradas que debemos agregar en el Web.config para que mande un mail cada vez que se produce el evento.

Debemos configurar para que nuestra aplicación pueda mandar mails, por ejemplo de esta forma:

<system.net>
<mailSettings>
<smtp from="xxxxxxxxxx@xxxxxxxxxx.xxx" >
<network host="xxx.xxx.xxx.xxx" />
</smtp>
</mailSettings>
</system.net>

Ahora si configuramos las entradas para healthMonitoring:

<healthMonitoring enabled ="true" heartbeatInterval="0">
<providers>
<add name="mail"
type="System.Web.Management.SimpleMailWebEventProvider"
to="xxxxxxxxxx@xxxxxxxxxx.xxx"
from="xxxxxxxxxx@xxxxxxxxxx.xxx"
buffer="false"
subjectPrefix="Event "/>
</providers>
<rules>
<add name="mail Heartbeats"
eventName="LogueoHeartbeats"
provider="mail"
profile="Default"
minInstances="1"
maxLimit="Infinite"
minInterval="00:30:00"
custom=""/>
</rules>
<eventMappings>
<add name="LogueoHeartbeats"
type="System.Web.Management.WebHeartbeatEvent,
System.Web,Version=2.0.0.0,Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
startEventCode="0"
endEventCode="2147483647" />
</eventMappings>
</healthMonitoring>



Monday, July 07, 2008

[AJAX] Emular el UpdateProgress con ModalPopup


por Ing. Juan Pablo Ibañez
http://ing.juanpablo.googlepages.com

Uno de los controles mas usados de la librería AJAX de Microsoft (ajax.asp.net) es el control UpdatePanel. Este control nos permite hacer un postback parcial de la página y solamente modificar una sección de la misma sin tener que recargar completamente la página. Cuando este postback parcial demora mucho, es conveniente mostrarle el estado al usuario, generalmente se muestra un mensaje como por ejemplo "cargando...", "loading...", "procesando...", etc.
La librería AJAX de Microsoft nos permite hacer esto mediante el control UpdateProgress. Usar este control es sumamente fácil, lo que debemos hacer es definir en un div, por ejemplo, el templete que deseamos que se muestre cuando se está realizando un postback asíncrono.

Un ejemplo de UpdateProgress seria:

<asp:UpdateProgress ID="UpdateProgress1" runat="server">

    <ProgressTemplate>

        An update is in progress...

    </ProgressTemplate>

</asp:UpdateProgress>


Cuando algunos de los UpdatePanel que tenga nuestra página .aspx haga un postback parcial, aparecerá el UpdateProgress y el usuario sabrá que debe esperar hasta que se actualice la parte de la página que está englobada en el UpdatePanel.

Hasta aquí es todo muy simple, el problema surge generalmente cuando el usuario no espera que se actualice la página y hace click nuevamente en el botón, o en otros botones y genera sucesivos postback parciales de la página. Para evitar esto existen varias soluciones:
  1. Deshabilitar del lado del cliente por Javascript todos los controles que hagan postback al servidor hasta que finalice la actualización parcial de la página. El problema es que requiere mucho código Javascript para hacerlo. Si agregamos un control nuevo, tenemos que modificar nuestra rutina para contemplar este nuevo control.
  2. Otra opción, que es la razón de este artículo es utilizar un ModalPopup que cuando presionemos cualquier control que haga un postaback parcial aparezca bloqueando toda posibilidad de que el usuario haga un click en otro control. La ventaja de esta solución es que podemos implementarla de manera tal que sea independiente de la cantidad de controles que tenga nuestra página y de cantidad de páginas que tenga nuestro sitio, etc, etc, etc.

Los elementos que debemos utilizar en esta segunda opción son:
  1. MasterPage.
  2. ModalPopup.
  3. Sys.WebForms.PageRequestManager.

La idea es armar un esquema que no necesite ser replicada en cada una de los webforms que creemos en nuestra aplicación, es por eso que utilizaremos una MasterPage. Es decir en nuestra MasterPage tendremos definido el ModalPopup y el Javascript necesario para hacerlo aparecer, cuando se lance una petición de postback parcial por cualquiera de los controles definidos en cualquiera de nuestros webforms que tengan seteada nuestra MasterPage y también ocultar el ModalPopup cuando la actualización esté terminada.

Muestra MasterPage podría ser:

<%@ Master Language="C#" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

    <head runat="server">

        <title></title>

    </head>

    <body>

        <%-- Código Javascript --%>

        <form id="form1" runat="server">

            <div>

                <asp:ScriptManager ID="ScriptManager1" runat="server"

                    EnableScriptGlobalization="True"

                    EnableScriptLocalization="True">

                </asp:ScriptManager>

                ESTA ES UNA MASTER PAGE

                <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">

                </asp:contentplaceholder>

            </div>

            <%-- ModalPopup --%>

        </form>

    </body>

</html>


Una vez que tenemos nuestra MasterPage lo que debemos definir en esta es el ModalPopup. Un ejemplo de ModalPopup sería:


<asp:LinkButton ID="LinkButton1" runat="server" Visible="true"/>

<asp:Panel ID="Panel" runat="server" Style="display: none">

    <table class="modalPopUp" border="0" cellpadding="0" cellspacing="0">

        <tr class="modalPopUpTopRow">

            <td valign="middle">

                <img src="images/ajax-loader.gif" alt="procesando..." />

            </td>

        </tr>

        <tr>

            <td align="center">

                Procesando...

            </td>

        </tr>

    </table>
</asp:Panel>

<cc1:ModalPopupExtender ID="ModalPopupExtender" runat="server"

    BehaviorID="programmaticModalPopupBehavior"

    TargetControlID="LinkButton1"

    PopupControlID="Panel"

    BackgroundCssClass="modalBackground"/>

Basicamente es ModalPopup tiene un gif animado y una leyenda de "Procesando...". O sea que cuando algún control haga una petición de postback parcial aparecerá este ModalPopup indicando que debe esperar a que termine la actualización de la página evitando que el usuario pueda hacer click en cualquiera de los controles.


Lo que falta ahora es el código Javascript que hacer aparecer y desaparecer el ModalPopup cada vez que comienza y finaliza un request.

Para esto haremos uso del objeto PageRequestManager y le añadiremos 2 funciones una para el evento beginRequest y otro para el evento endRequest.

Estas funciones lo que hacen es buscar el BehaviorID del ModalPopup y una vez que obtenemos la referencia al ModalPopup llamar al método hide() o show() del ModalPopUp.


<script type="text/javascript">

    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(

        function (sender, arg){

            var modalPopupBehavior = $find('programmaticModalPopupBehavior');

            modalPopupBehavior.hide();

        }

    );

   

    Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(

        function (sender, args) {

            var modalPopupBehavior = $find('programmaticModalPopupBehavior');

            modalPopupBehavior.show();

        }

    );

</script>