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 :D.

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,

Published 2/5/2008 21:40 por Sergio Tarrillo
Archivado en:
Comparte este post:
http://geeks.ms/blogs/sergiotarrillo/archive/2008/05/02/84711.aspx

Comentarios

# re: decodificando el ViewState... para verle hasta las venas

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

Sunday, May 04, 2008 7:34 PM por David Daniel Arroyo Zari "Ddaz"

# re: decodificando el ViewState... para verle hasta las venas

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:

<configuration>

  <system.web>

     <pages

      enableViewStateMac="true|false"

CopyPaste de la ayuda:

-Especifica si ASP.NET debe ejecutar un código de autenticación de mensajes (MAC) en el estado de vista de la página cuando ésta se devuelve desde el cliente. Un MAC de estado de vista es una versión cifrada de la variable oculta que el estado de vista de una página almacena cuando se envía al explorador. Si el valor de este atributo en true, se comprueba el estado de vista cifrado para asegurarse de que no se ha manipulado en el cliente.-

Por defecto FALSE, así que cuidado con esto.

Creo recordar (avisadme si me equivoco, hace tiempo que no estoy con ASP.NET) que hasta salta una excepcion especifica del viewstate corrupto o algo asi que puede ser capturada en el Global.asax (y quiza en mas sitios) y soltarle un mensaje al browser cliente diciendo que se ha corrompido la info entre cliente y servidor.

Monday, May 05, 2008 9:14 AM por El hombre sonriente.

# re: decodificando el ViewState... para verle hasta las venas

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,

Monday, May 05, 2008 4:06 PM por Sergio Tarrillo

# re: decodificando el ViewState... para verle hasta las venas

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ó.

Tuesday, May 06, 2008 9:09 AM por El hombre sonriente

# re: decodificando el ViewState... para verle hasta las venas

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: "evtde.argonautanet.com/.../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

Tuesday, January 19, 2010 3:56 PM por Fernando Reich

# re: decodificando el ViewState... para verle hasta las venas

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.

Friday, December 31, 2010 7:09 PM por buy paper

# re: decodificando el ViewState... para verle hasta las venas

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.

Thursday, January 06, 2011 5:18 PM por research paper shop

# re: decodificando el ViewState... para verle hasta las venas

Everyone in the world will read through your well done idea to make the high quality term papers or just american history essay.

Saturday, January 08, 2011 11:23 AM por tv essay paper

# re: decodificando el ViewState... para verle hasta las venas

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

Friday, January 14, 2011 1:29 PM por dissertation service

# re: decodificando el ViewState... para verle hasta las venas

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.  

Saturday, March 19, 2011 11:02 PM por essays online

# re: decodificando el ViewState... para verle hasta las venas

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.

Sunday, March 20, 2011 11:58 PM por dissertation writing service

# re: decodificando el ViewState... para verle hasta las venas

People have to treat thesis proposal related to this good post in a right way, because they would need this a dissertation in future.

Monday, March 21, 2011 12:00 AM por thesis writing

# re: decodificando el ViewState... para verle hasta las venas

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!

Wednesday, March 23, 2011 5:06 AM por articles submissions