Welcome to Comunidad .NET de Cd. Juárez Sign in | Join | Help

April 2007 - Posts

Presentación y material de WCF y CardSpace disponibles

El jueves pasado me tocó dar una de las pláticas durante el ProNet CodeCamp que tuvimos junto con Microsoft en la Comunidad .NET de Cd. Juárez. El tema fue Windows Communication Foundation y Windows CardSpace.

Estuvo bastante divertido. WCF es una de las tecnologías del .NET Framework 3.0 que más me gusta porque a pesar de que es un poco abstracta, habilita la infraestructura necesaria para orientación a servicios, las nuevas especificaciones de Web Services, etcétera. De hecho tengo planeado un par de posts, o incluso un screencast para tratar el tema y compararlo con Web Services "clásicos" usando ASP.NET.

Para mi sorpresa, CardSpace fue el que pareció generar más interés y preguntas en el público, sobre todo cuando vimos el demo de cómo integrarlo a una aplicación de consola con WCF.

En fin, aún no hemos publicado una reseña del evento completo, pero por lo pronto ya están disponibles la presentación y demostraciones que utilicé en la sección de archivos del sitio de la Comunidad. Pueden descargar el material de la siguiente dirección:

http://comunidadnetjuarez.org/files/folders/presentaciones/entry575.aspx

Para que funcionen los ejemplos de CardSpace es necesario tener instalados ciertos certificados digitales en la máquina que están corriendo. Para no batallar mucho, te recomiendo correr los scripts de instalación que vienen en el .NET Framework Training Kit para WF, WCF y CardSpace. Este kit está genial porque trae demos y hands-on labs para estas tres tecnologías, y puedes ver una agenda de aprendizaje por día o por tecnología.

También aproveché la ocasión para subir la presentación y demostraciones que utilicé el año pasado en el Microsoft Developer Community Day. El tema en aquella ocasión fue Desarrollo con .NET 3.0, la evolución del .NET Framework, que es una buena introducción a lo que tiene esta versión del framework. Ese material esta disponible aquí:

http://comunidadnetjuarez.org/files/folders/presentaciones/entry574.aspx

Finalmente, alguien me pidió que si podía también poner aquí los enlaces que recomendé en las presentaciones. Aquí estan, más algunos otros que no incluí en la presentación:

Para WCF:
Para CardSpace:
Enjoy.

El Otro Lado del Kamikaze cambia a Diario de un Dotnetero

Recientemente estuve analizando las estadísticas de este blog y me di cuenta que algunos de los artículos que he escrito (como ADO.NET para novatos y Cómo leer archivos planos con .NET) reciben 30 o 40 visitas diarias. Esto no solo me dio mucho gusto, sino que me motivó a hacer este blog un poquito más "formal".

El título original venía del hecho de que 1) mi nick, desde la era de BitNet siempre ha sido Kamikaze y 2) "El Otro Lado" era para diferenciarlo del primer blog que comencé a escribir, A Kamikaze Thought.

Sin embargo, creo que la dirección URL y el título no eran tan descriptivos a los temas que trato aquí. Así que para facilitar un poco las cosas y ayudar con la difusión compré el dominio Dotnetero.com y he decidido cambiarle el título a Diario de un Dotnetero. Un cambio pequeño, pero creo que necesario.

Si tienes bookmarks a los artículos de este blog, no hay de qué preocuparse, Blogger automáticamente redireccionará las peticiones a las direcciones nuevas. El feed del blog también permaecerá en la misma dirección, http://feeds.feedburner.com/ElOtroLado
Posted from Diario de un Dotnetero | 0 Comments
Filed under: ,

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

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 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 ...

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 automáticamente hace este tipo de serialización hacia XML.

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

Que NO hacer cuando encuentres el floppy de tu cónyuge

Cortesía de The Humor Archives:


[pegado al refri con un imán] "Hola cariño, encontré el disco que estabas buscando ayer tan frenéticamente"

Posted from El otro lado del Kamikaze | 0 Comments
Filed under:

Community Server cambia de versión, esquema de licenciamiento

La semana pasada Telligent lanzó la nueva versión de CS, Community Server 2007.  Yo tenía la esperanza de hacerle upgrade a la instalación que tenemos en el sitio de la Comunidad .NET de Cd. Juárez, ya que ofrece muchas mejoras en lo que menos me gustó de la versión 2.1 del producto: personalización.

Desgraciadamente, como acostumbran hacerlo con cada versión mayor, cambiaron de nuevo el esquema de licenciamiento.  Anteriormente, las versiones "gratis" (p.ej. la Personal o la Community), eran básicamente lo mismo menos algunos features como la capacidad de producir reportes de uso, de integrar con NNTP, FTP, Single Sign-On, etc.  lo cual era más que aceptable.

Ahora la versión Personal ya no es gratis, cuesta $99 dlls, lo cual no está mal, pero no puede ser utilizada por organizaciones de no-lucro (como nuestra Comunidad), solo por individuos.  La versión Community (que no sé si resurgió de los muertos porque hacía rato que no la veía) sigue siendo gratuita y ahora tiene todos los features, pero está limitada en la cantidad de cosas que soporta: máximo 10 blogs, 15 foros, 100 archivos y 10 galerías de fotos y sin capacidad de mirroring (agregar contenido de blogs externos).  Todo esto sin posibiliad de agregarle licencias adicionales para hacer un "upgrade".

En mi (no tan) humilde opinión, esto le quita bastante la atractividad del producto para comunidades que quieren iniciar, a menos que sean muy, muy pequeñas.  Para nosotros probablemente significa no hacer upgrade, ya que la versión que probablemente se nos acomodaría es la Professional y esa ya anda en $1500 dólares.  Osea que olvídate del concepto de iniciar tu comunidad con menos de $100.

Cuando originalmente ajustaron sus planes de licenciamiento, mencionaron que grupos que promueven .NET eran elegibles para licencias gratis para la version Professional, pero aún no he podido encontrar información al respecto.  Si averiguo algo, luego se los comento.

En fin.  Creo que si recibes algo gratis no tienes muchos derechos de reclamar, ¿o sí? 

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

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.

De vuelta

Tuve un mes muy agitado debido a bronquillas personales, así que no había tenido oportunidad de publicar nada en un buen rato. Y lo poco que escribí se fue al blog de noticias de la Comunidad. Nada notable, excepto quizá por el artículo Cómo iniciar el sitio de tu comunidad con menos de 100 dólares.

Mañana, lunes 9 de abril, me toca dar la plática de abril para la Comunidad. Hicimos una encuesta para ver qué tema le interesaría más al público y el ganador fue Manejo de XML con .NET. Este será un tema con nivel principiante-intermedio que cubrirá las pricipales especificaciones (XML, XML Schema, XPath y XSLT) y las facilidades te da el .NET Framework para manejarlas.

XML es de las tecnologías que más me gustan simplemente por la cantidad de problemas que resuelve, sobretodo en lo que se refiere a la famosísima "interoperabilidad". Y dado que es la base para otras (Web Services, anyone?) pues se me hace indispensable que al menos tengamos una idea de qué es y con qué se come.

Originalmente preparé ese tema para un curso de .NET que me inventé hace como año y medio. La sesión sobre XML y .NET estaba hecha para 8 horas, así que obviamente veremos una versión súper-abreviada del aspecto teórico en la reunión y ya en el taller del sábado profundizaremos con práctica y código. Tengo planeado hacer disponible tanto la versión completa de la presentación así como la abreviada y los ejemplos de código en el sitio de la Comunidad, así que estén atentos a eso.

Por otro lado, también voy a ser uno de los speakers en el Pronet Codecamp que estamos organizando junto con Microsoft para el jueves 26 de abril. Parece que me va a tocar el tema de Windows Communication Foundation, lo cual me tiene bastante emocionado. Pueden encontrar todos los detalles del evento en la página principal de la comunidad o en el blog del Pelos.

¡Espero verlos ahi! smile_shades

Posted from El otro lado del Kamikaze | 0 Comments
Filed under: