jueves, 16 de septiembre de 2010

Difererencias entre Eval, DataBinder.Eval y Bind

Lo primero es saber que cuando estamos dentro del contexto de una plantilla, el “elemento” al que estamos haciendo referencia con Eval es del tipo de un elemento del origen de datos. Así, si por ejemplo tenemos como origen de datos un DataTable, el “elemento” será del tipo “DataRowView”, pero si estamos enlazados a una colección de objetos de tipo “Empleado”, el tipo del elemento será “Empleado”.

Dentro de una plantilla de enlace a datos podemos utilizar:

  • Container.DataItem
  • DataBinder.Eval
  • Eval

Container puede ser “casteado” al tipo de la plantilla actual por la que estamos iterando (por ejemplo RepeaterItem), aunque cabe mencionar que si tenemos un control que implementa INamingContainer dentro de nuestro elemento actual (por ejemplo un LoginView dentro del RepeaterItem), Container será entonces del tipo LoginView y para acceder al control de tipo RepeaterItem tendremos que escribir algo como Container.NamingContainer. Una vez hemos accedido al elemento contenedor apropiado, podemos acceder a Container.DataItem que significa “dame el elemento de datos actual por el que estoy iterando”, que además podrá ser “casteado” de nuevo al tipo del elemento que sea realmente (DataRowView, Empleado, etc.).

En cualquier caso y como atajo, también podemos utilizar la expresión DataBinder.GetDataItem(Contenedor) donde “Contenedor” tiene que ser por ejemplo en nuestro caso, el RepeaterItem.

Por otro lado DataBinder.Eval nos permite acceder a la propiedad “indizada” sin conocer el tipo del “elemento” actual. Ya que si escribimos DataBinder.Eval(Container.DataItem, “Nombre”), ASP.NET será muy listo y sabrá si Nombre es una propiedad del objeto (en el caso de Empleado) o un campo del DataRowView.

Eval es una nueva instrucción que apareció en ASP.NET 2.0 como versión reducida de DataBinder.Eval, pero además de esto, hay más diferencias entre ellas: 

  • Eval sólo puede utilizarse en el contexto de una plantilla
  • DataBinder.Eval, además de poder utilizarse en el contexto de una plantilla, también puede ser utilizado en un procedimiento del code-behind/code-beside
  • La sintaxis acortada de Eval es diferente de la de DataBinder.Eval en el hecho de que Eval resuelve automáticamente el campo a través de la propiedad DataItem del objeto contenedor más cercano, mientras que DataBinder.Eval coge el argumento del contenedor (pudiendo elegir nosotros que contenedor y elemento utilizar a través de un “cast” oportuno).
    Es por esto que Eval sólo se usa dentro de una plantilla de un control de enlazado de datos y no se puede usar en el nivel de página.
  • Bind es igual en su comportamiento y uso que Eval, sólo que además soporta la actualización, eliminación e inserción con el control origen de datos. Esto se denomina “Two-Way”, es decir, no sólo se enlazan controles de datos a controles de orígenes de datos para su lectura y presentación, sino también para “modificación” de la capa de datos que subyace a todo este escenario. Cuando sólo se leen datos se denomina “One-Way”.

Los controles que soportan “Two-Way” son:

  • GridView
  • DetailsView
  • FormView

Finalmente, y para un objeto de tipo RootFolder (que bien podría ser Empleado, CuentaBancaria, DataRowView, etc), podemos ver las distintas maneras de enlazar datos en una plantilla:

FolderID:<%# CType(Container.DataItem, Entities.RootFolder).FolderID%>

 

FolderID:<%# DataBinder.Eval(Container.DataItem, " FolderID ")%>

 

FolderID:<%# Eval("FolderID")%>

Referencias:

http://weblogs.asp.net/rajbk/archive/2004/07/20/what-s-the-deal-with-databinder-eval-and-container-dataitem.aspx

http://dotnetguts.blogspot.com/2006/12/databindereval-method.html

Un saludo!

jueves, 9 de septiembre de 2010

Versiones de IIS

Hola, a propósito de la serie de artículos sobre IIS que tengo previsto publicar, me ha parecido oportuno recordar como identificar que versión de IIS viene integrada con cada versión de sistema operativo.

Esta información está sacada de wikipedia (http://es.wikipedia.org/wiki/Internet_Information_Services), pero a grandes rasgos tenemos:

  • IIS 1.0, Windows NT 3.51 Service Pack 3
  • IIS 2.0, Windows NT 4.0
  • IIS 3.0, Windows NT 4.0 Service Pack 3
  • IIS 4.0, Windows NT 4.0 Option Pack
  • IIS 5.0, Windows 2000
  • IIS 5.1, Windows XP Professional
  • IIS 6.0, Windows Server 2003 y Windows XP Profesional x64 Edition
  • IIS 7.0, Windows Vista (Solo Bussines y Ultimate) y Windows Server 2008
  • IIS 7.5, Windows 7 y Windows Server 2008 R2
  • IIS 8.0, Windows Server 2012 y Windows 8.

    Un saludo.

  • miércoles, 8 de septiembre de 2010

    Grupos de aplicaciones en IIS

    Me he propuesto realizar una serie de posts relativos a IIS y ASP.NET.

    El primero de ellos es este mismo y tratará sobre los grupos de aplicaciones y las identidades de usuarios que intervienen en el proceso autenticación, autorización, suplantación y respuesta a un recurso solicitado.

    En realidad este post es casi un copy/paste (pero con todo el cariño del mundo) de este otro post que igualmente recomiendo leer. http://web.archive.org/web/20080210135951/http://www.microsoft.com/spanish/msdn/articulos/archivo/111002/voices/IIS6ASPNET.asp

    ¿En qué momento aparecen en escena los grupos de aplicaciones?

    Cuando IIS recibe una petición a un recurso, el primer componente que aparece en escena es el módulo del kernel de Windows llamando HTTP.sys. Una vez que este módulo comprueba que la petición es válida y no tiene ninguna versión válida en cache que servir, redirecciona la petición al grupo de aplicaciones (ApplicationPool) que atiende a dicha petición y lo añade a su cola de peticiones.

    ¿Qué es un grupo de aplicaciones?

    Un grupo de aplicaciones encapsula uno o varios procesos que sirven uno o varios sitios web o aplicaciones. Por norma, un grupo de aplicaciones está compuesto por un solo proceso pero en el caso de estar compuesto por varios procesos estaríamos hablando de un Web Garden. Este concepto es especialmente útil en máquinas multiprocesador donde se puede especificar la afinidad de cada proceso del grupo de aplicaciones con un procesador concreto.

    Cada uno de los procesos que gestiona el grupo de aplicaciones se denominan Worker Process (w3wp.exe) y se ejecutan bajo la identidad de usuario especificada en las propiedades del grupo de aplicaciones. Cabe mencionar que estos procesos no se arrancan hasta que el grupo de aplicaciones recibe una petición y que pueden detenerse o reciclarse en función de la configuración del grupo de aplicaciones.

    ¿Qué ventajas suponen la aparición de los grupos de aplicaciones?

    Aislamiento de aplicaciones. Esto quiere decir que si una aplicación contenido en un grupo de aplicaciones falla no podrá afectar al resto de aplicaciones en otros grupos de aplicaciones distintos, esto es que se establecen unos límites para las aplicaciones que no se podrán rebasar al estar contenidas en un grupo de aplicaciones.

    Monitorización o control de recursos. Al ejecutarse siempre una aplicación en un grupo de aplicaciones resulta más sencillo monitorizar el uso de recursos que realiza el grupo de aplicaciones en el servidor, a la par que en entornos multiprocesador se puede crear afinidad del grupo de aplicaciones con un procesador determinado estableciendo, si fuera necesario, unos límites de uso y carga del procesador.

    Tolerancia a fallos. Además del ya comentado aislamiento de aplicaciones, un grupo de aplicaciones puede programarse para reciclarse bajo determinadas circunstancias.

    Configuración de la identidad del Worker Process. Es posible configurar el grupo de aplicaciones para especificar bajo que cuenta de usuario ejecutará su proceso o procesos asociados. De este modo, si un proceso o aplicación fuera comprometido por un usuario malintencionado sólo podría tener acceso a los recursos a los que pueda acceder la identidad del grupo de aplicaciones.

    Algunas de las cuentas sugeridas por defecto para un grupo de aplicaciones son:

    ¿En qué momento aparece ASP.NET en escena?

    Cuando el grupo de aplicaciones recibe una petición a través de la cola que lo une con HTTP.SYS, decide cómo resolverla en función del tipo o extensión de la URL solicitada. Por ejemplo, en el caso de páginas .aspx éstas van dirigidas a la ISAPI de ASP.NET (aspnet_isapi.dll), asociación especificada en el mapeo de extensiones en el servidor.

    Las responsabilidades de esta ISAPI son las siguientes y en el orden descrito:

    • Compilar el código. este paso se realiza exclusivamente en caso necesario, es decir, si no está previamente compilado en la caché o se ha modificado algún archivo. Esta caché se almacena en <%windows%>\Microsoft.NET\Framework\<%version%>\Temporary ASP.NET Files.
    • Ejecutar el código. En este paso se ejecuta el código compilado de la página .aspx y se genera la respuesta HTML.
    • Devolver el resultado al cliente. Se pasa la respuesta a HTTP.SYS para que lo devuelva al cliente.

    Autenticación y autorización

    Como vimos en una entrada anterior (http://panicoenlaxbox.blogspot.com/2010/09/autenticacion-autorizacion-y.html) este proceso es llevado a cabo conjuntamente por IIS y ASP.NET. Ahora intentaremos dar un repaso a estos pasos de la forma más clara y concisa posible:

    Un usuario realiza una petición desde su navegador.

    • IIS autentica al usuario (de forma anónima, Windows integrada, etc.).
    • IIS autoriza el acceso al recurso solicitado bajo la cuenta del usuario anterior. Es aquí donde entra por primera vez en juego los permisos NTFS. En caso de que la petición no sea autorizada veremos el típico error de “Acceso denegado”.
    • ASP.NET autentica al usuario si es preciso (si por ejemplo está activa la autenticación Forms, ya que en caso de ser Windows no realiza ningún paso extra).
    • ASP.NET autoriza al usuario si es preciso, mediante los permisos asociados al modo de autenticación Forms.
    • Por último, el acceso al recurso solicitado es realizada a través de la cuenta de usuario especificada en la configuración del grupo de aplicaciones (la cuenta bajo la que se ejecuta el Worker Process) y de nuevo tiene que superar la autorización que supone NTFS.

    Un saludo!

    lunes, 6 de septiembre de 2010

    Autenticación, autorización y suplantación en ASP.NET

    La seguridad en ASP.NET es un proceso de 2 capas.

    Todas las solicitudes a nuestro servidor web se gestionan en primer lugar por IIS y después por ASP.NET.

    De este modo es inicialmente IIS quién podrá aceptar o rechazar la petición solicitada. Si IIS acepta la petición, entonces se pasará a ASP.NET (en forma de token de seguridad representando al usuario autenticado y autorizado por IIS), donde se volverá a examinar atendiendo ahora a los criterios de seguridad de ASP.NET

    Los sistemas de seguridad de IIS y ASP.NET son independientes entre sí.
    Esto significa que son 2 capas de seguridad bien diferenciadas pero que trabajan de forma coordinada para ofrecer un único resultado.

    Para hablar de seguridad en IIS y ASP.NET es necesario manejar los siguientes conceptos:

    • Autenticación
      • Proceso por el que se valida las credenciales suministradas por el usuario contra una autoridad válida que pueda confirmar que el usuario es quien dice realmente ser.
    • Autorización
      • Después de la autenticación, el proceso de autorización determina si el usuario tiene permiso para acceder o no al recurso solicitado.
    • Suplantación, impersonalización
      • Proceso por el que ASP.NET utiliza para acceder a un recurso, una cuenta de usuario distinta de la que arrancó el proceso de ASP.NET.

    Si hablamos de la autenticación en IIS podemos encontrar la autenticación anónima, básica, texto integrada, Windows Integrada, etc.

    Cabe mencionar que la autenticación anónima podría considerarse como una no autenticación, puesto que IIS aceptará cualquier petición sin solicitar ninguna credencial al usuario ni llevar a cabo ningún tipo de autenticación. Aun así, como todas las solicitudes en IIS tienen que disponer de unas credenciales válidas se asignarán automáticamente a la cuenta IUSR_<NombreMáquina> que IIS crea durante su instalación.

    De hecho, la autenticación anónima es el método más rápido pero también el menos seguro (es el más rápido porque no necesita de autenticación contra una autoridad válida pero el menos seguro porque no autentica).

    Por otro lado, la autenticación integrada de Windows nos permite utilizar la seguridad integrada del sistema operativo basado en NTFS y pasar como token de seguridad a ASP.NET una cuenta de usuario válida del sistema o dominio (las credenciales del usuario son enviadas automáticamente por el navegador en las cabeceras de la solicitud HTTP cuando se detecta que el servidor requiere las mismas – modo de autenticación Windows Integrado - o bien se presenta un cuadro de diálogo – modo de autenticación básico).

    En este punto está claro que si alguien pide una página .aspx a nuestro servidor, la cuenta IUSR_<NombreMáquina> tiene que superar:

    • Autenticación.
      • Esto es automático ya que asumimos un escenario de autenticación anónima.
    • Autorización.
      • Tiene que poder acceder al fichero .aspx, y esto se traduce en que tiene que tener permisos de lectura sobre el fichero.

    Si alguno de estos mecanismos falla ASP.NET simplemente NO entra en escena porque IIS aborta la petición.

    Superada con éxito la autenticación y autorización de ISS, ahora es el turno de la autenticación y autorización de ASP.NET.

    Si hablamos de la seguridad de ASP.NET es muy importante el concepto de la impersonalización.  

    Por defecto ASP.NET no impersonaliza. Esto quiere decir que superada la seguridad de IIS, el acceso a cualquier recurso (disco, red, etc.) se realizará bajo el contexto de seguridad de la cuenta que haya arrancado el proceso de ASP.NET (la cuenta asignada al grupo de aplicaciones en el que se está ejecutando nuestra aplicación ASP.NET).

    Si por otro lado hemos decidido que ASP.NET impersonalice, el acceso a los recursos será realizado bajo el contexto de seguridad de la cuenta de usuario que representa el token de seguridad que fue recibido por IIS.

    Es decir, si no impersonalizamos (comportamiento por defecto), el acceso a recursos será bajo la cuenta del proceso de ASP.NET. Si impersonalizamos, el acceso será bajo la cuenta de usuario recibida desde IIS (que puede ser IUSR_<NombreMáquina> si está activa la autenticación anónima, Dominio\Usuario si está activa la seguridad de Windows Integrada, etc.)

    Volviendo a la capa de seguridad de ASP.NET, lo primero que tenemos que decidir es que método de autenticación queremos activar en ASP.NET. Los posibles valores son Windows (por defecto) o Forms.

    Si te fijas, elegir el proveedor de autenticación de ASP.NET es una decisión a tomar de forma conjunta al método de autenticación vigente en IIS. Así, si tenemos activada la autenticación anónima, quizás debiéramos seleccionar el proveedor de autenticación Forms que incluye una gestión completa de usuarios y permisos a través de los ficheros web.config, mientras que si no tenemos la autenticación anónima de IIS activa se debería seleccionar Windows. En cualquier caso, esto es siempre queriendo entrar en la mecánica propuesta de seguridad por ASP.NET porque para gustos los colores.

    Una vez hemos superado con éxito la capa de seguridad de IIS (autenticación y autorización) y también la autenticación de ASP.NET (Forms), llega el turno de la autorización de ASP.NET sobre el recurso solicitado (que, recordemos, a no ser que se impersonalice a través de ASP.NET, el acceso el recurso se llevará a cabo a través de la cuenta de usuario en la que se ejecuta el proceso de ASP.NET y no en la cuenta de usuario que IIS suministra a ASP.NET).

    Respecto a la autorización de ASP.NET, cabe mencionar que para extensiones asignadas a ASP.NET será el propio ASP.NET quién autorice (por ejemplo, .aspx, .ashx, etc.), pero para cualquier otro tipo de recurso será IIS quién autorice (por ejemplo  recursos estáticos como .jpg, .js, etc.).

    Si fuera necesario podría ser ASP.NET quien se encargará de autorizar todos los tipos de recursos, tanto estáticos como los propios, pero ese es otro tema. Aquí es importante saber la versión de IIS en la que estamos ejecutando nuestra aplicación ASP.NET: Si es inferior a 7.x funcionará como lo dicho anteriormente pero si es 7.0 o superior, todas las peticiones son gestionadas por ASP.NET (incluidas aquellas a recursos estáticos).

    Hasta ahora hemos hablado del “proceso en el cual se ejecuta ASP.NET”, pero
    ¿Cuál es ese proceso?

    En versiones de IIS 6.0 o superiores el nombre del proceso es w3wp.exe, mientras que en versiones anteriores el nombre es aspnet_wp.exe.

    Por otro lado, la cuenta por defecto para el proceso de ASP.NET es la cuenta que tenga configurada el grupo de aplicaciones en el que esté asignada la aplicación.

    Por ejemplo, Windows 2003 Server crea por defecto un grupo de aplicaciones llamado DefaultAppPool que se ejecuta bajo el contexto de seguridad de la cuenta NT AUTHORITY\Servicio de red.

    Siendo así, si queremos dar permisos de escritura en un directorio (porque por ejemplo generamos algún tipo de fichero), será a esa cuenta a la que tengamos que dar los permisos de escritura.

    clip_image001

    Aunque Windows 7 crea igualmente un grupo de aplicaciones DefaultAppPool, incorpora un nuevo tipo de cuenta llamada ApplicationPoolIdentity que en realidad es el usuario IIS APPPOOL\DefaultAppPool.

    Aquí cabe mencionar que el nombre de usuario DefaultAppPool es simplemente el nombre del grupo de aplicaciones, por lo que si nuestro grupo de aplicaciones se llama ContabilidadAppPool, la cuenta de usuario será IIS APPPOOL\ContabilidadAppPool.

    Para saber más sobre este nuevo tipo de cuentas virtuales, recomiendo el siguiente enlace que explica perfectamente todo lo referente a estas cuentas http://learn.iis.net/page.aspx/624/application-pool-identities/

    En cualquier caso, cabe mencionar que estas cuentas virtuales (digo virtuales porque no existen y se crean dinámicamente cuando arranca el grupo de aplicaciones) pertenecen a los siguientes grupos:

    • Todos
    • BUILTIN\Usuarios
    • NT AUTHORITY\SERVICIO
    • INICIO DE SESIÓN EN LA CONSOLA
    • NT AUTHORITY\Usuarios autentificados
    • NT AUTHORITY\Esta compañía
    • BUILTIN\IIS_IUSRS
    • LOCAL

    clip_image002[1]

    Al respecto de estas cuentas virtuales (ApplicationPoolIdentity) cabe mencionar que si quieres asignarles permisos en una carpeta o fichero concreto, no aparecen como disponibles en el listado de cuentas del equipo o dominio, así que es necesario introducirlas a mano en la pestaña seguridad de los permisos NTFS.

    Puedes ver cómo llevar a cabo estar tarea en el siguiente enlace imprescindible http://learn.iis.net/page.aspx/624/application-pool-identities/

    Por último sólo nos resta hablar de cómo impersonalizar en ASP.NET.
    Para ello tenemos disponibles 2 opciones:

    Impersonalizar bajo el contexto de seguridad de la cuenta de usuario recibida desde IIS. Para ello simplemente debemos agregar lo siguiente a nuestro web.config.

    <identity impersonate="true"/>

    Impersonalizar bajo una cuenta de usuario específica con independencia del token suministrado por IIS.

    <identity impersonate="true" userName="Usuario" password="Contraseña"/>

    Además de impersonalizar de modo global a través de ficheros de configuración (web.config) también se puede impersonalizar sólo ciertas líneas de código. Imagina que sólo una función de tu código tiene acceso a un fichero para que el necesitas ciertos permisos.

    En cualquier caso, hay que reseñar que la impersonalización puede afectar significativamente al rendimiento y escalado de la aplicación.

    Un saludo!

    miércoles, 14 de julio de 2010

    Servicios web y componentes de cliente

    En un post anterior vimos cuales eran los secretos y las consideraciones a la hora de trabajar con el control UpdatePanel.

    Sin embargo hay ocasiones en las que un control UpdatePanel no satisface nuestros requerimientos por diversos motivos. De este modo, tenemos otras opciones que nos brinda ASP.NET AJAX como son los servicios web y los métodos web de página.

    Un servicio web puede servir a distintos propósitos (no sólo para ayudarnos a la actualización parcial de una página) pero en esta entrada nos centraremos exclusivamente en esa funcionalidad. Siendo así, un servicio web se diferencia de un control UpdatePanel en lo siguiente:

    • Un servicio web no pertenece a una página aspx (a excepción de los métodos web de página aunque no es relevante).
    • Un servicio web (tampoco un método web de página) no lanza el ciclo de vida de una página .aspx.
    • El tamaño del envío y la respuesta de un servicio web es más reducido puesto que sólo hay que enviar unos mínimos datos al servicio y el servicio a su vez sólo devolverá el contenido solicitado.
    • En lo relativo a la representación parcial de una página, un servicio web es utilizado cuando el contenido que queremos actualizar no depende de los datos de la propia página o el contenido es literal (no queremos devolver un control de usuario con comportamiento de cliente ASP.NET AJAX).

    Esto último es de vital importancia puesto que a grandes rasgos, un servicio web siempre devuelve texto, sólo texto. Por ejemplo, podríamos devolver el texto que resulta de renderizar un control pero no su comportamiento. De este modo, el servicio web nos devolvería la primera instantánea del control pero al intentar interactuar con el control, la página fallaría porque no conoce el control (no se ha declarado en la página .aspx, ni se ha incluido de forma dinámica a través de la colección de controles de algún otro control contenedor de la página y además si fuera necesario crear un componente de cliente a través de ASP.NET AJAX para su funcionamiento, tampoco se hubieran ejecutado sus scripts requeridos). En definitiva, si vamos por la vía de un servicio web o un método web de página, nuestro principal uso será devolver contenido literal que podremos después inyectar en el DOM de cliente, pero no podemos esperar por ejemplo, devolver un control Tab de ASP.NET AJAX Control Toolkit y que funcionen las pestañas.

    Ahora la pregunta final que resolveremos en un siguiente post es ¿Cómo cargar un control que necesita componente de cliente – rutinas de javascript – y conseguir que su carga sea lo más óptima posible (esto es no utilizando un UpdatePanel)?

    Un saludo!

    Cuidado con el control UpdatePanel!

    El control UpdatePanel hace posible la representación parcial de una página. Esto es que, con este control, es posible actualizar sólo cierto contenido de la página en el cliente. Para su utilización hay que tener en cuenta 2 cosas muy importantes y que si no se entienden correctamente podrían arruinar el funcionamiento esperado del control.

    1. Durante el proceso de la petición asíncrona que desencadena un control UpdatePanel, en el servidor se ejecuta todo el ciclo de vida de la página que alberga el control. Esto es que, aunque el resultado de la petición sólo sea la actualización de una parte de la página del cliente, en realidad la petición ha desencadenado:
      • El envío y posterior actualización del estado de vista.
      • Se ha cargado de nuevo la página en el servidor y ha ocurrido todo el ciclo de vida de la página (aunque insisto nuestro único propósito era actualizar sólo cierta parte de la página).
      • Se han ejecutado todos los manejadores declarados en el código de la página en el servidor que procedan (Page_Load, Page_PreRender, etc.)
    2. El control UpdatePanel tiene una propiedad que determina drásticamente su comportamiento y eficiencia, la propiedad es UpdateMode. La propiedad UpdateMode tiene 2 posibles valores: Always y Conditional. Por defecto el valor de la propiedad es Always y eso justamente y en mi opinión es un error puesto que, aunque en principio nos facilita la vida cuando no queremos indagar en exceso sobre el funcionamiento del control UpdatePanel, cuando hablamos en términos de rendimiento y control preciso de que partes de la página cliente son actualizadas, es un escollo que tendremos que tratar.

    Para ilustrar de forma concreta la importancia de estas 2 propiedades, lo mejor será un ejemplo de su utilización. Supongamos una sencilla página con 2 controles de tipo UpdatePanel y en cada uno de ellos un control Literal y un botón.

    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
    <asp:Literal runat="server" ID="Literal1" Text="Texto no asignado"></asp:Literal>
    <br />
    <asp:Button runat="server" ID="Button1" Text="Actualizar" />
    </ContentTemplate>
    </asp:UpdatePanel>

    <asp:UpdatePanel ID="UpdatePanel2" runat="server">
    <ContentTemplate>
    <asp:Literal runat="server" ID="Literal2" Text="Texto no asignado"></asp:Literal>
    <br />
    <asp:Button runat="server" ID="Button2" Text="Actualizar" />
    </ContentTemplate>
    </asp:UpdatePanel>


    Y con el siguiente código en el servidor:

        Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
            Literal1.Text = System.DateTime.Now.ToString
        End Sub


        Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
            Literal2.Text = System.DateTime.Now.ToString
        End Sub


    Con la página cargada, nuestra primera acción es pulsar el botón Button1. El resultado en pantalla es:

    clip_image002

    En principio todo parece correcto, pero con la ayuda de firebug vamos a poder ver los entresijos de la petición desencadenada por la pulsación del botón y ver como no es oro todo lo que reluce. La petición ha enviado toda la información de la página sólo para actualizar un literal con la hora actual. Vemos como se incluyen todos los campos del formulario (entre los que está el campo __VIEWSTATE – que puede ser enorme!). Aunque en este caso concreto nos parezca que no se ha enviado demasiada información (o al menos que es soportable el tamaño del envío), en páginas complejas el tamaño de los datos enviados puede ser mucho mayor y en ocasiones estaremos hablando de un “killer-application” o lo que también viene llamándose “matar moscas a cañonazos”.

    clip_image004

    Además, también es hora de examinar la respuesta del servidor a nuestra petición:

    clip_image006

    Ver como en la respuesta hay 3 bloques claramente diferenciados:



    • El contenido a actualizar para el control UpdatePanel1.

    • El contenido a actualizar para el control UpdatePanel2.

    • El contenido a actualizar para los controles Hidden que gestiona automáticamente ASP.NET (__VIEWSTATE, __EVENTVALIDATION, etc.)

    En realidad el bloque 1 y 3 son innegociables, así funciona el control UpdatePanel y no podemos hacer nada para evitarlo, pero la pregunta es ¿Por qué se actualiza también el contenido de UpdatePanel2? De hecho, se actualiza al mismo contenido que tiene, así que además de “engordar” el tamaño de la respuesta de la petición, actualiza el control a su mismo contenido (aquí cabe mencionar que aunque parezca que no importa actualizar una parte del DOM del cliente a un mismo valor, en realidad bajo cuerda suceden eventos de cliente de ASP.NET AJAX, se tienen que eliminar elementos del árbol DOM de cliente y volverlos a crear, así que para un Literal no parece un problema, pero para contenido más complejo estaremos robando ciclos de CPU al cliente en un tarea que se puede evitar). Está en nuestra mano poder eliminar el bloque 2 (al que nadie invitó a la fiesta). Simplemente añadiremos la propiedad UpdateMode = “Conditional” al control UpdatePanel2. Con esta propiedad le estamos indicado al control UpdatePanel que sólo debe actualizarse si él mismo (o alguno de sus desencadenadores válidos – triggers) ha iniciado la petición.

    <asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional">


    Veamos ahora como al pulsar de nuevo el botón Button1, la respuesta sólo incluye la actualización del control UpdatePanel1 y la actualización de los controles Hidden de ASP.NET (pero ya no incluye, ni toca, ni manipula, ni hace nada con el control UpdatePanel2).

    clip_image008

    A la hora de trabajar con UpdateMode y el valor Conditional, también hay que tener en cuenta las siguientes consideraciones. Si por ejemplo, como es nuestro caso, tenemos un primer UpdatePanel que siempre se actualiza con cualquier petición asíncrona de la página y un segundo UpdatePanel que sólo se actualiza si es él mismo quien desencadena la petición, el siguiente código puede hacer que en el servidor tengamos un valor en el control Literal distinto del control renderizado en el cliente.

    clip_image010

    Si nos fijamos, en la segunda pulsación del botón 1, podemos ver que al actualizar tanto el Literal1 (dentro de UpdatePanel1) como el Literal2 (dentro de UpdatePanel2) se produce una situación en la que el valor de Literal2 en el cliente no está coordinado con el valor de Literal2 en el servidor. Es decir, en el servidor el valor de Literal2 es la fecha actual, mientras que en el cliente Literal2 aún mantiene su valor original (“Texto no asignado”) porque no se ha actualizado (debido al valor de la propiedad UpdateMode a Conditional). Siempre que sea oportuno podemos forzar la actualización de un control UpdatePanel desde el servidor, con independencia del valor de su propiedad UpdateMode. Esto se hace a través del método Update(). Así, por ejemplo, aunque el control UpdatePanel2 se actualiza de forma condicional, el siguiente código fuerza a que se actualice siempre y que funcione como si tuviera el valor Always en su propiedad UpdateMode.

        Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
            Literal1.Text = System.DateTime.Now.ToString
            Literal2.Text = System.DateTime.Now.ToString
            UpdatePanel2.Update()

        End Sub


    Como resumen a lo explicado se muestra una lista de las ventajas y desventajas más relevante del control UpdatePanel (en mi opinión, claro está!).




    • Ventajas



      • Actualización parcial de la página (no podría vivir sin ella, de hecho creo que es una de las características más demandadas en la llamada web 2.0).


      • Aunque el tamaño de la petición puede ser importante, siempre será menor que una llamada asíncrona convencional (PostBack).


    • Desventajas



      • Por defecto la propiedad UpdateMode tiene el valor Always que significa “actualiza todos los controles UpdatePanels de la página aunque con ellos no vaya la película siempre que se produzca una petición asíncrona).


      • Si no se tiene cuidado con la contención de los datos que envía un UpdatePanel (por dios no metas toda tu página dentro de un UpdatePanel a cholón!), el tamaño del envío y de la respuesta, lejos de ser beneficioso para la aplicación, puede ser un cuello de botella para nuestra aplicación del que después será difícil salir.

    Un saludo!

    miércoles, 16 de junio de 2010

    Copiando código VB desde Windows Live Writer

    Uno de los motivos por los que me he bajado Windows Live Writer, es porque el editor WYSIWYG de blogger no pasa de ser un editor simple sin muchas opciones de edición (tampoco esperaba el Word, pero…)

    Por ello y como el principal propósito de este blog es compartir código VB.NET y similar, me he bajado la extensión Visual Studio 2010 Pro Power Tools, porque entre una de sus muchas características está la de copiar código desde el IDE en formato HTML (genial para hacer copy/paste en el blog).

    De hecho, esta característica tiene hasta su propia entrada en algún que otro blog http://blogs.msdn.com/b/kirillosenkov/archive/2010/06/07/copy-code-in-html-format-with-visual-studio-2010.aspx

    Vamos con la prueba definitiva de copy/paste desde Visual Studio 2010 en Windows Live Writter.

    aspx

    <asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    </asp:Content>
    <asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
        <h2>
            Hola Mundo!!
        </h2>   
    </asp:Content>

    vb

    Partial Class _Default
        Inherits System.Web.UI.Page

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim a As String
            a = "Funciona el copy/paste en HTML"
        End Sub
    End Class

    Pues estoy la mar de contento, ahora ya puedo empezar mi viaje!


    Un saludo!