decodificando el ViewState… para verle hasta las venas

El tema de ViewState es tema muy triado, pero no he tenido la oportunidad de comentarlo y entenderlo bien así que voy a explicar algunos puntos relacionados al tema.

Para tratar de entender a detalle al ViewState pueden leer el siguiente artículo: TRULY Understanding ViewState, tal fue el ranking del post que un usuario hizo un pdf con todos los comentarios, clasificados y ordenados al estilo FAQ: TRULY Understanding ViewState, the comment index. Aunque supongo que ya lo leyeron, los que revisaron el LDLS-2008mar10.

Para entender el ViewState, veamos primero que pasaba antes de la existencia del mismo, y cual era el problema que en el ASP Clásico, y en general en el mundo Web con las demás tecnologías de servidor, debido a que las páginas web son stateless.

Cuando agregamos un nuevo WebForm a nuestro proyecto Web, agrega el siguiente código html:

   1: <body>
   2:     <form id="form1" runat="server">
   3:     <div>
   4:     
   5:     </div>
   6:     </form>
   7: </body>

Ahora vamos a cambiar el código de form, por el siguiente, para revisar el modelo de trabajo de un página con el clásico ASP:

   1: <form id="form1" method="post" action="WebForm01.aspx" >
   2:    <div>
   3:        <input id="txtNombre" name="txtNombre" type="text" />
   4:        <br />
   5:        <input id="btnEnviar" type="submit" value="enviar" />
   6:        <br />
   7:        <br />
   8:        <span><strong>Nombre: </strong>
   9:           < %= Request.Form["txtNombre"]%></span>
  10:    </div>
  11: </form>

En el caso del action, depende del nombre sobre el formulario que estén trabajando.

SI hacemos “View in Browser” a la página, ingresamos un nombre y hacemos un submit:

http://sergiot2.com/blogimages/2008/05May/02_name.jpg

Noten que el contenido del control txtNombre, se ha perdido. Este era el problema, la perdida de valores entre postbacks al servidor, y se usaban distintas técnicas para guardar el valor de los controles, como por ejemplo el uso de controles  Hidden. Veamos el código fuente de lo que se muestra en el navegador:

   1: <form id="form1" method="post" action="WebForm01.aspx" >
   2:    <div>
   3:        <input id="txtNombre" name="txtNombre" type="text" />
   4:        <br />
   5:        <input id="btnEnviar" type="submit" value="enviar" />
   6:  
   7:        <br />
   8:        <br />
   9:        <span><strong>Nombre: </strong>Ricardo</span>
  10:    </div>
  11: </form>

Recuerden que siempre al cliente llega todo como html, y nada de la tecnología de servidor usada. Para refrescar un poco:

http://sergiot2.com/blogimages/2008/05May/03_web.jpg

Sólo como recordatorio: El cliente ingresa a su navegador y pide una url, esta se envía por el método get al servidor, el servidor recibe el request, y lo procesa de acuerdo al tipo de recurso solicitado, en el caso de asp.net las compila, y genera el html para ser enviado al cliente que hizo el request, cuando llega el html al browser, este lo interpreta (si la diseño bien y respeto los estándares), y lo muestra finalmente al usuario. Esto es en el primer pedido, cuando el usuario no ha interactuado con el formulario.

En nuestro ejemplo si el usuario ingresa un nombre y hace un submit, el paso 1 se modifica y en el request también viaja el formulario con el contenido del formulario enviado, para que el servidor lo procese y vuelva devolver el html requerido.

Como pueden ver el problema, es que cada página muere después de su llegada al servidor, y este envía una nueva página, y ahí es donde había que hacer trabajo adicional para “mantener” variables o valores. En nuestro caso para “conservar” el valor podíamos hacer lo siguiente:

   1: <form id="form1" method="post" action="WebForm01.aspx" >
   2:    <div>
   3:        <input id="txtNombre" name="txtNombre" type="text" 
   4:               value="<%= Request.Form["txtNombre"]%>" />
   5:        <br />
   6:        <input id="btnEnviar" type="submit" value="enviar" />
   7:        <br />
   8:        <br />
   9:        <span><strong>Nombre: </strong>< %= Request.Form["txtNombre"]%></span>
  10:    </div>
  11: </form>

Con esto “mantenemos” el valor ingresado. Este es un caso simple, de como se pierde los valores de los controles entre postbacks, imaginen el trabajo necesario para mantener combos, listas, o grillas, u otra información, si que te hacía aprender html a la fuerza.

Ahora veamos a ASP.NET, y el famoso ViewState:

Primero hagamos una página igual a la anterior pero al estilo ASP.NET:

   1: <form id="form1" runat="server">
   2:     <div>
   3:         <asp:TextBox ID="TextBox1" runat="server" />
   4:         <br />
   5:         <br />
   6:         <asp:Button ID="Button1" runat="server" 
   7:              OnClick="Button1_Click" Text="Button" />
   8:         <br />
   9:         <br />
  10:         <asp:Label ID="Label1" runat="server" Text="Label" />
  11:     </div>
  12: </form>

¿Qué pueden notar a simple vista?, el casi camuflado runat=”server”. Esto hará que el compilador de asp.net les de un tratamiento especial, y si hacemos “View in Browser”, vamos a ver cual es ese tratamiento especial:

   1: <form name="form1" method="post" action="WebForm02.aspx" id="form1">
   2: <div>
   3:     <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
   4:           value="/wEPDwUKMTU5MTA2ODYwOWRkoCvvBWgUOH7PD446qvEOF6GTCq0=" />
   5: </div>
   6: <div>
   7:     <input name="TextBox1" type="text" id="Text1" />
   8:     <br />
   9:     <br />
  10:     <input type="submit" name="Button1" 
  11:              value="Button" id="Submit1" />
  12:     <br />
  13:     <br />
  14:     <span id="Span1">Label</span>
  15: </div>
  16: <div>
  17:     <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
  18:          value="/wEWAwK96cyQBQLs0bLrBgKM54rGBnfFy5qsGxoLdjEJRH5u2jb20INJ" />
  19: </div>
  20: </form>

Como pueden ver el html generado por ASP.NET tiene en general las mismas estructuras que el html que genera el clásico ASP. El formulario usará el método post para enviar su contenido al servidor, tiene un input tipo text para el contenido, y un input tipo submit para enviar el formulario. ¿Y dónde esta la diferencia?, ¿Qué ha hecho el runat=”server”?

Pues a parte de agregar los atributos que le faltaban al elemento “form”, ha agregado dos elementos input adicionales tipo hidden, y que el usuario no ve en el navegador. El primero de ellos es usado para el ViewState, y el segundo es usado para la validación de los eventos de los controles.

Pero centrémonos en el ViewState, esa “basurilla” que aparece en el value del input, es debido a que su valor esta codificado en Base64, y si queremos ver el contenido de este podemos usar la excelente herramienta de Fritz Onion: ViewState Encoding in ASP.NET 2.0.

Si descargamos esta herramienta, y copiamos el value del input, el resultado sería similar al siguiente:

http://sergiot2.com/blogimages/2008/05May/02_view01.jpg

El número que aparece, es un código identificador de la página que es agregado en la compilación, y no he revisado, con reflector, que patrón sigue para generar este código.

¿Qué pasa si ingreso un nombre al input y hago un submit?. El código html devuelto por el servidor es el siguiente:

   1: <form name="form1" method="post" action="WebForm02.aspx" id="form1">
   2: <div>
   3:     <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
   4:       value="/wEPDwUKMTU5MTA2ODYwOQ9kFgICAw9kFgICBQ8PFgIeBFRleHQFFWhvbGEgKGFnYWluKTogUmljYXJkb2RkZBYEcyX+SIJ6nk9MwXtX7kSpUKKN" />
   5: </div>
   6: <div>
   7:     <input name="TextBox1" type="text" value="Ricardo" id="Text1" />
   8:     <br />
   9:     <br />
  10:     <input type="submit" name="Button1" value="Button" id="Submit1" />
  11:     <br />
  12:     <br />
  13:     <span id="Span1">hola (again): Ricardo</span>
  14: </div>
  15: <div>
  16:     <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" 
  17:            value="/wEWAwLi/5/ADgLs0bLrBgKM54rGBlPmS3Xh+glhVkA6doo4UW+6VIvp" />
  18: </div>
  19: </form>

Como pueden ver el ViewState ha crecido, y nosotros, el que hizo el trabajito fue ASP.NET, no hicimos ningún trabajo adicional para “mantener” el estado del valor ingresado. Si nuevamente usamos la herramienta ViewState Decoder, vamos a ver como ASP.NET usa el View State para guardar el valor del contenido del elemento html span, que es lo que genera un control Label de ASP.NET:

http://sergiot2.com/blogimages/2008/05May/02_view02.jpg

¿Dónde vemos un caso más práctico?. Cuando llenamos un DropDownList, recuerdan que siempre nos dicen que debemos llenarlo en Load, con un condicional para llenarlo sólo en el primer request de la página. ¿Por qué ya no debemos llenarlo en los siguientes postbacks?, por que el ViewState se esta encargando de guardar los valores entre postbacks al servidor.

Ahora si agregamos un control DropDownList a la página, y en el evento Load de la página agregamos el siguiente código:

   1: protected void Page_Load(object sender, EventArgs e)
   2: {
   3:    if (!Page.IsPostBack)
   4:    {
   5:       DropDownList1.Items.Add("Trujillo");
   6:       DropDownList1.Items.Add("Lima");
   7:       DropDownList1.Items.Add("Cusco");
   8:    }
   9: }

Y sin hacer submit, vemos el ViewState actual de la página generada:

http://sergiot2.com/blogimages/2008/05May/02_view03.jpg

Podrán notar que sólo esta el contenido del DropDownList, si hacemos submit, se recargará al ViewState el valor del Label.

Podría resumir al ViewState como una técnica de ASP.NET, que hace uso de elementos html, para almacenar el valor de los controles de una página. Y esto también pasa con una grilla, pero atención que muchas veces el ViewState puede crecer demasiado:

http://sergiot2.com/blogimages/2008/05May/02_view04.jpg

Que a lo larga, lo único que hará será aumentar el tráfico del servidor, ya que este contenido estará viajando del cliente al servidor, y del servidor al cliente, innecesariamente, si es que todo el contenido de un control siempre es vuelto a generar. Si tengo un GridView que en cada postback es para cambiar su contenido, para que usar el ViewState para este control ¿?, pues eso, sólo usar el ViewState cuando sea necesario, por que a la larga no afectemos la escalabilidad y performance de la aplicación, hay un artículo interesante relacionado a la escalabilidad de aplicaciones web ASP.NET, en la edición MSDN Magazine 2008 Abril: Performance – Scaling Strategies for ASP.NET Applications, y aunque hay que leerlo varias veces para entenderlo, la esperanza es lo último que se pierde 😀.

Otra de las formas de rastrear que ViewState esta dando lata, es agregar el atributo Trace=”true”, a la directiva de la página asp.net, y al hacer “View in Browser”, recibiremos una lista con el tamaño de bytes que ocupa el ViewState de los controles que lo estén usando:

http://sergiot2.com/blogimages/2008/05May/02_view05.jpg

Por cierto el Trace, también brinda otra información adicional.

Espero que el tema del ViewState, haya quedado un poco más claro, el por que usarlo, el cuando usarlo, y ver que es lo que realmente hace es usar técnicas que pudieron ser usadas con el clásico ASP, pero ASP.NET se encarga de hacer ese trabajo por nosotros.

A medida que van saliendo las nuevas versiones de ASP.NET, se podrán ver que cada vez el trabajo del developer es más tonto, arrastrar y soltar, y la idea es que ocupe su tiempo en pensar bien las soluciones, y que no las este cambiando cada semana, pero siempre es bueno saber que hay detrás de ese trabajo para poder personalizarlo, y como pueden ver, todas son técnicas que ya se usaban antes. Es fácil arrastrar controles y saber ASP.NET, pero cuando lleguen formularios complejos, si sólo sabemos controles asp.net, y no sabemos nada de html/css/javascript, el formulario se puede convertir en un monstruo.

Nuevamente, leer el siguiente artículo: TRULY Understanding ViewState.

Otros artículos relacionados:

Saludos,

13 comentarios en “decodificando el ViewState… para verle hasta las venas”

  1. Hola:

    no se si felicitarlos por esa herramienta.. o preocuparme de nuevo por los problemas de seguridad…. ( logicamente hablando de las antipracticas de programacion)… ya se sabia de antes que estaba codificado en Base64.. y usando un decodificador medio se podia entender lo que decia .. pero ahora… el numero de sites “vulnerables”… podria aumentar… logicamente si esa tool cae en manos equivocadas… jeje

    salu2

    Ddaz

  2. No es tan facil cambiar el viewstate y mandarlo al server a que se lo trague todo como si fuese Tracy Lords. Existe un chequeo de la integridad del viewstate en el servidor que incluye un código de autenticación de mensajes para determinar si se ha manipulado.

    Archivo web.config:


  3. Así es hay una validación del valor del ViewState, con enableViewStateMac. Eso lo iba a comentar en otro post :D.

    Lo del Global.asax, no lo sabía, gracias por el dato.

    Saludos,

  4. Wops! Sabia yo que no me acordaba bien…
    No se captura la excepcion el en Global.asax como decia mas arriba. Pero se puede usar el procedimiento Application_Error o el evento Error que se hereda de HttpApplication de este mismo archivo que saltan cuando se produce una excepcion NO controlada (esto es, fuera de algun bloque Try/Catch en el CodeBehind). En la propiedad Server.GetLastError se encuentra la excepcion que saltó.

  5. Buenos días

    La consulta que voy a realizar no estoy seguro si tiene algo que ver con el tema del foro pero si me pueden ayudar, les estaré muy agradecido.

    ¿Como se puede pasar parámetros de query en la URL de una Web aspx?

    Intentaré explicarme, yo quiero agregar a la url: “http://evtde.argonautanet.com/Varios/ComprobacionTelefono.aspx” algún parámetro que automáticamente agregue el dato que solicita el formulario en el textbox y que el botón Aceptar se active.

    Es decir, no quiero tener que ingresar el dato que solicita la página y hacer click en el botón Aceptar.

    Al hacer click en dicho botón, la página no se redirecciona a ninguna otra página por lo que no puedo invocar otro link para realizar el query en cuestión.

    Con la respuesta que ustedes me den pienso capturar el contenido de los query con Excel (algo que si se hacer).

    Aunque si con Excel se pudiera realizar un query de un valor específico (o personalizado) y que el botón aceptar se haga click solo, también me interesa, así como cualquier otra solución alternativa (como un script).

    Saludos y gracias

  6. Different people at shool are willing to get the doctoral degree and they order the custom essays related to this good topic from the custom writing service, but sometimes they search for the articles just about order essays.

  7. There are lots of things you do consequently. Nevertheless, some of them can be nice and others will be hard. In fact, you do not like to do academic papers writing, but, you will simply purchase do custom research paper service.

  8. Some successful scholars can read your data connected with this post and just order the dissertation cover from the thesis writing service.

  9. I do not understand a proper way to show my emotions after the utilizing the aid of custom writing service. I should just tell that my history essays are great now. Term paper writers are very kind.

  10. Your really hot data referring to this post would be open for students, just because they want thesis and good dissertation writing or just doctoral thesis.

  11. I guessed that I could do links building by my own. Nonetheless, I didn’t got any knowledge how to do that! So, I didn’t have got any choice and I strived to utilize the article submissions company and my deals has got better just after it!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *