Mostrando entradas con la etiqueta c#. Mostrar todas las entradas
Mostrando entradas con la etiqueta c#. Mostrar todas las entradas

Lo que todo desarrollador debería saber sobre serialización a XML en .NET (y cómo afecta a los Web Services)

lunes 23 de abril de 2007 | categorías: , , , , | 6 comentarios -- da clic aquí para dejar el tuyo

En la plática y taller de este mes, alguien hizo una pregunta muy común: "Quiero construir un Web Service en .NET que haga X, ¿por dónde comienzo?"

Así que le prometí escribir un artículo al respecto. Sin embargo, en cuanto comencé, me di cuenta que hay un concepto más básico que debe ser amaestrado para en verdad entender lo que está sucediendo: Serialización. Específicamente serialización a XML.

¿Qué es serialización y cómo se utiliza?

Serialización, no es más que una palabra dominguera que significa transformar una instancia de una clase a una serie de bytes con un formato determinado. En este caso estoy hablando de agarrar una instancia de una clase y transformarla a un documento XML.

En la plática, algunas personas se sorprendieron cuando les dije que prácticamente cualquier clase podía ser serializada casi automáticamente, de una manera relativamente sencilla. Solo hay un "pero" del que debes estar consciente: únicamente los miembros y propiedades públicas pueden ser serializados. En otras palabras, no convierte métodos, indexadores, campos privados o protegidos o propiedades solo-lectura (excepto colecciones solo-lectura).

Toma como ejemplo una clase sencilla como la siguiente:

using System;
 
public class MiClase
{
    protected string _campo1 = "campo1 es protegido";
    public string _campo2 = "campo2 es publico";
    private string _campo3 = "campo3 es privado";
    private int _propiedad1 = 1000;
    private int _propiedad2 = 9999;
    public int _propiedad3 = 7777;
 
    public int UnaPropiedad
    {
        get { return _propiedad1; }
        set { _propiedad1 = value; }
    }
 
    protected int OtraPropiedad
    {
        get { return _propiedad2; }
        set { _propiedad2 = value; }
    }
 
    public int PropiedadPublica
    {
        get { return _propiedad3; }
    }
 
    // Se requiere un constructor publico default para que 
    // funcione la serializacion
    public MiClase() { }
}

Podemos serializarla (transformarla a XML pues) con un código como este:

using System;
using System.IO;
using System.Xml.Serialization;
 
class Program
{
    static void Main(string[] args)
    {
        MiClase m = new MiClase();
 
        XmlSerializer serializador = new XmlSerializer(typeof(MiClase));
        StringWriter escritor = new StringWriter();
 
        // se puede serializar a casi cualquier tipo de Stream o Writer
        // p.ej. System.IO.StreamWriter, System.Xml.XmlWriter, etc.
        serializador.Serialize(escritor, m);
        Console.WriteLine(escritor.ToString());
    }
}

Si corremos el programa, el resultado será este:

O, visto de una manera más amigable (utilizando el visualizador de XML de Visual Studio):

Nota que únicamente el _campo2, _propiedad3 y UnaPropiadad fueron serializados, ya que eran los únicos con un nivel de acceso public. PropiedadPublica, a pesar de ser public, era solo-lectura y por lo tanto no fue serializada. También nota que automáticamente construyó el documento utilizando el nombre de la clase (MiClase) como el elemento raíz y tomó el nombre de cada campo para los elementos hijos (_campo2, _propiedad3, UnaPropiedad).

La magia la hace la clase XmlSerializer, la cual tiene 3 métodos interesantes:

  • Serialize() convierte una instancia de una clase a XML.
  • Deserialize() hace lo contrario, toma un documento XML y lo transforma en una instancia de una clase.
  • CanDeserialize() regresa un booleano para probar si el XML en realidad se puede des-serializar.

Ahora, puedes controlar varios aspectos de la serialización, aplicando atributos:

  • [Serializable] no solo indica que la clase puede ser serializada, sino que también revisa que todos los tipos contenidos dentro de la clase (otra clase, por ejemplo) también sean serializables. Si no lo son, entonces arroja un SerializationException.
  • [NonSerialized] y [XmlIgnore] indican que no queremos que se serialize el campo o propiedad. El primero afecta al SoapFormatter (el utilizado por WebServices), y el segundo afecta a XmlSerializer.
  • [XmlRoot], que su vez tiene parámetros como Namespace y ElementName para especificar el nombre y espacio de nombres del elemento raíz. Este se aplica solo a la clase.
  • [XmlElement], es parecido al anterior, pero se aplica a los campos o propiedades. Puedes especificar el tipo de dato de XML Schema que debe aplicar y si es o no nulleable mediante los parámetros DataType y IsNullable. También puedes especificar el espacio de nombres y el nombre del elemento como en XmlRoot.
  • [XmlAttribute] indica que quieres serializar el valor como un atributo, en lugar de un elemento.

Para ver el impacto, vamos a aplicar estos conceptos al ejemplo anterior:

using System;
using System.Xml.Serialization;
 
[Serializable()]  //indica explicitamente que esta clase es serializable
[XmlRoot(Namespace = "http://comunidadnetjuarez.org/2007/04",
    ElementName = "MiClaseSerializada")] // indica el namespace y nombre 
public class MiClase                     // del elemento raiz
{
    protected string _campo1 = "campo1 es protegido";
 
    [XmlElement(ElementName = "SegundoCampo",
        DataType = "string",
        IsNullable = false)]  // indica el nombre y tipo del elemento
    public string _campo2 = "campo2 es publico";
 
    private string _campo3 = "campo3 es privado";
    private int _propiedad1 = 1000;
    private int _propiedad2 = 9999;
 
    [NonSerialized()] // no serializar cuando se use SoapFormatter
    [XmlIgnore()]     // no serializar cuando se use XmlSerializer
    public int _propiedad3 = 7777;
 
    [XmlAttribute(AttributeName = "valor")] // indica que deseamos que
    public int UnaPropiedad                 // se serialize como atributo XML
    {                                       // y no como elemento XML
        get { return _propiedad1; }
        set { _propiedad1 = value; }
    }
 
    protected int OtraPropiedad
    {
        get { return _propiedad2; }
        set { _propiedad2 = value; }
    }
 
    public int PropiedadPublica
    {
        get { return _propiedad3; }
    }
 
    // Se requiere un constructor publico default para que 
    // funcione la serializacion
    public MiClase() { }
}

El resultado sería el siguiente:

La cosa comienza a ponerse más interesante mientras más complejidad le agreguemos a la clase. Por ejemplo, ¿qué pasa si mi clase tiene una colección o lista de cosas? Bueno, pues resulta que únicamente las colecciones que implementen ICollection o IEnumerable podrán serializarse (p.ej. un ArrayList). Si implementan IDictionary (como un HashTable) estas no son serializadas (de hecho levanta una excepción).

Agreguemos el siguiente miembro a la clase:

    public string[] arreglo = { "arreglo uno", 
                                "arreglo dos", 
                                "arreglo tres" };

El resultado sería el siguiente:

Y finalmente veamos qué pasa si aplicamos [XmlElement]:

    [XmlElement(ElementName = "UnArreglo")]
    public string[] arreglo = { "arreglo uno", 
                                "arreglo dos", 
                                "arreglo tres" };

Creación automática de una clase serializable

Como puedes ver, tienes bastante control sobre la conversión de una clase .NET a un documento XML. Sin embargo, mientras más complejo sea el documento XML que quieras producir, más complejo y cuidadoso tendrás que ser con la aplicación de los atributos para obtener el resultado que quieres.

Muchas veces quizá es más sencillo comenzar con un documento XML de ejemplo o mejor aún con el contrato XML Schema que debe cumplir el documento XML que quieres producir cuando se serialice tu clase. Una vez que tienes esto, puedes utilizar la utilería xsd.exe para automáticamente generar los tipos adecuados en C# (o VB.NET).

Veamos un ejemplo. Supongamos que tienes un archivo llamado SchemaEjemplo.xsd con el siguiente contenido:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="personas">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="persona"
                    type="personaType"
                    minOccurs="1"
                    maxOccurs="unbounded" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="personaType">
    <xs:sequence>
      <xs:element name="titulo"
                  type="tituloType"
                  minOccurs="0" />
      <xs:element name="nombre"
                  type="nombreType" />
      <xs:element name="edad"
                  type="xs:integer" />
      <xs:element name="direccion"
                  type="direccionType" />
      <xs:element name="genero"
                  type="generoType" />
    </xs:sequence>
    <xs:attribute name="colorOjos"
                  type="xs:string" />
  </xs:complexType>
  <xs:simpleType name="tituloType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Sr." />
      <xs:enumeration value="Sra." />
      <xs:enumeration value="Señorita" />
    </xs:restriction>
  </xs:simpleType>
  <xs:complexType name="direccionType">
    <xs:sequence>
      <xs:element name="calle"
                  type="xs:string" />
      <xs:element name="numero"
                  type="xs:string" />
      <xs:element name="numeroDepartamento"
                  type="xs:string"
                  minOccurs="0" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="nombreType">
    <xs:all>
      <xs:element name="primerNombre"
                  type="xs:string" />
      <xs:element name="segundoNombre"
                  type="xs:string"
                  minOccurs="0" />
      <xs:element name="apellidos"
                  type="xs:string" />
    </xs:all>
  </xs:complexType>
  <xs:complexType name="generoType">
    <xs:choice>
      <xs:element name="hombre"
                  type="xs:boolean" />
      <xs:element name="mujer"
                  type="xs:boolean" />
    </xs:choice>
  </xs:complexType>
</xs:schema>

La siguiente línea de comando de Visual Studio 2005 genera las clases necesarias:

xsd.exe SchemaEjemplo.xsd /classes /language:CS

El archivo resultante (SchemaEjemplo.cs) se ve algo así como este (solo muestro una parte dado que es muy largo el fragmento de código). Nota que define una clase fuertemente tipada por cada elemento o complexType definido en el Schema:

//------------------------------------------------------------------------------
// 
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.42
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// 
//------------------------------------------------------------------------------
 
using System.Xml.Serialization;
 
// 
// This source code was auto-generated by xsd, Version=2.0.50727.42.
// 
 
 
/// 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class personas
{
 
    private personaType[] personaField;
 
    /// 
    [System.Xml.Serialization.XmlElementAttribute("persona", 
        Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public personaType[] persona
    {
        get { return this.personaField; }
        set { this.personaField = value; }
    }
}
 
/// 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class personaType
{
 
    private tituloType tituloField;
    private bool tituloFieldSpecified;
    private nombreType nombreField;
    private string edadField;
    private direccionType direccionField;
    private generoType generoField;
    private string colorOjosField;
 
    /// 
    [System.Xml.Serialization.XmlElementAttribute(
        Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public tituloType titulo
    {
        get { return this.tituloField; }
        set { this.tituloField = value; }
    }
 
    /// 
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool tituloSpecified
    {
        get { return this.tituloFieldSpecified; }
        set { this.tituloFieldSpecified = value; }
    }
 
    /// 
    [System.Xml.Serialization.XmlElementAttribute(
        Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public nombreType nombre
    {
        get { return this.nombreField; }
        set { this.nombreField = value; }
    }
 
    /// 
    [System.Xml.Serialization.XmlElementAttribute(
        Form = System.Xml.Schema.XmlSchemaForm.Unqualified, DataType = "integer")]
    public string edad
    {
        get { return this.edadField; }
        set { this.edadField = value; }
    }
 
    /// 
    [System.Xml.Serialization.XmlElementAttribute(
        Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public direccionType direccion
    {
        get { return this.direccionField; }
        set { this.direccionField = value; }
    }
 
    /// 
    [System.Xml.Serialization.XmlElementAttribute(
        Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public generoType genero
    {
        get { return this.generoField; }
        set { this.generoField = value; }
    }
 
    /// 
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string colorOjos
    {
        get { return this.colorOjosField; }
        set { this.colorOjosField = value; }
    }
}
 
// ... así continúa ...

Una vez que tus clases han sido generadas es solo cuestión de utilizarlas:

using System;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
 
class Program
{
    static void Main(string[] args)
    {
        // objeto principal
        personas p = new personas();
 
        // declara dos personas
        personaType p1 = new personaType();
        personaType p2 = new personaType();
 
        // poner las propiedades de p1
        p1.colorOjos = "Cafe";
 
        direccionType d1 = new direccionType();
        d1.calle = "Chinches Bravas";
        d1.numero = "123";
        d1.numeroDepartamento = "";
        p1.direccion = d1;
 
        p1.edad = "25";
 
        generoType g1 = new generoType();
        g1.ItemElementName = ItemChoiceType.hombre;
        g1.Item = true;
        p1.genero = g1;
 
        nombreType n1 = new nombreType();
        n1.primerNombre = "Chucho";
        n1.segundoNombre = "El";
        n1.apellidos = "Roto";
        p1.nombre = n1;
 
        p1.titulo = tituloType.Sr;
 
        // poner las propiedades de p2
        p2.colorOjos = "Azul";
 
        direccionType d2 = new direccionType();
        d2.calle = "La laguna";
        d2.numero = "7777";
        d2.numeroDepartamento = "9A";
        p2.direccion = d2;
 
        p2.edad = "15";
 
        generoType g2 = new generoType();
        g2.ItemElementName = ItemChoiceType.mujer;
        g2.Item = true;
        p2.genero = g2;
 
        nombreType n2 = new nombreType();
        n2.primerNombre = "Lola";
        n2.segundoNombre = "La";
        n2.apellidos = "Trailera";
        p2.nombre = n2;
 
        p2.titulo = tituloType.Señorita;
 
        // agregar p1 y p2 al array de personas
        p.persona = new personaType[] {p1, p2};
 
        //
        // serializar la instancia
        //
        XmlSerializer serializador = new XmlSerializer(typeof(personas));
        StringWriter escritor = new StringWriter();
        serializador.Serialize(escritor, p);
 
        Console.WriteLine(escritor.ToString());
    }
}

El resultado:

Bueno, ¿pero qué carajos tiene que ver con Web Services?

Pues sin ahondar mucho en detalles (eso lo haré en otro artículo), resulta que uno de los primeros pasos al crear un Web Service es precisamente definir el formato de los mensajes que se intercambiarán entre el cliente y el servicio (despues de todo, Web Services, visto desde un punto de vista sobre-simplificado no son más que mensajes XML sobre HTTP). ASP.NET y el .NET Framework automáticamente hacen este tipo de conversión de y hacia XML.

También es importante comprender la serialización, porque la siguiente generación de herramientas para servicios (Windows Communication Foundation) utiliza otros mecanismos para transformar tipos de .NET a XML y hay algunas diferencias importantes. Así que solo hemos comenzado con el tema, pero por ahora creo que es suficiente.

Cómo validar tu XML contra un Schema usando .NET

lunes 16 de abril de 2007 | categorías: , , , , , | 1 comentarios -- da clic aquí para dejar el tuyo

En el taller de este mes estábamos utilizando una de mis herramientas preferidas para manejar XML: XMLPad de WMHelp.com, o como yo le llamo, el "Visual Studio para XML".

Sin embargo, parecía que de repente se ponía chiple al intentar validar un documento XML contra un XML Schema. Afortunadamente yo traía por ahí (bueno, por ahí no, porque luego me alburean) una pequeña herramienta que desarrollé hace tiempo, XML Validator.

Este es un programita super sencillo que básicamente toma un documento XML (que pudiera estar en un archivo), e intenta validarlo contra un XML Schema. El programa permite que edites el documento en la primera caja de texto para que puedas sacar las pulgas de tu documento.

Ejemplo de uso de XmlValidator

XML Validator y su código fuente están disponibles para descargarse en: http://comunidadnetjuarez.org/files/folders/ejemplos/entry523.aspx

La mayoría del código, aunque no lo creas, es para manejar los eventos de los botones, etcétera. En realidad el pedazo interesante, el que en realidad hace la validación es el siguiente:

try 
{
    Cursor.Current = Cursors.WaitCursor;
 
    XmlSchemaSet schemaSet = new XmlSchemaSet();
    schemaSet.Add(String.Empty,
        XmlReader.Create(new StreamReader(xmlSchemaFileTextBox.Text)));
 
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.Schemas = schemaSet;
    settings.ValidationType = ValidationType.Schema;
 
    XmlReader reader = XmlReader.Create(
        new StringReader(inputXmlTextBox.Text), settings);
 
    while (reader.Read()) { }
 
    resultTextBox.Text = "Document is valid :o)" +
    DateTime.Now.ToLongDateString();
 
} 
catch (XmlSchemaException schemaEx) 
{
   resultTextBox.Text = "Document is NOT VALID:" +
       Environment.NewLine + schemaEx.Message;
}
catch (Exception ex) 
{
   resultTextBox.Text = ex.ToString();
}
finally
{
   Cursor.Current = Cursors.Default;
}

Como puedes ver, lo único que tienes que hacer es crear un XmlValidatingTextReader e iterar por todo el documento. En la versión 2.0 del .NET Framework, esto se puede lograr utilizando el método Create() de la clase abstracta XmlReader y especificando un objeto XmlReaderSettings con la configuración para el reader. El objeto de settings debe tener especificada la propiedad ValidationType y un XmlSchemaSet, que es la colección de XML Schemas contra las que se validará el documento.

PD. Si no sabes ni de qué $#^%&! estoy hablando con esto de XML Schema, validaciones y todo eso, entonces quizá quieras echarle un ojo al material de la reunión del mes de abril 2007 de la Comunidad .NET de Cd. Juárez.

Editor de code snippets para C# y VS2005

martes 28 de noviembre de 2006 | categorías: , , , | 0 comentarios -- da clic aquí para dejar el tuyo

Hace rato había platicado de la chidez de los code snippets en Visual Studio 2005.

Hoy se me ofreció hacer uno rápidamente. Y aunque es relativamente sencillo hacerlo a pata, en realidad no tenía tiempo de echarme la documentación para hacerlo. Necesitaba un "editor" para sinppets, pero el único que hasta hoy conocía es para Visual Basic 8.

Afortunadamente, este vato se creó un programita llamado Snippy. Puedes descargarlo de aquí.

El programita te genera el archivo .snippet; lo grabas en un directorio debajo de My Documents/Visual Studio 2005/Code Snippets/Visual C# y listo. Ni siquiera tienes que reiniciar Visual Studio.

Usando using

lunes 28 de agosto de 2006 | categorías: , , , , | 4 comentarios -- da clic aquí para dejar el tuyo

El día de hoy aprendí un tip bastante bueno de como usar using gracias a Eber Irigoyen.

Todo comenzó porque él hizo un comentario en el último artículo recalcando la importancia de usar using para TODOS los objetos relacionados con la base de datos (conexiones, comandos, transacciones, etcétera). A mí se me hacía un poco de overkill, pero ahora comprendo que en realidad sí es un buen consejo.

Por si no sabes ni de qué hablo, esta instrucción define un alcance (scope) explícito para un objeto, fuera del cual el objeto es automáticamente "dispuesto" (manda llamar su método Close() o Dispose()), incluso si se levanta una excepción dentro de ese bloque.

Aunque estrictamente hablando no es necesario, ya que hay un scope implícito cada vez que abres y cierras llavecitas en C#, para recursos limitados como conexiones de red, el scope explícito que crea el using ayuda a que el garbage collector reclame esos recursos más fácil y rápidamente.

Si no lo tuvieras, tendrías que hacer todo a punta de bloques try/catch/finally. Eso era algo que no me gustaba de VB 7--bueno VB .NET o "VB 2003", como le quieran llamar. Afortunadamente VB 8 (2005) ya lo trae.

En el artículo original no la quise complicar mucho con esto, pero así quedaría el "patrón de uso de un DataReader" usando try/catch/finally:

string miStringDeConexion =
    @"Data Source=.\SQLEXPRESS;Initial Catalog=AdoNetDemo;" +
    "Integrated Security=True";
string miQuery = "SELECT * FROM Peliculas;";
 
SqlDataReader speedy = null;
SqlConnection miConexion = null;
SqlCommand miCommando = null;
try
{
    // en cualquiera de las instrucciones de este bloque se podría
    // levantar una excepción
 
    miConexion = new SqlConnection(miStringDeConexion);
    miCommando = new SqlCommand(miQuery, miConexion);
    miConexion.Open();
    speedy = miCommando.ExecuteReader();
    while (speedy.Read())
    {
        // hacer mi desmater 
    }
}
catch (SqlException)
{
    // hacer algo para intentar recuperarme o re-lanzar exception
 // si no pienso hacer nada, es mejor omitir el catch
}
catch
{
    // hacer algo para intentar recuperarme o re-lanzar exception
 // si no pienso hacer nada, es mejor omitir el catch
}
finally
{
    // haya o no haya ocurrido excepción, siempre debemos asegurarnos
    // de cerrar las conexiones, DataReaders, etc.
    if (!speedy.IsClosed)
        speedy.Close();
    if (miConexion != null)
        miConexion.Close();
    if (miCommando != null)
        miCommando.Dispose();
}

Como puedes ver, es medio engorroso. Por eso el using es tan cool.

Pero, yo tenía mis reservas, porque cuando tienes varios objetos, es fácil--pensaba yo--que acabes con un chorro de usings anidados, lo cual no me gustaba:

// asumiendo que TipoA, TipoB y TipoC son clases que
// implementan IDisposable
using (TipoA a = new TipoA())
{
    using (TipoB b = new TipoB())
    {
        using (TipoC c = new TipoC())
        {
            // hacer mi desmater
        } // using dispone c
    } // using dispone b
} // using dispone a

Ahora, también sabía que using soporta declarar varios objetos del mismo tipo dentro del paréntesis. Algo así como esto:

// De nuevo, asumiendo que TipoA implementa IDisposable
using (TipoA a1 = new TipoA(), a2 = new TipoA(), a3 = new TipoA())
{
    // hacer mi desmater
} // using dispone a1, a2 y a3

Lo cual no es muy útil cuando tienes objetos de distintos tipos, como en el patrón de uso de un DataReader--donde tienes que usar SqlCommand, SqlConnection y SqlDataReader.

Así que por eso se me hizo tan chido cuando Eber me comentó que using soporta una sintaxis más o menos así:

// asumiendo que TipoA, TipoB y TipoC son clases que
// implementan IDisposable
using (TipoA a = new TipoA())
using (TipoB b = new TipoB())
using (TipoC c = new TipoC())
{
   // hacer mi desmater
} // using dispone a, b y c

De esa forma podría re-escribir el ejemplo de esta forma:

string miStringDeConexion =
    @"Data Source=.\SQLEXPRESS;Initial Catalog=AdoNetDemo;" +
    "Integrated Security=True";
string miQuery = "SELECT * FROM Peliculas;";
 
using(SqlConnection miConexion = new SqlConnection(miStringDeConexion))
using(SqlCommand miCommando = new SqlCommand(miQuery, miConexion))
{
    miConexion.Open();
    using (SqlDataReader speedy = miCommando.ExecuteReader())
    {
        while (speedy.Read())
        { // hacer mi desmater 
        }
    } // using manda llamar speedy.Close()
} // using manda llamar miConexion.Close() y miComando.Dispose()

Ahora, nomás de payaso modifiqué un poco el código para verificar que en realidad se estuvieran mandando llamar los Dispose(), agregando manejadores para el evento Disposed tanto de la conexión como del comando de la siguiente forma:

public static void UsandoUsing() {
 
    string miStringDeConexion =
        @"Data Source=.\SQLEXPRESS;Initial Catalog=AdoNetDemo;" +
        "Integrated Security=True";
    string miQuery = "SELECT * FROM Peliculas;";
 
    using(SqlConnection miConexion = new SqlConnection(miStringDeConexion))
    using(SqlCommand miCommando = new SqlCommand(miQuery, miConexion))
    {
        miConexion.Disposed += new EventHandler(miConexion_Disposed);
        miCommando.Disposed += new EventHandler(miCommando_Disposed);
 
        miConexion.Open();
        using (SqlDataReader speedy = miCommando.ExecuteReader())
        {
            while (speedy.Read())
            { // hacer mi desmater 
            }
        } // using manda llamar speedy.Close()
    } // using manda llamar miConexion.Close() y miComando.Dispose()
}
 
static void miConexion_Disposed(object sender, EventArgs e)
{
    Console.WriteLine("miConexion liberada");
}
 
static void miCommando_Disposed(object sender, EventArgs e)
{
    Console.WriteLine("miComando liberado");
}

¿El resultado?

Oh yeah.

Code Snippets para Visual C# 2005

sábado 4 de marzo de 2006 | categorías: , , , , | 1 comentarios -- da clic aquí para dejar el tuyo

Después de mucho buscar y esperar, finalmente encontré los Code Snippets para Visual C# 2005. Les recomiendo mejor bajarlos todos de un guamazo, en lugar de uno por uno, y luego hagan lo que dice en esta página. Para los que no saben de code snippets, este es un feature de Visual Studio 2005 que te permite insertar un machote (sin albur) de código pre-definido para tareas sencillas y comúnes. Esto facilita enormemente las cosas para la raza que apenas comienza a aprender, ya que con la enorme librería de clases del .NET Framework a veces parece difícil hacer cosas sencillas, como cómo leer un archivo o registrar un evento en el EventLog de la máquina. Los proyectos de VB 2005 ya traen de cajón un montón de snippets, pero si querías hacer lo mismo con C#, te tenías que conformar con unos patéticos para cosasa como for's o if's. Supongo que asumieron que si sabías C# deberías saber lo que estabas haciendo... En fin, lo único que tienes que hacer para usarlos es dar clic derecho en el editor de código... Insert Snippet... y te da un menú para que escojas una tarea de diferentes categorías, como el siguiente ejemplo (dale clic a la imágen para verla bien): Otra alternativa es utilizar el shortcut (atajo pues) del snippet--en el ejemplo de arriba sería appEvent. Del editor de código, comienzas a teclear el shortcut del snippet... el IntelliSense lo reconoce, TAB + TAB--mi nueva combinación favorita--y listo, en menos de 2 segundos tienes tu código. De ahí solo tienes que llenar las cajas resaltadas, y estás listo pa'l baile.