XmlTextWriter... pero para javascript



Estoy tratando de hacer un chat para ASP.NET desde hace unas semanas. Comencé con la idea de algo "sencillito"... pero claro, se te van ocurriendo cosas y ya me he puesto totalmente en serio a hacer el mejor chat para ASP.NET que yo sepa hacer .

La idea es que cualquiera pueda tener un chat en su página, aplicación, intranet o lo que sea sin más que arrastrar y hacer los cambios de estilo que el webmaster crea oportuno.

La cosa es que mi primera decisión importante fue usar AJAXbyMe, es decir, que no se usara en ningún momento AjaxPRO.NET, ASP.NET AJAX (ex-Atlas) o cualquier otro framework AJAX. De ese modo independizo totalmente al webmaster de ellos.

La cosa es que poniéndome poco a poco me estoy fabricando mi propio framework AJAX (prometo publicarlo y hacerlo libre más adelante, por si a alguien le interesa)... y entre otras cosas me molestaba crear ficheros XML con javascript, pues lo que valía para Internet Explorer, no valía para Firefox y viceversa... Por cierto, lo de los ficheros XML es por aquello de enviar y recibir info mediento un XmlHttpRequest con un XML como Dios manda y mediante POST.

... así que decidí crear la clase XmlTextWriter para javascript. De modo que las funcionalidades más usadas del XmlTextWriter de ASP.NET fueran sintácticamente muy similares (por no decir idénticas) a las de esta mini-librería.

Eso sí, la librería es muy sencillita, y muy ampliable (el que se anime a ampliarlo que lo haga y lo publicamos aquí!!!), por lo que no esperéis magia!! Sólo lo básico.

Sólo con poneros un ejemplo de código veréis lo que quiero decir:

    var miXML = new XmlTextWriter();
    miXML.Formatting = true;
   
    miXML.WriteStartDocument();
    miXML.WriteStartElement("myXML");
            miXML.WriteStartElement("persona");
                miXML.WriteAttributeString("Id", "1");
                miXML.WriteStartElement("nombre");
                    miXML.WriteValue("David");
                miXML.WriteEndElement();
                miXML.WriteElementString("Apellidos", "Villa");
            miXML.WriteEndElement();
            miXML.WriteStartElement("persona");
                miXML.WriteStartElement("nombre");
                    miXML.WriteAttributeString("Id", "2");
                    miXML.WriteCDATA("Samuel");
                miXML.WriteEndElement();
                miXML.WriteElementStringCDATA("Apellidos", "Etoo");
            miXML.WriteEndElement();           
        miXML.WriteEndElement();
        miXML.WriteElementString("Vacío");
    miXML.WriteEndElement();
    miXML.WriteEndDocument();


¿Qué es código en javascript o código en ASP.NET?

Como sabéis de otros dos artículos de XmlTextWriter para ASP.NET (XmlTextWriter y XmlTextWriter en un StringBuilder), la única diferencia se encuentra a la hora de declarar la variable XmlTextWriter... que paradójicamente es más sencilla de declarar con javascript

Como os comentaba, la mayoría de la librería es un calco de las propiedades y métodos del análogo para .NET, pero además hay otras funciones y métodos que deberíais conocer. A continuación os digo como accederlas (siguiendo el ejemplo) y qué son:

- miXML.xml: es el propio xml en formato texto raso, tal cual.
- miXML.escapeXML: devuelve miXML.xml como UrlEncode, y es ideal para enviar al servidor (ahí debe leerse con UrlDecode).
- miXML.parseXML: devuelve el xml pero como objeto xml para javascript (funciona para todos los navegadores).
- miXML.WriteElementStringCDATA("nombreElemento", "contenido"): es lo mismo que el WriteElementString, sólo que el contenido lo escribe como CDATA.

Hay otras funciones que no he sabido hacer privadas (¿¿se pueden declara métodos y propiedades privadas en una "clase" javascript??), y por tanto acceder, aunque no creo que os sirvan para mucho

Pues lo dicho, aquí tenéis la mini-librería javascript:






Redirigir a páginas de error

En ciertas circunstancias, puede ser conveniente que, al surgir un error, el cliente sea redirigido a una página específica.

Antes de ASP.NET, el único modo de redirigir al usuario si surgía un error era configurando el servidor Web y explicitando qué página se encarga de qué tipo de error (Page Not Found: error 404, Server Error: error 500, etc.)

Con ASP.NET (y desde la versión 1.0), es muy sencillo definir a qué página se irá cuando surja un error, no hay más que configurar el web.config. Por ejemplo:

<configuration>
  <system.web>
    <customErrors defaultRedirect="GenericError.html" mode="RemoteOnly">
      <error statusCode="500" redirect="InternalError.html"/>
    </customErrors>
  </system.web>
</configuration>


Como es de imaginar, el atributo "defaultRedirect" indica a qué página se irá si surge un error que no hemos indicado explícitamente.

En cuanto al "mode", las opciones son "On", "Off" y "RemoteOnly", según si queremos que se activa, se desactive o que únicamente esté activado cuando se accede en remoto (Por meter leña al fuego... ¿Echamos en falta "LocalOnly"?).

Por último, el elemento "error" asigna una página específica según el código de estado (500: error interno de servidor, 404: página no encontrada, etc.)

Fijaos que es conveniente que se redirija a páginas .html, o en general a páginas que no maneje ASP.NET... imaginaos el enorme lío que puede montarse si ante un error 404, se redirija a una página .aspx que no existe; o ante un error 500, se redirija a una .aspx que también da error 500!!

Realmente no sé cómo se comporta ASP.NET en estos casos, pero creo que no querría saberlo



Lista Genérica Autonumérica (extended by Subgurim)

Muchos de vosotros ya conoceréis la enorme utilidad de las listas genéricas, nuevas en ASP.NET 2.0.

Como ya os comenté en su correspondiente artículo, fue comenzar a usarlas y no soltarlas... sin embargo en ocasiones surgen requerimientos que no pueden ser resueltos con las clases que vienen por defecto... y he aquí la gran utilidad de la herencia de clases

En esta ocasión, lo que yo quería era una lista genérica de las de siempre, pero con una variable autonumérica de la que no quería preocuparme más que para recoger el valor.

Dicho de otro modo, yo quiero una lista genérica, y asociado a cada Item que inserto en la lista, debe haber una variable entera "autonumeric" que se vaya incrementando en base a la variable "step" que indique y a partir del "seed" que inicialice... como podréis comprobar, es equivalente a lo que en las BBDD se le llama autonumérico, identity o similares.

Pues bien, resulta ser que implementar esto es tremendamente sencillo, y aquí tenéis el código:

using System;

namespace System.Collections.Generic
{
    /// <summary>
    /// Listado genérico autonumérico
    /// Autonumeric generic List
    /// </summary>
    public class AutonumericList<TValue> : Dictionary<int, TValue>
    {
        #region Propiedades
        // Autonumérico
        public int autonumeric = 1;

        private int _step = 1;
        /// <summary>
        /// Define el incremento del autonumérico. No puede valer 0.
       /// Defines the autonumeric increment
        /// </summary>
        private int step
        {
            get { return _step; }
            set
            {
                _step = value != 0 ? value : 1;
            }
        }

        #endregion

        #region Inicialización

        public AutonumericList()
            : this(1, 1)
        { }       

        public AutonumericList(int seed, int step)
        {
            this.autonumeric = seed;
            this.step = step;
        }

        #endregion

        #region 'Nuevas propiedades'
        public void Add(TValue value)
        {
            base.Add(autonumeric, value);
            autonumeric += step;
        }

        /// <summary>
        /// The first argument is ignored.
        /// El primer argumento es ignorado.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public new void Add(int key, TValue value)
        {
            this.Add(value);
        }

        #endregion
    }
}


El quid de la cuestión está en heredar de la clase Dictionary, que consta de una clave (key) y un valor (value) genéricos. En este caso, obligamos a que la clave sea un entero, y será la que usaremos como autonumérico.

En cuanto al código:
  • Sólo defino dos propiedades (autonumeric y step), asegurándonos que el step no puede valer 0.
  • La inicialización es también muy simple. Si no indico nada, el primer autonumérico valdrá 1 y se incrementará de 1 en 1.
  • Lo más importante está en la función Add, que se encarga de añadir el valor que insertemos y crear el autonumérico correspondiente de forma automática. No hay ningún método (al menos que yo conozca y no sea demasiado difuso) para ocultar la función Add que añade la clave y el valor. Esta función es la que se usa en un Dictionary normal y corriente, solo que con nuestra AutonumericList no queremos que pueda cambiarse la Key (nuestro autonumérico).
Usar el AutonumericList es igualmente sencillo, por ejemplo:

        AutonumericList<string> listado = new AutonumericList<string>();

        for (int i = 0; i < 15; i++)
        {
            listado.Add(i.ToString());
        }

        listado.Add(5000, "Veremos que no se hace nada con el 5000");
       
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        foreach (KeyValuePair<int, string> kvp in listado)
        {
            sb.Append(kvp.Key);
            sb.Append("<br>");
        }
        Label1.Text = sb.ToString();


Espero que os sea útil para algo




Multi Search API

Como su propio nombre indica, multiSearch API es una librería donde se aúnan las búsquedas de varios buscadores.

MultiSearch API usa las APIs de búsqueda de Google, Yahoo y MSN, de modo que con unas pocas líneas de código tendremos los resultados de estos tres buscadores y además una cruce entre todos ellos, llamado Global, que trata de mostrar los mejores resultados en base al orden tabulado en que aparecen en los tres buscadores.

Es decir, se le da una puntuación de 0 a 10 a cada buscador según lo fiable que sean sus búsquedas, y en Global se analiza el puesto en que han aparecido las Webs según qué buscador y se tabula en base a la puntuación que se le ha dado, obteniendo finalmente un listado ordenado de la forma más óptima posible.

La Web de ejemplo, junto con el enlace a sí misma, la tenéis en multisearchapi.subgurim.net

Para aprender a usarla no tenéis más que seguir el ejemplo descargable.



Crear y consumir Web Services con Visual Web Developer

Crear y consumir Web Services con el Visual Web Developer (y superiores) es tremendamente sencillo.

En este artículo vamos a crear paso por paso el típico Web Service al que le mandaremos nuestro nombre y nos devolverá un saludo. Una vez creado lo subiremos a una biblioteca de Servicios Web y lo consumiremos en nuestra propia aplicación... y en poco más de 5 minutos creamos y consumimos un sencillo Web Service.

Crear un servicio Web
1.- Abrir un nuevo proyecto con el Visual Web Developer.
2.- Creamos un nuevo fichero .asmx: File -> New File -> Web Service Template, y lo nombramos HelloWorld.asmx. Por costumbre, en los Web Service deshabilito que el código vaya en otro fichero separado.
3.- Tendremos algo como esto:

Upload/ws1.jpg

4.- Apenas vamos a cambiar nada, simplemente el Namespace del WebService y un poco la función, obteniendo esto:

Upload/ws2.jpg

5.- ¿¿¡¡Ya está el Web Service!!?? Sí, ya está. Ahora solo queda publicarlo en vuestra Web (obviamente con soporte para ASP.NE)T. Específicamente, este webservice lo podéis encontrar en http://www.subgurim.net/servicios-web/holamundo.asmx
Para que nuestro Web Service sea conocido y utilizado por la comunidad ASP.NET, lo publicaremos en la biblioteca de servicios Web de portal de ASP.NET en castellano: www.es-asp.net.


Consumir un servicio Web
Si crear un servicio Web ha sido sencillo, consumirlo lo es aún más:
1.- En cualquier proyecto Web -existente o creado para la ocasión- vayamos a WebSite -> Add Web Reference, obteniendo:

Upload/ws3.jpg

2.- Presionaremos sobre GO y nos pedirá que le demos un nombre de referencia. En nuestro caso lo llamaremos subgurim.Prueba
3.- Ahora, para ver como llamamos al WebService y nos devuelve el valor, creamos una página con un TextBox, un Button y una Label, de forma que cuando se presione sobre el Button, se le manda al servicio Web el contenido del TextBox, y éste nos devolverá el saludo personalizado.
El código vendría a quedar como:

pruebaHelloWorld.aspx
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /><br />
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>


pruebaHelloWorld.aspx.cs
    protected void Button1_Click(object sender, EventArgs e)
    {
        subgurim.Pruebas.HolaMundo prueba = new subgurim.Pruebas.HolaMundo();

        Label1.Text = prueba.HelloWorld(TextBox1.Text);
    }



Obteniendo el resultado esperado:

Upload/ws4.jpg

Y sí, ya está: no más de 5 minutos!!
Para crear un servicio Web más complejo no tiene más dificultad que cambiar el código de nuestro .asmx. Podemos devolver un DataSet, un fichero XML, una fecha, una matriz de números reales... lo que queramos!!



Profiles II

Tras nuestro primer artículo de introducción a los profiles, ahora veremos alguna de las características más avanzadas de los profiles. Éstas hacen de los profiles no sólo una herramienta útil y cómoda de usar, sino una herramienta muy potente y prácticamente imprescindible para las aplicaciones Web.

Tipos de datos
En el primer artículo sobre profiles, vimos que en el XML que las definía contenía el tipo de datos de la variable profile. Pues bien, no sólo se puede hacer uso de los tipos de básicos, sino que podemos usar cualquiera, desde listados genéricos hasta nuestras propias clases. siguiendo el ejemplo del primer artículo:

        <profile enabled="true">
                <properties>
                    <add name="Sexo" defaultValue=""/>
                    <add name="Visitas" type="int" defaultValue="1"/>
                    <add name="Cumple" type="System.DateTime"/>
                    <add name="misAmigos" type="System.Collections.Specialized.StringCollection"/>
                   
<add name="referido" type="Subgurim.Persona"/>
                </properties>
        </profile>


Como vemos, hemos añadido dos variables profile:
- "misAmigos": que no es más que un StringCollection.
- "referido", que identificará a la persona que nos ha aconsejado esta Web y que será de la clase Persona que hemos creado nosotros.

Groups
Dando otra vuelta de tuerca a los profiles, tenemos los groups. Con ellos podemos agrupar varios profiles en un mismo grupo. Por ejemplo, imaginemos que queremos guardar en variables profile la cantidad noticias por página que mostraremos al usuario, así como cantidad de respuestas por página en un post del foro. Obviamente las podríamos guardar como dos variables profile distintas... pero no hay duda de que conceptualmente responden a "items por página".

De modo que usaremos los groups:

        <profile enabled="true">
                <properties>
                    <add name="Sexo" defaultValue=""/>
                    <add name="Visitas" type="int" defaultValue="1"/>
                    <add name="Cumple" type="System.DateTime"/>
                    <add name="misAmigos" type="System.Collections.Specialized.StringCollection"/>
                   
<add name="referido" type="Subgurim.Persona"/>
                    <group name="Mostrar">
                        <add name="General" type="System.Int16" defaultValue="25" />
                        <add name="Noticias" type="System.Int16" defaultValue="8" />
                        <add name="Foro" type="System.Int16" defaultValue="15" />
                    </group>

                </properties>
        </profile>


Y para ello no hay más que abrir otro elemento XML llamado "group", dentro del cual estarán los elementos "add" que ya conocemos.

A la hora de usarlo en código, que es realmente lo que nos interesa, vemos que sigue siendo intuitivo y sencillo:

        Profile.Mostrar.Foro = 13;
        Profile.Mostrar.Noticias = Profile.Mostrar.General;



allowAnonymous
Hagamos un pequeño inciso para recordar que los Profiles funcionan conjuntamente con el sistema de autenticación integrado en ASP.NET. Es decir, que cuando un usuario se autentica con su nombre y contraseña, éste tiene almacenado en la Base de Datos (transparente a los programadores) las características del profile.

¿Pero qué ocurre cuando queremos usar los profiles con usuarios que no es autentican (anónimos)? El modo de proceder de ASP.NET en estos casos es asignar una clave al visitante anónimo (en una cookie) que se corresponda con una entrada en la tabla de profiles. De ese modo, el usuario anónimo puede disfrutar de los profiles, aunque sea dependiendo de una cookie .

Por defecto los profiles no están habilitados para los visitantes anónimos, y debemos explicitarlo cuando definamos el profile. En nuestro ejemplo, sólo vamos a querer que el visitante anónimo pueda usar los profiles del grupo mostrar", pues el resto nos es inútil si no se registra. Por tanto, quedaría:

        <profile enabled="true">
                <properties>
                    <add name="Sexo" defaultValue=""/>
                    <add name="Visitas" type="int" defaultValue="1"/>
                    <add name="Cumple" type="System.DateTime"/>
                    <add name="misAmigos" type="System.Collections.Specialized.StringCollection"/>
                    <add name="referido" type="Subgurim.Persona"/>
                    <group name="Mostrar">
                        <add name="General" type="System.Int16" defaultValue="25" allowAnonymous="true" />
                        <add name="Noticias" type="System.Int16" defaultValue="8" allowAnonymous="true" />
                        <add name="Foro" type="System.Int16" defaultValue="15" allowAnonymous="true" />
                    </group>
                </properties>
        </profile>


Acceder al profile de un usuario que no sea el activo.
Hasta ahora hemos visto cómo accedíamos a la variables profile del usuario que estaba activo, pero podríamos querer acceder a las variables profile de otros usuarios.

Por ejemplo imaginemos que queremos hacer una ficha de usuario pública de todos nuestros usuarios; el usuario A acceder a la ficha del usuario B, si usáramos:

        Label1.Text = Profile.Sexo;

La Label nos mostraría el sexo del usuario A... ¿cómo lo hacemos entonces?

Pues es bien sencillo, no hay más que hacer:

        ProfileCommon prof = Profile.GetProfile("usuarioB");
        prof.Sexo;


Se coge el profile del usuario que queramos con el GetProfile y la asignamos a una variable del tipo ProfileCommon. Esta variable (prof) puede acceder -intellisense incluído- a todas las propiedades profile del usuario especificado.


Tu propia clase profile.
Si ya te has convencido del enorme poder de los profile... ¿qué pensarías si te dijera que puedes crearte tu propia clase profile sin necesidad de usar el XML del web.config?

Para entenderlo mejor, veamos un ejemplo. A las propiedades profile que ya tenemos vamos a añadir otro StringCollection de usuariosIgnorados (listado de usuarios que nos caen mal)... pero no lo vamos a añadir en el XML, sino que vamos a crear esta clase:

    public class myProfileClass : ProfileBase
    {
        public myProfileClass()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        public StringCollection usuariosIgnorados
        {
            get
            {
                return (StringCollection)base["Ignorados"];
            }
            set
            {
                base["Ignorados"] = value;
            }
        }
    }


Que no es más que una clase que hereda de ProfileBase y a la que le hemos añadido una propiedad (usuariosIgnorados) que acceder a base["ignorados"] para devolver o grabar valores.

Esto no es más que un ejemplo con una única propiedad, pero podríamos extenderlo tanto como quisiéramos.

Pero ojo, de algún modo le tenemos que decir al XML que tenemos una clase que extiende a ProfileClass... cosa que conseguimos con solo añadir un atributo:

        <profile enabled="true" inherits="myProfileClass">
                <properties>
                    <add name="Sexo" defaultValue=""/>
                    <add name="Visitas" type="int" defaultValue="1"/>
                    <add name="Cumple" type="System.DateTime"/>
                    <add name="misAmigos" type="System.Collections.Specialized.StringCollection"/>
                    <add name="referido" type="Subgurim.Persona"/>
                    <group name="Mostrar">
                        <add name="General" type="System.Int16" defaultValue="25" allowAnonymous="true" />
                        <add name="Noticias" type="System.Int16" defaultValue="8" allowAnonymous="true" />
                        <add name="Foro" type="System.Int16" defaultValue="15" allowAnonymous="true" />
                    </group>
                </properties>
        </profile>



Conclusión
Ya hemos visto bastante sobre los profiles (siempre hablando a nivel práctico). Como en todo, su uso es muy recomendable, pero su abuso no.

La tabla de los profiles de la base de datos que se crea ASP.NET supone un registro por cada usuario. Cada registro tiene un campo donde se guardan los datos en XML. Os podréis imaginar que a mayor complejidad, mayor es el XML... y cuantos más son los usuarios, más grande es la base de datos... supongo que no hace falta que os diga más



Introducción al control de errores: try - catch - finally

En ocasiones es imprescindible manejar el comportamiento de nuestra aplicación cuando surge un error.
Por ejemplo debemos exigir que se cierre un DataReader si se produce un error, que se cierre un fichero XML si surge un error de lectura, o que se controle una llamada a un WebService al que no tenemos acceso ninguno.

Así pues, el objetivo de este artículo es mostrar el uso básico de los comandos try, catch y finally.

Por ejemplo vamos a controlar si surge algún error cuando enviamos un Email mediante nuestro código C# (error que, dicho sea de paso, sucede a menudo). Recordando de nuestro artículo de "envío de emails con ASP.NET":

    MailMessage Email = new MailMessage(Origen, Destino, Asunto, Mensaje);
    SmtpClient smtp = new SmtpClient();
    try
    {
        smtp.Send(Email);
    }
    catch (Exception ex)
    {
        Label1.Text = ex.Message;
    }


Como vemos, tratamos de enviar un mensaje, y si nos da error lo mostraremos en nuestro Label (que suponemos está en nuestra página .aspx). De modo que dentro de "try" colocaremos el código que queremos vigilar y dentro del "catch" diremos lo que queremos hacer si sucede una excepción.

Cuando estemos más avanzados en el pequeño mundo de la captura de errores, veremos que se pueden anidar tantos catch como queramos, poniéndoles a cada uno como parámetro el tipo de excepción que queramos controlar. Pero esto no lo vamos a explicar en este artículo, con la idea de mantenernos en un nivel básico/ de iniciación.

En cuanto al "finally", es el comando al que se acudirá siempre, tanto si sucede un error como si no. Por ejemplo:

    MailMessage Email = new MailMessage(Origen, Destino, Asunto, Mensaje);
    SmtpClient smtp = new SmtpClient();
    try
    {
        smtp.Send(Email);
    }
    catch (Exception ex)
    {
        Label1.Text = ex.Message;
    }
    finally
    {
       Label2.Text = "Ya hemos hecho el intento de envío de mensaje";
    }

Si no sucediera un error, de forma que el mail se mande correctamente, al acabar el envío llegaremos al finally y escribiremos sobre la Label2... pero si sucede un error, cuando lo hayamos tratado en el catch también llegaremos al finally y escribiremos sobre la Label2.

El finally es muy útil en los ejemplos que hemos comentado al inicio. Por ejemplo si trabajamos con un DataReader, pondremos un árbol try - catch - finally en el que el catch controlaría los errores y el finally se encargaría de cerrar el DataReader, de modo que éste quedaría cerrado surgiera o no un error.

Para finalizar, es importante destacar que no hay que usar try - catch - finally en todos los sitios, ni imponer el control de errores de forma genérica sobre numerosas líneas de código. Hay que darse cuenta de que al usarlos estamos utilizando una vigilancia exhaustiva de todo lo que sucede, por lo que gastamos recursos y empeorará la eficiencia de nuestra aplicación.

Por tanto se recomienda usarlos sólo cuando haga falta y tratando de utilizar otros remedios menos gastadores. Por ejemplo, en lugar de hacer esto:

        try
        {
            resultado = a / b;
        }
        catch
        {
            // Si ha dado error es que b = 0. Le daremos el valor de 0 a resultado, aunque obviamente no vale eso.
            resultado = 0;
        }


hay que hacer esto:

        if (b != 0)
            resultado = a / b;
        else
            resultado = 0;



Profiles

Los profiles son una de las funcionalidades prefabricadas que vienen con ASP.NET 2.0 que cuando las conoces ya no puedes vivir sin ellas.

Con los profiles vamos a poder definir propiedades a nuestros usuarios, sin más que rellenar un sencillo XML en nuestro Web.Config. Y es aplicable tanto a usuarios registrados como a usuario anónimos.

Por ejemplo, podríamos querer almacenar el número de veces que un usuario ha visitado nuestra página, su cumpleaños o el tamaño de letra que prefiere para leer nuestros textos. Realmente el límite está en la imaginación del webmaster y de su aplicación.

Hasta ahora teníamos dos métodos para tal menester, o bien fabricábamos una base de datos con todas esas características o bien usábamos las cookies. Ambas opciones pueden ser válidas en algunos escenarios, pero tienen sus problemas:

Usando una base de datos...
Si nos creáramos nuestra base de datos tendríamos un soporte fiable, pero también deberíamos invertir una mayor cantidad de tiempo. Sobretodo si quisiéramos alcanzar la facilidad de uso de los profiles, pues habríamos de crear la BBDD con sus procedimientos almacenados, su capa DAL y si capa BLL. Además, si quisiéramos aumentar/disminuir la cantidad de propiedades de cada usuario, se traduciría en otro extra de nuestro preciado tiempo.

Usando cookies...
Si lo hiciéramos con cookies, la facilidad con que guardaríamos los datos sería inmediata (ver artículo sobre cookies en ASP.NET), pero no sería tan sencillo de usar como con profiles (más tardería veremos el porqué) y obviamente mucho menos fiable y efectivo. Menos fiable porque cualquier usuario puede elegir borrar sus cookies o ni siquiera activarlas. Y menos efectivo porque esas propiedades del usuario no serían propiamente del usuario, sino del navegador con que accede el usuario. Si el usuario cambia de ordenador o simplemente de navegador, sus propiedades no se mantendrían.

Por tanto, usemos profiles!!
Como en tantas otras cosas con ASP.NET, los profiles eliminan las desventajas y se quedan con las ventajas... incluso les añaden más! Con los profiles:
1.- Tenemos un soporte fiable (la info se guarda en un BBDD, aunque para nosotros sea tranparente.
2.- Se guardan los datos tan fácilmente como se le da valor a una variable
3.- La cantidad de propiedades de usuario se pueden quitar y añadir en cualquier momento sin más que borrar o escribir unas pocas líneas de XML.
4.- Sirve tanto para usuario registrados como para usuarios anónimos. En caso de ser usuario registrado, la info que le guardemos la podremos acceder esté donde esté. En caso de usuarios anónimos, tenemos las mismas limitaciones de las cookies: sólo accederemos a su info si accede desde el mismo lugar y navegador.
5.- Acceder a los datos es también muy sencillo, pues tenemos el soporte de intellisense. Y es que para nosotros, las características de nuestros usuarios, los profiles, no serán más que "variables globales" que podremos acceder desde cualquier lugar de nuestro código.

Queremos ejemplos! Quereeeemos ejemplos!
Pero vale ya de palabrería, ¿No? Un ejemplo vale más que mil palabras, así que vamos a plantear el siguiente escenario, en el que queremos que de nuestros usuarios podamos almacenar las siguientes características:
- Su fecha de cumpleaños
- La cantidad de visitas que ha hecho a la web
- Su sexo (Me refiero a "masculino o femenino" no a "mucho o poco"  )

Por tanto, lo primero que debemos hacer es definir el siguiente fragmento XML dentro de nuestro web.config:

        <profile enabled="true">
                <properties>
                    <add name="Sexo" defaultValue=""/>
                    <add name="Visitas" type="int" defaultValue="1"/>
                    <add name="Cumple" type="System.DateTime"/>
                </properties>
        </profile>


Sí, así de simple. Vemos que en las propiedades definimos un nombre, el tipo de datos (por defecto es un string), y si lo deseamos un valor por defecto.

En cuanto a lo de recoger o grabar valores de las propiedades de usuario... más fácil imposible:

        Profile.Sexo = "Masculino";

        Profile.Visitas = Profile.Visitas + 1;
        // O como con cualquier otra variable int
        // Profile.Visitas += 1;
        // Profile.Visitas++;

        Profile.Cumple = new DateTime(1981, 8, 14);
        Label1.Text = Profile.Cumple.ToShortDateString();


Y ya está. ASP.NET hace el resto: guardarlo en base de datos, enlazar al usuario con sus profiles correspondientes (bien sea un usuario registrado o un usuario anónimo), genera al vuelo la clase Profile con las propiedades que le hemos especificado, etc.


Perfecto, ¿es eso todo?
No ni mucho menos, muchas cosas quedan por decir de los profiles, pero por hoy ya tenemos bastante. En la próxima entrega estudiaremos aspectos y características algo más avanzadas.