domingo, 21 de febrero de 2010

Asignación implícita de tipos en Visual C#

En ocasiones nos podemos ver enfrentados a la problemática de no saber de qué tipo debemos declarar una variable, parece raro, pero no lo es y te diré porque. Primero revisemos el siguiente código:

protected void Button1_Click(object sender, EventArgs e)
        {
            Int32 departmentID = Convert.ToInt32(departmentList.SelectedValue);

            var courseInfo = from c in schoolContext.Course
                             where c.Department.DepartmentID == departmentID
                             select new
                             {
                                 CourseID = c.CourseID,
                                 CourseTitle = c.Title,
                                 CourseCredits = c.Credits
                             };
            
            foreach (var course in courseInfo)
            {
                Response.Write("<br>ID: " + course.CourseID + "<br>Title:" + course.CourseTitle + "<br>Credits:" + course.CourseCredits);
            }
        }

El resultado de courseInfo es una colección de tipos anónimos y solamente el compilador puede tener acceso al nombre de ese tipo y es aquí entonces en donde usaremos var y lógicamente la variable course en foreach también debe tener tipo implícito.

Ahora si revisamos este segundo ejemplo, inmediatamente podemos deducir que el tipo de la variable courseInfo para su resultado es IEnumerable, pero si usamos var también estará bien. La variable course en foreach también la definimos como string.

protected void Button2_Click(object sender, EventArgs e)
        {
            string[] Courses = { "Ingenieria", "Ingles", "Economia", "Matematicas" };
            IEnumerable<string> courseInfo = from name in Courses
                              where name[0] == 'I'
                              select name;

            foreach (string course in courseInfo)
            {
                Response.Write("<br>Course :" + course);
            }
        }

Entonces en resumen, a las variables locales se les puede asignar un "tipo" deducido var en lugar de un tipo explícito. La palabra clave var indica al compilador que deduzca el tipo de la variable a partir de la expresión que se encuentra en el lado derecho de la instrucción de inicialización. El tipo deducido puede ser un tipo integrado, un tipo anónimo, un tipo definido por el usuario o un tipo definido en la biblioteca de clases de .NET Framework.

Saludos, Toby

viernes, 19 de febrero de 2010

Como usar ViewState en ASP.NET con C#

El ViewState nos permite almacenar información de estado (la información se serializa en XML y luego se codifican en Base64) directamente en las páginas Web ASP.NET entre devoluciones de datos o Post Back. El PostBack es un reenvío de los datos del formulario de vuelta al servidor, el cual puede ser provocado por la acción de un evento click de un botón o el cambio de selección de un combobox, etc. Cuando se procesa la página, se codifica el estado actual de la página y de los controles, y la cadena que se obtiene se guarda en la página en forma de campo oculto, por lo tanto se pueden realizar cambios en el estado hasta el evento PreRenderComplete. Cuando la página se represente en el explorador, no se guardarán los cambios en el ViewState.

El ViewState proporciona información de estado para una página específica ASP.NET. Si se necesita utilizar esa información en más de una página o si se desea que la información permanezca para todas las visitas al sitio Web, se debe utilizar otro método para mantener el estado, como por ejemplo, estado de aplicación, estado de sesión o personalización.

Ya sabemos que el ViewState nos permite almacenar información, pero ¿qué tipo de información se puede almacenar?

Se puede almacenar objetos de tipo Cadenas, Enteros, Booleanos, Array, ArrayList, Tablas Hash, Convertidores de tipos personalizados y además puede almacenar otros tipos de datos en donde la clase debe compilarse con el atributo Serializable para que el ViewState pueda serializarlos en formato XML.

Como ya indiqué antes, la información del ViewState se serializa en XML y luego se codifica en Base64, lo cual en ocasiones nos puede generar grandes cantidades de información que puede afectar al rendimiento de la página y nos puede generar problemas con algunos proxy y firewall, por lo tanto, es recomendable probar el rendimiento de las páginas y si es necesario también deshabilitar el ViewState para los controles de datos como el GridView, DataList, Repeater, etc que pueden generar campos ocultos de gran tamaño.

Si se nos presentará el problema de mucha cantidad de datos almacenados en la propiedad ViewState y excede el valor especificado en la propiedad de la página MaxPageStateFieldLength, la página divide el ViewState en varios campos ocultos para reducir el tamaño de cada campo y evitando así ser rechazados por el firewall.

Ahora, otra solución a este problema es tratar de minimizar este traslado de información entre cliente y servidor no persistiendo el ViewState en un campo oculto de la página, sino que en otro lugar como por ejemplo en la memoria del servidor (siempre y cuando tengamos buenos servidores y se nos permita hacerlo) y para eso tenemos el SessionPageStatePersister. Para ello lo único que hay que hacer es sobreescribir la propiedad PageStatePesister de la página de modo que devuelva una referencia a un objeto de la clase que acabamos de mencionar, y eso se hace de la siguiente manera:

protected override PageStatePersister PageStatePersister
{
   get
   {
       return new SessionPageStatePersister(this);
   }
}

Si miras el código fuente de la página, notaras que la cantidad de información a disminuido considerablemente.

También podemos comprimir (System.IO.Compression) la información de los campos ocultos, pero eso es un tema que hay que tratar más en detalle en otra oportunidad, por mientras basta con que sepas que se puede hacer.

Entonces, en resumen tenemos que ViewState nos brinda las siguientes ventajas:

  • No se requieren recursos del servidor: Está incluido en una estructura dentro del código de la página.
  • Implementación sencilla: No requiere que se utilice una programación personalizada. Se habilita de forma predeterminada para mantener los datos de estado en los controles.
  • Características de seguridad mejorada: Los valores están fragmentados, comprimidos y codificados para implementaciones de Unicode, por lo que son más seguros que los campos ocultos.

Y las desventajas de utilizar el ViewState son:

  • Consideraciones sobre el rendimiento: Dado que el ViewState se almacena en la propia página, el almacenamiento de valores de gran tamaño puede hacer que la página se muestre y se envíe de forma más lenta para los usuarios. Esto es especialmente relevante para los dispositivos móviles, donde el ancho de banda constituye a menudo una limitación.
  • Limitaciones de dispositivos: Los dispositivos móviles pueden carecer de una capacidad de memoria suficiente para almacenar una gran cantidad de datos.
  • Posibles riesgos de seguridad: El ViewState se almacena en uno o varios campos ocultos de la página. Aunque se almacenan los datos fragmentados, se pueden ver y manipular si se obtiene acceso al código fuente de la página.

Como ya se señaló anteriormente, la información de un campo oculto de ViewState puede ser vista si se obtiene acceso al código fuente de la página, lo que nos puede generar un problema de seguridad si los datos son de cierta importancia, así que para aminorar este problema, se puede cifrar el ViewState cambiando el atributo viewStateEncryptionMode en la directiva @ Page al valor “Always”.

Creo que ya es suficiente con esta información, ahora pasemos a algo práctico. Lo primero que debemos saber es que para utilizar la propiedad ViewState, es que la página Web ASP.NET debe tener un elemento de formulario de servidor, ósea un Form:

<form id="form1" runat="server">
   ...
</form>

Acá les dejo el código de un ejemplo muy sencillo. Se trata de generar un arreglo con valores el cual se guarda en el ViewState y por cada envío de la página se incrementan lo valores de acuerdo al último valor generado, nada de otro mundo, pero lo importante de esto es que vean como se guarda la información y como la podemos recuperar.

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" ViewStateEncryptionMode="Always" CodeFile="Default.aspx.cs" Inherits="_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">
    <title></title>
    </head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Enviar P&aacute;gina" />
    </div>
    <br />
    <div>
        <asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333" 
            GridLines="None">
            <RowStyle BackColor="#EFF3FB" />
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
            <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
            <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <EditRowStyle BackColor="#2461BF" />
            <AlternatingRowStyle BackColor="White" />
        </asp:GridView>
    </div>    
    </form>
</body>
</html>

Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Collections;   //para el ArrayList

public partial class _Default : System.Web.UI.Page 
{
    private ArrayList ArregloDeValores;
    private int UltimoValor;

    //protected override PageStatePersister PageStatePersister
    //{
    //    get
    //    {
    //        return new SessionPageStatePersister(this);
    //    }
    //}

    protected void Page_Load(object sender, EventArgs e)
    {
        //Si se intenta obtener un valor que no existe en el ViewState, no se iniciará ninguna excepción,         //por lo tanto es mejor asegurarse de que el valor existe, por lo tanto es recomendable primero 
        //comprobar la existencia del objeto
        if (ViewState["ARREGLO"] != null)
        {   //  rescato los ultimos valores guardados en ViewState
            ArregloDeValores = (ArrayList)ViewState["ARREGLO"];
            UltimoValor = Convert.ToInt32(ViewState["ULTIMO"]);
            
            for (int i = 0; i < 100; i++)
            {
                ArregloDeValores[i] = UltimoValor + i;
            }

            ViewState.Add("ARREGLO", ArregloDeValores); //  Guardo el arreglo en ViewState
            //ViewState["ARREGLO"] = ArregloDeValores;  //  También puedo guardar el arreglo así
            
            GridView1.DataSource = ArregloDeValores;
            GridView1.DataBind();
        }
        else
        {
            UltimoValor = 100;
            ArregloDeValores = NuevoArreglo(UltimoValor);   //  La primera vez crea el arreglo
            ViewState.Add("ARREGLO", ArregloDeValores);     //  Guardo el arreglo en ViewState
            GridView1.DataSource = ArregloDeValores;
            GridView1.DataBind();
        }
    }
 
    protected void Page_PreRenderComplete(object sender, EventArgs e)
    {
        //Se pueden realizar cambios en el ViewState hasta el evento PreRenderComplete.
        //Después del evento cuando la página se represente en el explorador, no se guardarán los 
        //cambios realizados en el ViewState.
        
        //ViewState.Add("ULTIMO", Convert.ToInt32(ViewState["ULTIMO"]) + 100);Puedo asignar de ambas formas
        ViewState["ULTIMO"] = Convert.ToInt32(ViewState["ULTIMO"]) + 100;
    }

    private ArrayList NuevoArreglo(int Ultimo)
    {
        ArrayList miArreglo = new ArrayList(100);
        for (int i = 0; i < Ultimo; i++)
        {
            miArreglo.Add(i);
        }
        return miArreglo;
    }
}

No olviden de revisar el código fuente resultante de la página y hacer pruebas con el ViewStateEncryptionMode spara ver la información codificada en Base64 encriptada.

Prueba también quitanto los comentaríos a SessionPageStatePersister y si miras el código fuente de la página, notaras que la cantidad de información a disminuido considerablemente de esto:


A tan solo esto:

Es todo por hoy, espero les sea de ayuda.

Saludos Toby

Entradas populares