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:

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:

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:

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:

¿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:

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:

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:

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,
Crossposting desde ...