Tag Archive for viewstate

Disminuyendo el tamaño del ViewState, exprimiendo la compresión

La última entrega usamos Compresión GZip que viene incluída en la framework para comprimir el ViewState, porqué no experimentamos un poco y usamos algún otro método de compresión?.

Qué tal si jugamos con la compresión Zip? (usando la ICSharpZipLib) o hasta la novedosa y mucho más poderosa compresión LZMA (conocida como 7Zip). Veamos cuanto podríamos ganar con cada una de ellas. Intentemos primero con Zip:

(C# Code)

using System;
using System.IO;
using System.Text;
using System.Web.UI;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

namespace ViewStateCompressCS
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e) {}

        protected override void SavePageStateToPersistenceMedium(object state)
        {
            string vstate = string.Empty;

            using (var sw = new StringWriter()) {
                var formatter = new LosFormatter();
                formatter.Serialize(sw, state);
                vstate = sw.ToString();
            }

            var memory_stream = new MemoryStream();
            using (var zip_stream = new DeflaterOutputStream(memory_stream, new Deflater(Deflater.BEST_COMPRESSION))) {
                byte[] buffer = Encoding.UTF8.GetBytes(vstate);
                zip_stream.Write(buffer, 0, buffer.Length);
            }

            byte[] vstate_bytes = memory_stream.ToArray();
            memory_stream.Close();

            vstate = Convert.ToBase64String(vstate_bytes);

            ClientScript.RegisterHiddenField("__VSTATE", vstate);
        }

        protected override object LoadPageStateFromPersistenceMedium()
        {
            string vstate = Request.Form["__VSTATE"];
            if (string.IsNullOrEmpty(vstate))
                throw new InvalidOperationException("Something wrong goes with my ViewState!");

            var vstate_stream = new MemoryStream();
            var memory_stream = new MemoryStream(Convert.FromBase64String(vstate));
            using (var zip_stream = new InflaterInputStream(memory_stream, new Inflater())) {
                int read;
                var buffer = new byte[4096];
                while ((read = zip_stream.Read(buffer, 0, buffer.Length)) != 0) {
                    vstate_stream.Write(buffer, 0, read);
                }
            }

            byte[] vstate_bytes = vstate_stream.ToArray();
            vstate_stream.Close();
            memory_stream.Close();

            vstate = Encoding.UTF8.GetString(vstate_bytes);

            var formatter = new LosFormatter();
            return formatter.Deserialize(vstate);
        }
    }
}

(VB.net Code)

Imports System.IO
Imports System.IO.Compression
Imports ICSharpCode.SharpZipLib.Zip.Compression
Imports ICSharpCode.SharpZipLib.Zip.Compression.Streams

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
        Dim vState As String = String.Empty

        Using sw As New StringWriter()
            Dim formatter = New LosFormatter()
            formatter.Serialize(sw, vState)
            vState = sw.ToString()
        End Using

        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something wrong goes with my ViewState!")
        End If

        Dim memStream = New MemoryStream()
        Using zipStream = New DeflaterOutputStream(memStream, New Deflater(Deflater.BEST_COMPRESSION))
            Dim buffer = Encoding.UTF8.GetBytes(vState)
            zipStream.Write(buffer, 0, buffer.Length)
        End Using

        Dim vStateBytes = memStream.ToArray()
        vState = Convert.ToBase64String(vStateBytes)

        ClientScript.RegisterHiddenField("__VSTATE", vState)
    End Sub

    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
        Dim vState As String = Request.Form("__VSTATE")

        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something wrong goes with my ViewState!")
        End If

        Dim vStateStream = New MemoryStream()
        Dim memStream = New MemoryStream()
        Using zipStream = New InflaterInputStream(memStream, New Inflater())
            Dim read As Integer
            Dim buffer(4096) As Byte
            While ((read = zipStream.Read(buffer, 0, buffer.Length) <> 0))
                vStateStream.Write(buffer, 0, read)
            End While
        End Using

        Dim vStateBytes = vStateStream.ToArray()
        vStateStream.Close()
        memStream.Close()

        vState = Encoding.UTF8.GetString(vStateBytes)

        Dim formatter = New LosFormatter()
        Return formatter.Deserialize(vState)
    End Function
End Class

Obviamente como se daran cuenta el código es muy similar al código usando GZip, quizás por eso es tan bonito la ICSharpLib :D

Veamos ahora los números:

Sin Comprimir

Carácteres: 6032

Tamaño (KB): 5.89

Comprimido (Zip)

Carácteres: 2508

Tamaño: 2.45

Wow! ahora tenemos una reducción del 58.42%, y eso que este es nuestro segundo intento :D

Intentemos ahora cambiando un “poco” nuestra página, ahora usemos compresión por 7zip, usando el 7Zip C# SDK y una clase Helper hecha por Peter Bromberg, publicada en Eggheadcafe.

(C# Code)

using System;
using System.IO;
using System.Text;
using System.Web.UI;
using Rioshu.Utils.Compression.SevenZip;

namespace ViewStateCompressCS
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e) {}

        protected override void SavePageStateToPersistenceMedium(object state)
        {
            string vstate = string.Empty;

            using (var sw = new StringWriter()) {
                var formatter = new LosFormatter();
                formatter.Serialize(sw, state);
                vstate = sw.ToString();
            }

            byte[] vstate_bytes = Encoding.UTF8.GetBytes(vstate);
            vstate_bytes = SevenZipHelper.Compress(vstate_bytes);

            vstate = Convert.ToBase64String(vstate_bytes);

            ClientScript.RegisterHiddenField("__VSTATE", vstate);
        }

        protected override object LoadPageStateFromPersistenceMedium()
        {
            string vstate = Request.Form["__VSTATE"];
            if (string.IsNullOrEmpty(vstate))
                throw new InvalidOperationException("Something wrong goes with my ViewState!");

            byte[] vstate_bytes = Convert.FromBase64String(vstate);
            vstate_bytes = SevenZipHelper.Decompress(vstate_bytes);
            vstate = Encoding.UTF8.GetString(vstate_bytes);

            var formatter = new LosFormatter();
            return formatter.Deserialize(vstate);
        }
    }
}

(VB.net Code)

Imports System.IO
Imports Rioshu.Utils.Compression.SevenZip

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
        Dim vState As String = String.Empty

        Using sw As New StringWriter()
            Dim formatter = New LosFormatter()
            formatter.Serialize(sw, vState)
            vState = sw.ToString()
        End Using

        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something wrong goes with my ViewState!")
        End If

        Dim vStateBytes = Encoding.UTF8.GetBytes(vState)
        vStateBytes = SevenZipHelper.Compress(vStateBytes)

        vState = Convert.ToBase64String(vStateBytes)

        ClientScript.RegisterHiddenField("__VSTATE", vState)
    End Sub

    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
        Dim vState As String = Request.Form("__VSTATE")

        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something wrong goes with my ViewState!")
        End If

        Dim vStateBytes = Convert.FromBase64String(vState)
        vStateBytes = SevenZipHelper.Decompress(vStateBytes)

        vState = Encoding.UTF8.GetString(vStateBytes)

        Dim formatter = New LosFormatter()
        Return formatter.Deserialize(vState)
    End Function
End Class

Y ahora veamos los cambios:

Sin Comprimir

Carácteres: 6032

Tamaño (KB): 5.89

Diferencia: NA

Comprimido (Zip)

Carácteres: 2508

Tamaño (KB): 2.45

Diferencia: 58.42%

Comprimido (7Zip)

Carácteres: 2412

Tamaño (KB): 2.36

Diferencia: 60%

Wow!, como nos percatamos logramos quitarle un 60% del tamaño de nuestro ViewState original, eso involucra que si nuestro ViewState es de 900kB (algo que hace varios meses resultó positivo en una aplicación a mi cargo), este se tornará en 360kB, un “poco más” manejable.

Escoger entre 7Zip y Zip es cuestión de gustos, personalmente prefiero Zip por el soporte de la maravillosa Library de Zip que viene en ICSharpZipLib. Pero bueno, es cuestion de gustos!

Pero esto no queda aquí, veremos que otras opciones tenemos para manipular nuestro ViewState, aún quedan varias!

El ejemplo podemos bajarlo de aquí.

Disminuyendo el tamaño del ViewState, Comprimiendo el ViewState

En la última entrega aprendimos a como manipular y controlar el lugar donde se va a guardar el ViewState serializado en la página resultante. Como ejemplo movimos el ViewState del campo oculto __VIEWSTATE a otro campo oculto llamado __VSTATE. Es hora de que hagamos un par más de trucos.

Como el ViewState serializado resultante del LosFormatter es realmente una cadena de caracteres, porqué no utilizamos algún algoritmo de compresión para comprimir su tamaño? Yep, escucharon bien, comprimamos el ViewState :)

Comencemos usando las facilidades de compresión que nos regala la .Net Framework en su namespace System.IO.Compression.

using System;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Web.UI;

namespace ViewStateCompressCS
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e) {}

        protected override void SavePageStateToPersistenceMedium(object state)
        {
            string vstate = string.Empty;

            using (var sw = new StringWriter()) {
                var formatter = new LosFormatter();
                formatter.Serialize(sw, state);
                vstate = sw.ToString();
            }

            if (string.IsNullOrEmpty(vstate))
                throw new InvalidOperationException("Something wrong goes with my ViewState!");

            var memory_stream = new MemoryStream();
            using (var gzip_stream = new GZipStream(memory_stream, CompressionMode.Compress)) {
                byte[] buffer = Encoding.Default.GetBytes(vstate);
                gzip_stream.Write(buffer, 0, buffer.Length);
            }

            byte[] vstate_bytes = memory_stream.ToArray();
            vstate = Convert.ToBase64String(vstate_bytes);

            ClientScript.RegisterHiddenField("__VSTATE", vstate);
        }

        protected override object LoadPageStateFromPersistenceMedium()
        {
            string vstate = Request.Form["__VSTATE"];
            if (string.IsNullOrEmpty(vstate))
                throw new InvalidOperationException("Something wrong goes with my ViewState!");

            var vstate_stream = new MemoryStream();
            var memory_stream = new MemoryStream(Convert.FromBase64String(vstate));
            using (var gzip_stream = new GZipStream(memory_stream, CompressionMode.Decompress)) {
                int read;
                var buffer = new byte[4096];
                while ((read = gzip_stream.Read(buffer, 0, buffer.Length)) != 0) {
                    vstate_stream.Write(buffer, 0, read);
                }
            }

            byte[] vstate_bytes = vstate_stream.ToArray();
            vstate_stream.Close();
            memory_stream.Close();

            vstate = Encoding.Default.GetString(vstate_bytes);

            var formatter = new LosFormatter();
            return formatter.Deserialize(vstate);
        }
    }
}

(VB.net Code)

Imports System.IO
Imports System.IO.Compression

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
        Dim vState As String = String.Empty

        Using sw As New StringWriter()
            Dim formatter = New LosFormatter()
            formatter.Serialize(sw, vState)
            vState = sw.ToString()
        End Using

        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something wrong goes with my ViewState!")
        End If

        Dim memStream = New MemoryStream()
        Using gzipStream = New GZipStream(memStream, CompressionMode.Compress)
            Dim buffer = Encoding.UTF8.GetBytes(vState)
            gzipStream.Write(buffer, 0, buffer.Length)
        End Using

        Dim vStateBytes = memStream.ToArray()
        vState = Convert.ToBase64String(vStateBytes)

        ClientScript.RegisterHiddenField("__VSTATE", vState)
    End Sub

    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
        Dim vState As String = Request.Form("__VSTATE")

        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something wrong goes with my ViewState!")
        End If

        Dim vStateStream = New MemoryStream()
        Dim memStream = New MemoryStream()
        Using GZipStream = New GZipStream(memStream, CompressionMode.Decompress)
            Dim read As Integer
            Dim buffer(4096) As Byte
            While ((read = GZipStream.Read(buffer, 0, buffer.Length) <> 0))
                vStateStream.Write(buffer, 0, read)
            End While
        End Using

        Dim vStateBytes = vStateStream.ToArray()
        vStateStream.Close()
        memStream.Close()

        vState = Encoding.UTF8.GetString(vStateBytes)

        Dim formatter = New LosFormatter()
        Return formatter.Deserialize(vState)
    End Function
End Class

(Creo que no hace falta decirles que no soy un programador de VB.net, así que errores en mi código de VB.net es posible que encuentren :D )

Revisemos ahora los tamaños

 

Sin comprimir

Carácteres: 6032

Tamaño (KB): 5.89

 

Comprimido

Carácteres: 3152

Tamaño (KB): 3.08

 

A simple vista representa una reducción del 47.75% de nuestro ViewState original, no esta mal para ser nuestro primer intento verdad?

Como siempre los archivos ejemplos pueden bajarlo de aquí.

Disminuyendo el tamaño del ViewState, “emulando” el ViewState

Bueno, ahora pasamos a dónde realmente comienza la acción. La primera técnica que utilizamos fue simplemente “Quitar” el ViewState. Ahora digamos que por cosas de la vida necesitamos SIEMPRE mantener el ViewState en una página. Hay casos donde obviamente no podemos deshacernos de ello, como por ejemplo, controles muy avanzados de Tree y Grids.

Ya que comprendimos en la entrega anterior que el ViewState se guarda en la página por “algún medio” luego de este haber sido serializado por un serializador (que por defecto es un LosFormatter).

Ok, intentemos lo primero, ya que no podemos “deshacernos” del ViewState, y que podemos cambiar dónde se guarda, intentemos pensar en las siguientes opciones:

  • Sigamos guardando el ViewState en la página
  • Guardemos el ViewState en el Server, así nos olvidamos de él!!!

Bien, antes que algún lector “pilas” me saque a relucir el último punto creo que debemos comenzar por el primero, así nos entendemos bien que sucede debajo del capó de la página! (descuiden, luego entraremos a la parte del ServerSide State y con todas sus implicaciones :D )

Bien, el primero que entra al campo de juego es el “formatter”. Nuestro individuo de estudio es el poco conocidoLosFormatter, un familiar del más conocido BinaryFormatter o SOAP Formatter. “LOS” viene de “Limited Object Serialization” y esta diseñado para serializar efectivamente ciertos tipos de datos a su representación en Base64.

El LosFormatter no crea el campo VIEWSTATE, sino que es a su vez usado por otra clase (la cuál veremos en otro post) para guardar la información en el campo oculto __VIEWSTATE.

En la cascada de ejecución de la página en ASP.NET, se llaman dos métodos específicos:

  • SavePageStateToPersistenceMedium se encarga de guardar el objeto que contiene el “estado” de la página completa a un medio de persistencia (que en el caso por defecto es un Hidden Field con el nombre de __VIEWSTATE).
  • LoadPageStateFromPersistenceMedium se encarga de obtener el objeto de estado de donde lo guardamos anteriormente y retornarlo a la página.

No hace falta explicar que el primero es usado en el momento de enviar la página del server al cliente y el segundo cuando el cliente envía la respuesta al server.

Comencemos usando estos dos métodos para guardar el ViewState no en un campo llamado __VIEWSTATE sino en un campo llamado __VSTATE

NOTA: El código ejemplo pueden bajarlo de aquí. Necesita SQL Server 2008 Express con la base de datosAdventureWorksLT 2008.

Como veran inicialmente el codebehind es simple:

(C# code)

using System;
using System.Web.UI;

namespace WebApplication1
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e) {}
    }
}

(VB.net Code)

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

End Class

Si revisamos bien, nuestro ViewState mide aproximadamente 5.92KB (6060 caracteres)

Bien, ahora hagamos un “simple” cambio dando un par de overrides:

(C# code)

using System;
using System.IO;
using System.Web.UI;

namespace SimpleViewStateCS
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e) {}

        protected override void SavePageStateToPersistenceMedium(object state)
        {
            string vstate = string.Empty;

            using (var sw = new StringWriter()) {
                var formatter = new LosFormatter();
                formatter.Serialize(sw, state);
                vstate = sw.ToString();
            }

            ClientScript.RegisterHiddenField("__VSTATE", vstate);
        }

        protected override object LoadPageStateFromPersistenceMedium()
        {
            string vstate = Request.Form["__VSTATE"];
            if (string.IsNullOrEmpty(vstate))
                throw new InvalidOperationException("Something wrong goes with my ViewState!");

            var formatter = new LosFormatter();
            return formatter.Deserialize(vstate);
        }
    }
}

(VB.Net code)

Imports System.IO

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
        Dim vState As String = String.Empty

        Dim sw = New StringWriter()
        Dim formatter = New LosFormatter()
        formatter.Serialize(sw, state)
        vState = sw.ToString

        ClientScript.RegisterHiddenField("__VSTATE", vState)

    End Sub

    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
        Dim vState As String = Request.Form("__VSTATE")
        If String.IsNullOrEmpty(vState) Then
            Throw New InvalidOperationException("Something goes wrong with __VSTATE")
        End If

        Dim formatter = New LosFormatter()
        Return formatter.Deserialize(vState)
    End Function

End Class

Ahora nuestro ViewState no existe, pero tenemos un campo __VSTATE con “nuestro” ViewState con tamaño de 5.89KB (6032 caracteres).

Este último no es una “gran” ganancia, pero creo que comprendimos una lección importantísima, aprendimos “como” manipular nuestro campo de storage de ViewState.

Bueno, hasta la siguiente entrega, dónde podremos ver como esta información nos puede ser mucho más que útil!

Manejo de estado en ASP.NET

Escribiendo (o por lo menos tratando) de escribir mi serie acerca del ViewState y sus formas de hacerlo más pequeño y manejable, me topo con el problema siguiente: ¿y si el lector no conoce las formas de estado de las aplicaciones de ASP.net? ¿Qué puedo guardar en el “estado”? pues casi cualquier cosa, cualquier data, cualquier objeto (que sea serializable), cualquier información que quiera. Es como una bolsa de data temporal que podemos usar.

Es importante notar que todas estas propiedades se comportan como “property bags” o diccionarios a los cuales les cabe “todo”.

  • Application, la información guardada en este lugar es accedida por todos los usuarios dentro de la misma aplicación y es mantenida en memoria del application pool.
  • QueryString, es la infomación pasada entre páginas usando la cadena de request en el URL, obviamente no podemos contener mucha información y no es “muy segura” que digamos.
  • ViewState, si, nuestro amigo el ViewState también puede usarse para almacenar data arbitraria a nuestro antojo. “Por default” es guardada en un campo “hidden” bajo el nombre __VIEWSTATE en la página generada.
  • Session, es manejado por sesión de usuario conectada a la página, es sumamente “pasajera” y demora lo que demora la sesión de un usuario (por defecto 20min). No se necesita ser un usuario “registrado” o existente para tener un objeto sesión, los usuarios anónimos también tienen una sesión. Las sesiones existen por request. “Por default” las sesiones son guardadas en memoria del proceso o Application Pool, o sea, que usan la memoria del servidor.
  • Cookies, usan espacio en el browser que puede ser manipulado por el usuario o cliente, tiene un máximo de storage de 4K, se les puede asignar un tiempo de vida (o el usuario puede borrarlas a su antojo). Se envian e intercambian con cada request.

Bien, les dije que sería una introducción corta ;)

Los espero en el siguiente post!

Disminuyendo el tamaño del ViewState, No ViewState

La primera técnica tibetana de adelgazamiento del ViewState en ASP.Net: Eliminar el ViewState.

NOTA: Una forma de medir el ViewState usando Firefox es mediante el ViewSate Size Extension, otros utilizan la WebDeveloper Toolbar o Fiddler2 en Internet Explorer. Para efectos de esta serie de post utilizaré la extensión de Firefox.

Usemos una página simple y sencilla en ASP.Net como ejemplo inicial:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
    Inherits="WebApplication1._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"></head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>
            Saludo: <asp:TextBox ID="text_saludo" runat="server" />
            <asp:Button ID="button_saludar" runat="server" Text="Saludar"
                OnClick="buttonSaludar_onClick" />
        </p>
        <p>
            <asp:Label ID="label_saludo" runat="server" Text="hola mundo" />
        </p>
        <p>
            <asp:Label ID="label_echo" runat="server" />
        </p>
    </div>
    </form>
</body>
</html>

Y este es su codebehind respectivo:

using System;
using System.Web.UI;

namespace WebApplication1
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            label_echo.Text = label_saludo.Text;
        }

        protected void buttonSaludar_onClick(object sender, EventArgs e)
        {
            label_saludo.Text = string.Format("Hola {0}", text_saludo.Text);
        }
    }
}

Simple y sencillo, ahora revisemos el funcionamiento:

  • La primera vez que carga ambas labels dicen “hola mundo”
  • Ingresamos “motto” (el nombre de uno de mis gatos) en la textbox y presionamos “Saludar”, esto crea el postback e inicia la cadena de eventos, cambiando la “label_saludo” a “hola motto”.
  • Se muestra la label “label_echo” como “hola mundo” (obviamente, se carga en el load y esto muestra el valor por defecto) y “label_saludo” tiene la frase “hola motto”
  • Se ingresa “cocco” (el nombre de otro de mis gatos) en la textbox y volvemos a crear el postback al presionar el boton “Saludar”
  • Se vuelve a desplegar la página con “label_saludo” como “hola cocco” y “label_echo” con “hola motto”.

Quiero que ahora el lector se detenga y piense en el papel crucial del ViewState en la cadena anterior de eventos, ¿cómo sabe la página que mensaje mostrar?… Si leyeron cuidadosamente los artículos anteriores en los que publiqué el link, responderan correctamente: El ViewState guarda el “cambio” en la propiedad Text del label. El “hola mundo” se inicializa a partir del markup, y el “hola cocco” se inicializa a partir de la data guardada en el ViewState.

Si no esta aún claro les recomiendo volver a los links de mi artículo anterior y hecharles una buena leída.

Bien, revisemos en Firefox:

  • En el inicio reporta un ViewState de 0.09kB
  • Al ingresar “cocco” el ViewState crece a 0.13kB

Tal vez los números no nos asusten (estamos hablando de menos de 1K), pero consideren que la “label” es el control más sencillo y pequeño de la .Net Framework, imagínense una gran cantidad de controles en la página!

Bien, como el título lo predice, la forma más sencilla de eliminar el tamaño del ViewState es simplemente: Eliminar el ViewState. Esto se puede lograr de dos maneras: a nivel de la página o a nivel del control. Intentemos a nivel de página:

Cambiemos la declaración de la página para que lea de la siguiente manera:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
    Inherits="WebApplication1._Default" EnableViewState="false" %>

Veamos nuestra página ahora:

  • ViewState inicial: 0.05kB
  • ViewState luego de cada evento: 0.05kB

Alguien precavido dirá: “Hey no que no hay ViewState, 0.05kB no significa 0kB!!!”, y tiene razón. Eso me lleva a la siguiente aclaración: “En ASP.net 2.0 existen dos tipos de ViewState”.

  • El “data” ViewState, mantiene la data asignada al control o a la página en cuestión, es una property bag pública de cada control y puede eliminarse al desabilitar el ViewState
  • El “control state” ViewState, mantiene el “estado” o la data necesaria para saber como renderizar el control en markup (por ejemplo, que checkbox esta seleccionada). Este “ViewState” NO puede ser eliminado.
  • Pueden conocer un poco más de ambos aquí.

Si probamos la aplicación nos toparemos con una desagradable sorpresa, la funcionalidad anterior ha desparecido. Esto es porque como mencionamos antes dependemos del ViewState de la label “label_saludo”, bien, resolvamoslo de forma sencilla, habilitemos el ViewState de la página y luego desabilitemos todos los ViewState excepto el ViewState de la label “label_saludo”, el código de la página pasa a ser algo así:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
    Inherits="WebApplication1._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server"></head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>
            Saludo: <asp:TextBox ID="text_saludo" runat="server" EnableViewState="false" />
            <asp:Button ID="button_saludar" runat="server" Text="Saludar"
                OnClick="buttonSaludar_onClick" EnableViewState="false" />
        </p>
        <p>
            <asp:Label ID="label_saludo" runat="server" Text="hola mundo" />
        </p>
        <p>
            <asp:Label ID="label_echo" runat="server" EnableViewState="false" />
        </p>
    </div>
    </form>
</body>
</html>

Ahora todo funciona como es de esperar, revisemos los tamaños del ViewState:

  • Inicial: 0.05kB
  • Post evento: 0.09kB

Lastimosamente en ASP.net 2.0 (y por lo tanto la 3.5) no se puede eliminar el ViewState de la página y luego selectivamente activar el ViewState de cada control, esto también sucede con los controles que son contenedores (intentenlo con la “form1” por ejemplo). En la próxima versión de ASP.net (la 4.0 que vendrá con Visual Studio 2010) esto podrá hacerse de manera declarativa, que bien verdad?

Bien, los dejo hasta la próxima, donde veremos la forma de realizar el mismo ejemplo sin necesidad de usar el ViewState en ningún momento, además de un ejemplo más complejo utilizando una GridView. Hasta entonces.

PD: Como siempre, acepto concejos o sugerencias.