MSDN Magazine > Home > Issues > 2007 > September >  Cutting Edge: Arquitectura de aplicaciones AJAX...
Cutting Edge
Arquitectura de aplicaciones AJAX, primera parte
Dino Esposito

Descarga de código disponible en: CuttingEdge2007_09.exe (333 KB)
Browse the Code Online
Cualquier administrador del sistema, diseñador o desarrollador, puede ver su trabajo afectado significativamente por AJAX. Los administradores tienen que asegurarse de que la el nivel de seguridad sea lo bastante alto como para afrontar los nuevos tipos de ataques posibles. Los administradores de la intranet tienen que garantizar que JavaScript no esté deshabilitado en ningún explorador. A los diseñadores web se les presentan nuevos desafíos que conseguir, ya que se encuentran con características que ahora son accesibles con AJAX que antes eran imposibles o impracticables. Y los desarrolladores disponen de una API nueva y una nueva perspectiva general de programación con la que familiarizarse. Dicho todo lo cual, ¿qué sentido tiene AJAX para los arquitectos?
Las aplicaciones de AJAX son un desafío porque introducen conceptos completamente nuevos y una base nueva. La función del arquitecto es esencial porque el paradigma de AJAX es un puente de unión entre los entornos de cliente y servidor. Tener una visión arquitectónica clara es vital para determinar qué lógica y procesamiento tienen lugar en el cliente y qué parte permanece en el servidor, así como qué objetos de datos pueden intercambiar el cliente y el servidor.

AJAX al rescate
Las Web se usó en un principio para compartir páginas estáticas de información. Durante los últimos años, evolucionó hacia un medio mucho más dinámico. Hoy, la web está compuesta por páginas muy interactivas; sin embargo, todavía depende mucho de un paradigma que se basa en la transición de páginas enteras. Cuanto más interactúa el usuario con una página, más frecuentemente deben crearse y servirse dichas páginas a su explorador. Hay muchas consecuencias negativas que se derivan de servir páginas interactivas de esta manera, como una actualización lenta de las páginas y el parpadeo. Se trata de una solución nada elegante que lleva con frecuencia a una experiencia de usuario pobre. AJAX implica un cambio muy deseado en este paradigma que permite obtener aplicaciones web más limpias y establecer la base para una generación nueva de aplicaciones. AJAX está realmente destinado al usuario final. Gracias a las características de AJAX, una aplicación web se vuelve mucho más interactiva y tiene mayor capacidad de respuesta. Es más rápida y fácil de usar. Se anima al usuario a hacer más cosas con la página, ya que la interacción y las respuestas (y la realimentación en el caso de operaciones lentas) se administran de un modo mucho más elegante. En términos generales, el usuario consigue tener una experiencia mucho mejor.
Con AJAX, se ejecuta más código en el explorador y esto requiere proporcionar más scripts a las páginas del cliente. Pero esto deja algunas preguntas importantes sin contestar. ¿Qué clase de script? ¿Quién escribirá este script? ¿Y a qué principios y pautas arquitectónicas se adherirá este script?
En esta columna, explicaré AJAX desde un punto de vista arquitectónico para ayudar a desarrolladores y arquitectos a hacer selecciones más reflexionadas. Al mismo tiempo, se dará a los diseñadores y administradores suficiente información de contexto para que puedan llevar a cabo sus trabajos con más facilidad. Al tratarse de un tema bastante importante, lo dividiremos en dos partes. No se pierda la columna del próximo mes, en la que vamos a continuar hablando de este tema.

La arquitectura de AJAX
Si está pensando en aplicar AJAX, vea la figura 1, que ilustra las implicaciones arquitectónicas del cambio. Una aplicación web tradicional realiza todas sus acciones en el servidor. Sólo ocasionalmente la aplicación es la que emite código de scripts para ejecutar una tarea en el cliente, por ejemplo, para administrar la validación de datos.
Figura 1 Paradigma clásico de web frente al paradigma de AJAX (Hacer clic en la imagen para ampliarla)
Una aplicación de AJAX usa un marco de cliente que se ocupa de emitir llamadas al servidor web. A continuación un marco de servidor de AJAX se preocupa de la solicitud y devuelve una alimentación de datos al cliente. Con frecuencia esto será una secuencia de datos de JavaScript Notation Object (JSON), pero pueden usarse otros formatos, como XML, RSS y CSV.
El cliente recibe alimentaciones de datos y actualiza la IU con JavaScript. El servidor responde a solicitudes devolviendo datos sin procesar y codificados en un formato concreto. El consumo del ancho de banda se minimiza, la velocidad de las aplicaciones aumenta debido a que las solicitudes tardan menos en completarse y las actualizaciones de IU pueden hacerse efectivas sin necesidad de ninguna devolución visible. Pero aunque esto resuelve muchos problemas, el aumento en la acción sobre el cliente genera también problemas nuevos, como prácticas nuevas de codificación, peligros nuevos de seguridad, problemas de accesibilidad, etcétera.

¿Qué es un marco de AJAX?
Para mantener AJAX activo en una página web deben cumplirse unas cuantas condiciones. En primer lugar, es necesario que el explorador sea compatible con JavaScript. También se requiere una conexión permanente a Internet, ya que las aplicaciones de AJAX no pueden funcionar sin conexión. Cuando se han hecho todas las solicitudes en el nivel de la página, igual que ocurre con aplicaciones que no son AJAX, el explorador puede ofrecer navegar por un conjunto de estas páginas en la memoria caché, y de esta forma se puede seguir trabajando sin conexión. Este mismo comportamiento tendría que codificarse explícitamente en el marco basado en el script que está asociado al explorador en una aplicación de AJAX. Se está trabajando mucho en esta área y se están desarrollando algunas nuevas herramientas de ayuda. La capacidad de usar aplicaciones AJAX sin conexión es un desafío para muchos proveedores de software.
Cualquier aplicación seria de AJAX requiere un marco especial. Generalmente, el marco elegido se articula en partes separadas para cliente y servidor.
Existen dos tipos principales de código de script en una página de AJAX: el código en el nivel del sistema del marco elegido y el código a nivel de usuario, que implementa el comportamiento previsto de la página. El código en el nivel del sistema proporciona el motor usado para enviar solicitudes asincrónicas al servidor web y así procesar cualquier respuesta. El código en el nivel de usuario actualiza la IU de la página, y lo hace usando esencialmente scripting de modelo de objetos del documento (DOM). Así que nos encontramos con una de las preguntas que mencionaba antes: ¿Quién escribe qué? Para tratar el tema, nos centraremos en un marco concreto de AJAX: las extensiones de AJAX de ASP.NET.

Extensiones de AJAX de ASP.NET
ASP.NET AJAX Extensions es una extensión de ASP.NET 2.0 que ofrece capacidades tanto a los sitios web nuevos como a los ya existentes. Hay dos modelos de programación para AJAX de ASP.NET: la representación parcial y los servicios remotos. Estos dos modelos suponen dos arquitecturas radicalmente diferentes en la aplicación y en consecuencia presentan diferentes pros y contras. (Probablemente ya se habrá visto que la mayoría de las características de AJAX conllevan tanto ventajas como desventajas).
En pocas palabras, la representación parcial permite mantener una arquitectura semejante a la de una aplicación clásica de ASP.NET 2.0. Simplemente ofrece un conjunto de herramientas nuevas de servidor que permiten implementar actualizaciones de página sin parpadeos.
Los servicios remotos, por otro lado, requieren un back-end orientado a servicios e invocado por un front-end de AJAX con un uso bastante profuso de scripts. Casi todos los procesos fundamentales de las aplicaciones, incluidas la autenticación, la paginación de datos y la clasificación, deben volver a diseñarse. Debe producirse código de servidor para los servicios específicos de la aplicación y debe también seleccionarse un formato (como, por ejemplo, JSON) para el intercambio de datos. Finalmente, debe organizarse un cliente y prestarse la atención requerida para limitar la codificación a tareas de nivel de IU y mantener la mayor parte de la lógica empresarial fuera del cliente.
El enfoque de los servicios remotos ofrece una experiencia AJAX más completa, mientras que la representación parcial ofrece una transición más fácil, con una mejora progresiva de las características de la aplicación existente.
Estos dos enfoques pueden combinarse hasta cierto punto. Por ejemplo, se puede mantener la misma arquitectura tradicional de web, agregar algunas actualizaciones sin parpadeos aquí y allá, y entonces tomarse tiempo para volver a producir algunas características claves orientadas a los servicios. Las extensiones de AJAX de ASP.NET proporcionan varios ingredientes claves, pero las partes más elementales de este trabajo para crear unas aplicaciones magníficas de AJAX todavía dependen de usted. La figura 2 muestra los componentes del cliente y del servidor del marco de ASP.NET AJAX Extensions.

Archivo Ubicación Descripción
Microsoftajax.js Cliente Contiene funciones para extender JavaScript con creaciones orientadas a objetos. Extiende el prototipo de objetos de JavaScript integrados y define clases nuevas de aplicación auxiliar, como StringBuilder.
MicrosoftAjaxWebForms.js Cliente Contiene las clases de JavaScript que forman la pila de red y todas las clases que implementa el motor de representación parcial del cliente.
MicrosoftAjaxTimer.js Cliente Representa el modelo de objetos del cliente para el nuevo control de servidor de AJAX System.Web.UI.Timer. Es básicamente un contenedor de servidor para un objeto del temporizador del explorador.
System.Web.UI.ScriptManager System.Web.Extensions Orquesta la descarga de archivos apropiados de JavaScript y datos del cliente, incluidos la biblioteca de AJAX, las clases proxy para servicios remotos, la versión localizada de archivos de scripts y los datos de globalización.
System.Web.UI.UpdatePanel System.Web.Extensions Define una región de una página que puede actualizarse a través de una devolución de AJAX sin parpadeos.
System.Web.UI.UpdateProgress System.Web.Extensions Define una plantilla de servidor que puede usarse para proporcionar realimentación al usuario mientras tiene lugar una operación larga de representación parcial.
System.Web.UI.Timer System.Web.Extensions Control del servidor de aplicación auxiliar que hace las devoluciones a la manera de AJAX cuando un temporizador del cliente secundario agota el tiempo de espera.

Una ojeada a la representación parcial
La columna Código malvado de Jeff Prosise de junio de 2007 (msdn.microsoft.com/msdnmag/issues/07/06/WickedCode) ofrece un excelente debate acerca de la representación parcial con AJAX de ASP.NET. Desde un punto de vista arquitectónico, la representación parcial no agrega nada nuevo. Se trata sólo de una manera interesante de mejorar las aplicaciones heredadas con algunas capacidades de AJAX, la más importante de las cuales es la actualización de páginas sin parpadeos.
La representación parcial no requiere aprender muchas técnicas nuevas y tiene un impacto muy limitado en el código existente. También ofrece un mecanismo de reserva sencillo para tratar aspectos de una aplicación que pueden verse afectados a raíz de la adopción de AJAX, por ejemplo la seguridad y la accesibilidad. Básicamente, si en el proceso de actualización surgen problemas al convertir algunas partes del código existente a AJAX, simplemente se pueden dejar los bloques de código tal y como estaban y seguir adelante.
Una solicitud de representación parcial a menudo se conoce como una devolución de AJAX. El término es bastante apropiado y representa perfectamente lo que sucede en realidad. Una devolución de AJAX es como una devolución clásica de ASP.NET, salvo porque la lleva a cabo una parte de código de script definida en la biblioteca del cliente de AJAX de ASP.NET. Aunque se presenta disfrazada como una llamada remota pura de AJAX, una devolución de AJAX se parece a una solicitud regular de devolución para los componentes del tiempo de ejecución de ASP.NET. Una vez en el servidor, la solicitud pasa por el ciclo de vida habitual de las solicitudes de devolución y origina eventos como Init, Load y PreRender. En el servidor, una devolución de AJAX difiere de una devolución clásica de ASP.NET sólo en el algoritmo que usa para representar el marcado final. Este algoritmo diferente es clave para la mejora del rendimiento y la ausencia de parpadeo en la página. Sin embargo, el modelo de la aplicación sigue siendo el mismo que en ASP.NET. La figura 3 muestra el ciclo de vida modificado de una solicitud de devolución de AJAX.
Figura 3 Ciclo de vida de una devolución de AJAX 
Todo es igual en las devoluciones de AJAX y de ASP.NET, salvo en lo que se refiere a la implementación de la fase de representación. Una devolución de AJAX todavía inicia eventos de notificación como Load y PreRender, y aún procesa la información de viewstate y activa eventos de estados cambiados y de devolución como TextChanged y Click.
Una página de AJAX de ASP.NET debe incluir una instancia del control ScriptManager. Este control es el auténtico centro neurálgico de las páginas de AJAX de ASP.NET. Se ocupa de vincular la página a cualquier archivo de script del marco que sea necesario y organiza la representación parcial si detecta que se está produciendo una devolución de AJAX. El control ScriptManager comprueba si hay un encabezado HTTP en la solicitud para determinar si se trata de una devolución de AJAX. Lo que viene a continuación es un resumen del archivo MicrosoftAjaxWebForms.js que establece el encabezado HTTP antes de activar la solicitud de AJAX:
   request.get_headers()['X-MicrosoftAjax'] = 
       'Delta=true';
Para ver qué hace que el estadio de representación sea diferente en una devolución de AJAX, observe más de cerca el resumen siguiente del ensamblado System.Web.Extensions:
   protected override void OnPreRender(EventArgs e) {
       base.OnPreRender(e);
       if (IsInAsyncPostBack) 
           PageRequestManager.OnPreRender();
   }
En concreto, el fragmento de código que se mostraba anteriormente procede del control ScriptManager. Como puede apreciarse, el director de scripts registra un controlador de eventos de representación preliminar. Al iniciarse, el controlador detecta si está comprometido con una devolución de AJAX y, si es así, invoca un método desde la clase interna de PageRequestManager. El método de OnPreRender de la clase PageRequestManager hace lo siguiente:
   internal void OnPreRender()
   {
       _owner.SetRenderMethodDelegate(
          new RenderMethod(this.RenderPageCallback));
   }
Es bastante simple, el método establece una subrutina específica para representar el marcado para la solicitud actual. SetRenderMethodDelegate es un método definido en la clase System.Web.UI.Control. Como no está destinado a un uso público, este método asigna básicamente un controlador de eventos que la página o el control usarán para representar su contenido. En el fragmento de código anterior, se invoca al método en la página actual que acaba invalidando todo el proceso de representación para la solicitud actual. El verdadero código responsable del marcado de una devolución de AJAX se define por lo tanto en el método RenderPageCallback, un método interno de la clase PageRequestManager. (Para obtener más información sobre el control de ScriptManager, consulte el artículo de Ben Rush sobre este tema en MSDN® Magazine).
Básicamente el proceso de representación modificado para una devolución de AJAX establece bucles en todos los paneles de actualización de la página implicados en la devolución y acumula el marcado de cada uno. Todos los fragmentos del marcado, junto con campos ocultos y cualquier información de errores, se empaquetan en una secuencia de respuestas y se pasan al cliente. Diseccionemos ahora una llamada habitual de representación parcial en el contexto de una página de muestra.

Anatomía de una devolución de AJAX
Para hacer que una página de ASP.NET sea una página que se representa parcialmente, primero debe agregarse un director de scripts a la página, y luego definir independientemente las regiones que puedan actualizarse y ajustarlas con un control UpdatePanel. Aquí se muestra un ejemplo:
<asp:ScriptManager runat="server" />
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
   <ContentTemplate>
      <%-- Markup of the region goes here --%>
   </ContentTemplate>
</asp:UpdatePanel>
El control UpdatePanel no altera de ninguna manera el marcado visible generado para la región. Simplemente agrega una etiqueta <div> circundante al marcado original:
<div id="UpdatePanel1">
      <%-- Markup of the region goes here --%>
</div>
¿Qué activa una devolución de AJAX? ¿Cómo se administra? ¿Y por quién? Siempre que el director de scripts detecta uno o más controles UpdatePanel en la página, emite el bloque del script como se muestra a continuación:
<script type="text/javascript">
Sys.WebForms.PageRequestManager._initialize('ScriptManager1', 
        document.getElementById('form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(
    ['tUpdatePanel1','tUpdatePanel2'], [], [], 90);
</script>
El método _initialize es un método estático del objeto del cliente PageRequestManager (consulte MicrosoftAjaxWebForms.js). Crea una instancia global de la clase PageRequestManager y la inicializa. La clase actúa como singleton y la única instancia disponible puede recuperarse después a través del método getInstance. La segunda declaración del fragmento de código anterior registra una matriz de controles UpdatePanel con el marco del cliente. Se hace referencia a los controles del servidor de UpdatePanel a través de su identificador.
Lo que es clave aquí es lo que tiene lugar dentro del método _initialize. Como hemos dicho, después de crear la instancia de singleton de la clase, el código la inicializa. En este momento, entre otras cosas, se registra un controlador para el evento de envío del objeto del formulario DOM. Esto significa que siempre que la página envía un formulario, el script de AJAX se activa y coloca la solicitud mediante XMLHttpRequest, en vez de permitir que ésta atraviese una devolución normal del explorador. El conjunto original de campos de formularios y alguna información extra se anexan para adecuarse al director de scripts del servidor. Por eso una devolución de AJAX carga un poco más de información que una devolución normal de ASP.NET.
El viewstate, así como cualquier otro campo oculto, se llevan a cabo y se cargan en el servidor junto con la solicitud. De vuelta, se descarga un viewstate actualizado junto con los campos ocultos nuevos, si los hay, y un marcado algo más corto. En concreto, la respuesta incluye sólo el marcado para las regiones que pueden actualizarse y que han sido modificadas durante la devolución. La lista incluye el control UpdatePanel que activó la devolución (y cualquier panel anidado), cualquier otro control UpdatePanel de la página que tiene la propiedad UpdateMode establecida en Always y cualquier control UpdatePanel que se actualiza mediante programación. El código siguiente es un ejemplo de cómo se actualiza un panel mediante programación y basado en las condiciones del tiempo de ejecución:
   UpdatePanel1.Update()
Considere la página del ejemplo que se muestra en la figura 4 y la respuesta devuelta. Puede usar diversas herramientas para supervisar paquetes HTTP entrantes y salientes. Para esta columna, usé la herramienta Web Development Helper de Nikhil Kothari, que puede descargarse de forma gratuita en projects.nikhilk.net/Projects/WebDevHelper.aspx.
<%@ Page Language="VB" CodeFile="Test.aspx.vb" Inherits="Test" %>

<html  >
<head runat="server">
    <title>Test :: Partial Rendering</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager runat="server" ID="ScriptManager1" /> 
        
    <asp:UpdatePanel runat="server" ID="UpdatePanel1">
        <ContentTemplate>
            <asp:TextBox runat="server" ID="TextBox1" /> 
            <asp:Button runat="server" ID="Button1" Text="Update" /> 
            <hr />
            <asp:Label runat="server" ID="Label1" />
        </ContentTemplate>
    </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>

La respuesta de una devolución de AJAX es una secuencia de texto que puede consultarse como una tabla de registros con las columnas Size, Type, ID y Content. Cada registro se conoce como nodo delta. La figura 5 muestra la tabla que se obtiene para la página del ejemplo.

Size Type ID Content
249 updatePanel UpdatePanel1 <input name="TextBox1" type="text" value="Test" id="TextBox1" /> <input type="submit" name="Button1" value="Update" id="Button1" /> <hr /> <span id="Label1"></span>
52 hiddenField __VIEWSTATE  
56 hiddenField __EVENTVALIDATION  
0 asyncPostBackControlIDs    
0 postBackControlIDs    
13 updatePanelIDs   tUpdatePanel1
0 childUpdatePanelIDs    
12 panelsToRefreshIDs UpdatePanel1  
2 asyncPostBackTimeout 90  
9 formAction   Test.aspx
25 pageTitle   Prueba: Representación parcial
Un nodo delta identifica un cambio posible sucedido durante la devolución de AJAX. No todas las respuestas incluyen el mismo conjunto de nodos delta; depende de lo que sucede durante el ciclo de vida del servidor de la solicitud y la estructura del marcado original.
La figura 6 enumera todos los nodos delta compatibles actualmente. El código de JavaScript responsable de procesar la tabla delta puede encontrarse en el archivo MicrosoftAjaxWebForms.js.

Técnicas de optimización para la representación parcial
Después de examinar la figura 6, observará que la respuesta está compuesta por dos bloques grandes: marcado y viewstate. Los datos de validación de eventos (una característica relacionada con la seguridad de ASP.NET 2.0), los campos ocultos personalizados, los scripts y otros tipos de nodos normalmente ocupan unos cuantos bytes en total. El tamaño de viewstate es un viejo problema que tienen las páginas de ASP.NET. Por desgracia, la representación parcial con AJAX de ASP.NET, no hace nada para corregirlo. Todavía necesitará mantener un viewstate eficaz y compacto para poder mejorar el tiempo de descarga. Así que, ¿qué se puede hacer para reducir el marcado de una página? Básicamente, se pueden tener paneles más pequeños que devuelvan sólo la cantidad mínima de marcado necesario para ese clic particular.

Tipo de nodo delta Descripción
updatePanel Almacena el marcado actualizado para una área de la representación parcial.
hiddenField Almacena el contenido de un campo oculto.
arrayDeclaration Almacena una declaración de matrices agregada a la respuesta mediante el método RegisterXXX adecuado en el director de scripts.
scriptBlock Almacena un bloque de scripts agregado a la respuesta mediante el método RegisterXXX adecuado en el director de scripts. El script especificado se ejecuta o se inserta en la página en función del método que se usó.
expando Almacena una propiedad expando agregada a la respuesta mediante el método RegisterXXX adecuado en el director de scripts. El valor especificado se asigna al identificador de la propiedad especificada cuando se procesa la respuesta.
onSubmit Almacena un bloque de scripts de onsubmit agregado a la respuesta mediante el método RegisterXXX adecuado en el director de scripts.
asyncPostBackControlIDs Almacena el identificador de controles registrados como activadores asincrónicos para los paneles de actualización en la llamada.
postBackControlIDs Almacena el identificador de controles registrados como activadores de devolución para los paneles de actualización en la llamada.
updatePanelIDs Almacena el identificador de los paneles de actualización implicados en la llamada.
asyncPostBackTimeout Almacena el tiempo de espera de la solicitud en segundos.
childUpdatePanelIDs Almacena el identificador de cualquier panel de actualización anidado actualizado en la llamada.
panelsToRefreshIDs Almacena el identificador de cualquier panel de actualización actualizado durante la llamada, incluidos los paneles actualizados mediante programación.
formAction Almacena la dirección URL del formulario de la acción.
dataItem Almacena cualquier información extra generada en el servidor para el consumo de los componentes del cliente.
dataItemJson Almacena cualquier información JSON extra serializada y generada en el servidor para el consumo de los componentes del cliente.
scriptDispose Almacena un script de deshecho agregado a la respuesta mediante el método RegisterDispose en el director de scripts. El script especificado se ejecuta en el cliente para el elemento especificado de DOM.
pageRedirect Almacena la nueva dirección URL en caso de una redirección.
error Almacena la información de errores en caso de que se genere una excepción durante la devolución.
pageTitle Almacena el título nuevo de la página.
focus Almacena el identificador del control nuevo que retiene el foco de entrada.
Observe de nuevo el código de la figura 4. La lógica en la página es bastante sencilla, pero ilustra lo que queremos decir. Básicamente, cuando el usuario hace clic en el botón, se usa todo el contenido del TextBox para actualizar la etiqueta.
La página sólo contiene un control UpdatePanel que lo incluye todo: cuadro de texto, botón, separador y etiqueta. Hablando desde el punto de vista de la lógica, esto puede ser aceptable. Si se desea identificar una región de la página para actualizarla autónomamente, puede ser una opción válida. Si embargo, si se define de este modo, la región contiene una parte considerable de código que no se actualiza entre devoluciones. Los controles TextBox y Button, por ejemplo, no se actualizan en esta página, y el separador <hr> es un texto estático sin formato.
Una mejor opción sería reducir UpdatePanel para que sólo incluya el control Label, es decir, el único control del servidor que se actualiza en cualquier devolución activada por el botón. En general, deben identificarse con cuidado las relaciones de las devoluciones entre los controles: examinar básicamente cuál actualiza cuál y diseñar paneles que puedan actualizarse para incluir un número mínimo de controles para una acción determinada de un usuario. En el contexto del ejemplo que se muestra en la figura 4, aquí hay un esquema mejor:
<asp:TextBox runat="server" ID="TextBox1" /> 
<asp:Button runat="server" ID="Button1" Text="Update" 
     OnClick="Button1_Click" /> 
<hr />
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
   <ContentTemplate>
       <asp:Label runat="server" ID="Label1" />
   </ContentTemplate>
   <Triggers>
      <asp:AsyncPostBackTrigger ControlID="Button1" />
   </Triggers>
</asp:UpdatePanel>
El control UpdatePanel ahora contiene sólo el control Label. Esto significa que ningún marcado (sin modificar) será devuelto para los controles textbox y button. De forma predeterminada, un control UpdatePanel se actualiza cuando uno de sus controles secundarios causa una devolución o se actualiza otro UpdatePanel de la página. Este comportamiento puede alterarse con algunas propiedades públicas, por ejemplo, UpdateMode, ChildrenAsTriggers y Triggers.
En particular, UpdateMode determina si UpdatePanel se establece para actualizar de forma incondicional (el predeterminado) o sólo bajo ciertas condiciones. Si desea realizar un actualización condicionada, es decir, una configuración clave para optimizar los paneles que se van a actualizar, empiece por establecer UpdateMode en Conditional:
<asp:UpdatePanel runat="server" ID="UpdatePanel1" 
     UpdateMode="Conditional">
Observe que, sin embargo, las actualizaciones condicionadas son relevantes sólo si se tienen diversos paneles en una página.
Puede que haya situaciones donde parezca difícil dividir una página en un conjunto de paneles normalizados. Una técnica que podría ayudarle en estos casos es evitar que los elementos secundarios activen devoluciones. La propiedad ChildrenAsTriggers es una propiedad booleana (establecida en verdadero de forma predeterminada) que determina si los controles secundarios de un panel actúan como activadores de eventos de devolución de AJAX. En el fragmento de código siguiente, el control Button1 no hace que se actualice el panel:
<asp:UpdatePanel runat="server" ID="UpdatePanel1" 
     ChildrenAsTriggers="false">
   <ContentTemplate>
       <asp:Button runat="server" ID="Button1" Text="Update" 
          OnClick="Button1_Click" /> 
       <asp:Label runat="server" ID="Label1" />
   </ContentTemplate>
</asp:UpdatePanel>
Al hacer clic en un botón secundario de un panel configurado de esta forma, tiene lugar una devolución de AJAX para ejecutar cualquier código de devolución adjunto en el botón, por ejemplo, el método Button1_Click, pero no se devuelve ningún marcado para actualizar el panel.
La tercera propiedad implicada en la actualización condicionada es Triggers. Se trata de una propiedad de recopilación y muestra los eventos de control que ordenarán un actualización del panel, como ésta:
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
   <ContentTemplate>
       <asp:Label runat="server" ID="Label1" />
   </ContentTemplate>
   <Triggers>
      <asp:AsyncPostBackTrigger ControlID="Button1"
           EventName="Click" />
   </Triggers>
</asp:UpdatePanel>
En este caso, el evento Click de Button1 actualizará el panel. El control Button1 puede colocarse en cualquier lugar de la página. Tenga en cuenta que estamos hablando de eventos del servidor. Es decir, si se desea actualizar un panel cuando el usuario cambia la selección en una lista desplegable, debe agregarse primero el atributo AutoPostBack a la lista desplegable.
Todavía puede configurar un panel para que se actualice cuando un evento de estado cambiado tenga lugar en el servidor durante una devolución de AJAX. Observe el siguiente código:
<asp:TextBox runat="server" ID="TextBox1" /> 
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
   <ContentTemplate>
       <asp:Label runat="server" ID="Label1" />
   </ContentTemplate>
   <Triggers>
      <asp:AsyncPostBackTrigger
           ControlID="TextBox1"
           EventName="TextChanged" />
   </Triggers>
</asp:UpdatePanel>
La etiqueta se actualiza siempre que el contenido TextBox1 cambia:
Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles TextBox1.TextChanged
   Label1.Text = TextBox1.Text
End Sub
El evento TextChanged, así como otros eventos de estado cambiado, son eventos del servidor que se inician como resultado de una devolución. La página aún necesita un botón, o un control de devolución automática, para activar la devolución y así actualizar la etiqueta.
El gráfico de la figura 7 resume las posibles ventajas que pueden obtenerse de aplicar técnicas de optimización a los paneles que pueden actualizarse. Mediante la representación parcial, el tamaño del paquete de solicitudes aumenta poco, pero incluso en el caso menos optimizado la respuesta que se obtiene es más pequeña que la de una situación típica de ASP.NET. Y, por supuesto, los usuarios no experimentan más parpadeos.
Figura 7 Ventajas de optimizar paneles que pueden actualizarse (Hacer clic en la imagen para ampliarla)
Debo advertir, sin embargo, que las páginas con un viewstate grande quizás no se beneficien de la representación parcial. Puede que ahorre 5 KB de marcado, pero no es mucho si tiene que cargar con 30 KB de viewstate.
Pero a veces, viewstate es sólo un cabeza de turco inocente de un problema que se originó en otra parte. Supongamos que tiene un control de calendario en una página de ASP.NET y se usan paneles que pueden actualizarse para mantener una actualización sin conflictos:
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
   <ContentTemplate>
       <asp:Calendar runat="server" ID="Calendar1" />
   </ContentTemplate>
</asp:UpdatePanel>
El marcado para este fragmento no es menor de 7 KB, y puede crecer hasta 10 KB si se agregan algunos estilos. Ahora bien, si se desactiva el viewstate del calendario, se ahorrará aproximadamente 1 KB de datos, que es sólo un 10 por ciento del tamaño total. Esto es así porque Calendar es un control pesado en términos de marcado. El viewstate tiene poco que ver con este problema. Una página de ASP.NET AJAX no debería usar controles Calendar para las funciones de selección de fechas. En vez de eso, AJAX Control Toolkit ofrece un extensor, el control CalendarExtender, que, cuando se ha agregado a un TextBox sin formato, permite seleccionar fechas, ahorrando 10 KB de marcado.
Este código hace emerger un calendario siempre que el cuadro de texto recibe el foco de entrada:
<asp:textbox runat="server" ID="TextBox1" />
<act:CalendarExtender ID="CalendarExtender1" runat="server"
    TargetControlID="TextBox1"   
    OnClientDateSelectionChanged="updateLabel"
    Format="dd/MM/yyyy" />

<asp:UpdatePanel runat="server" ID="UpdatePanel1" 
     UpdateMode="Conditional">
    <ContentTemplate>
        <asp:label runat="server" ID="Label1" />
    </ContentTemplate>
</asp:UpdatePanel>
El calendario se crea completamente en el cliente y sólo requiere la descarga de un par de iconos pequeños. El extensor escribe automáticamente la fecha seleccionada en el TextBox complementario. Sin embargo, con un poco de código de JavaScript, puede administrar el evento de la selección de fechas de cliente y hacer cualquier cosa que necesite.

Compensación de la representación parcial
La representación parcial es la manera más rápida de adornar un sitio web de ASP.NET con capacidades de AJAX. No requiere ni habilidades nuevas ni una arquitectura nueva. En vez de eso, se presta a mejorar progresivamente un sitio web existente. Pero comparado con un enfoque puro de AJAX (llamadas del cliente directo a los servicios remotos) la representación parcial sufre penalizaciones considerables en su rendimiento.
Como norma general, se recomienda la representación parcial como el mejor enfoque para crear una primera versión sólida de AJAX de un sitio. Progresivamente puede irse alejando de la arquitectura clásica de ASP.NET y empezar a crear un conjunto de servicios back-end y un nivel de presentación sólido. En la entrega siguiente de Cutting Edge, exploraremos los servicios remotos relacionados con AJAX. Es fantástico desde el punto de vista de la arquitectura, pero puede requerir volver a diseñar completamente la aplicación y origina unos cuantos problemas nuevos.

Envíe sus preguntas y comentarios para Dino a la dirección cutting@microsoft.com.


Dino Esposito es profesor de Solid Quality Learning y autor de Programming Microsoft ASP.NET 2.0 (Microsoft Press, 2005). Con residencia en Italia, Dino participa habitualmente en conferencias de eventos del sector en todo el mundo. Puede ponerse en contacto con Dino en la dirección cutting@microsoft.com o entrar en su blog en weblogs.asp.net/despos.

Page view tracker