{ WillyXoft .NET }

Blog de Willy Mejía sobre Microsoft .NET Framework y temas relacionados...

<September 2008>
SuMoTuWeThFrSa
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011


Navigation

e-Grupos / Foros

Web/Blog Amigos

INETA & MUGs

Subscriptions

News

Post Categories

Article Categories



Thursday, July 03, 2008 - Posts

WCF bajo contrato (2/4)

Contrato de Datos

WCF emplea, de forma predeterminada, a la clase DataContractSerializer como mecanismo de serialización de datos .NET desde y hacia XML, el cual requiere que los tipos tengan un contrato de datos definido.

Hasta ahora el servicio utiliza tipos simples (string) para el intercambio de datos (en el parámetro de entrada y el valor devuelto) sin ninguna preparación. Esto se debe a que ciertos tipos del .NET Framework, entre ellos los "primitivos", tienen contratos de datos predeterminados. Si lo desea puede consultar la lista de los tipos admitidos por el DataContractSerializer.

En caso que deseáramos utilizar nuestros propios tipos de datos, necesitamos definir tipos complejos. Para ello debemos crear tipos que tengan un contrato de datos definido, lo cual conseguimos aplicando el atributo DataContract a las clases, estructuras y/o enumeraciones a ser serializables por el DataContractSerializer. Además de lo anterior debemos aplicar el atributo DataMember a los miembros que deseemos sean serializables, sin que importe su modificador de acceso.

Continuando con nuestro ejemplo, supongamos que ahora deseamos utilizar los siguientes tipos para el intercambio de datos:

Listado de HelloData.cs

using System;
using System.Runtime.Serialization;

namespace hello.data
{
    [DataContract(Namespace="http://hello/data/")]
    public class Person
    {
        private string firstName;
        private string lastName;

        [DataMember()]
        public string FirstName
        {
            get { return firstName; }
            set { firstName = value; }
        }

        [DataMember()]
        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }
    }

    [DataContract(Namespace="http://hello/data/")]
    public class HelloCard
    {
        private string greeting;
        private int serial;

        [DataMember()]
        public string Greeting
        {
            get { return greeting; }
            set { greeting = value; }
        }

        public int Serial
        {
            get { return serial; }
            set { serial = value; }
        }
    }
}

Nótese que son clases "planas" con los atributos que definen el contrato de datos. Observe también la declaración del espacio de nombre del .NET Framework: System.Runtime.Serialization, a cuyo ensamblado debemos referenciar para compilar HelloData.cs:

>csc /t:library HelloData.cs /r:System.Runtime.Serialization.dll

Una vez definidos los tipos personalizados, ahora definimos el nuevo contrato de servicio, y reescribimos su implementación, como se lista a continuación:

Listado de Hello.cs

using System;
using System.Text;
using System.ServiceModel;
using hello.data;

namespace hello
{
  [ServiceContract(Namespace="http://hello/")]
  interface IHello
  {
    [OperationContract()]
    public HelloCard SayHello(Person person);
  }

  [ServiceBehavior(Namespace="http://hello/", Name="HelloService")] 
  public class Hello : IHello
  {
    private StringBuilder message = new StringBuilder("Hola ");
  
    [OperationContract(Namespace="http://hello/")]
    public HelloCard SayHello(Person person)
    {      
      if (person == null ||
      person.FirstName == null || 
      person.FirstName.Length == 0)
        throw new FaultException("Objeto Person inválido.");
      message.Append(person.FirstName + "!");
     string msg = message.ToString();
     HelloCard card = new HelloCard();
     card.Greeting = msg;
     System.Console.WriteLine(msg);
     return card;
    }
  }
}

Nota: En el código se altera la interfaz del contrato del servicio, cuando en la práctica se debe definir una nueva interfaz e implementarla. Se hizo así para simplicidad del ejemplo.

Ahora compilamos el servicio agregando la referencia al ensamblado generado previamente:

>csc /t:library Hello.cs /r:System.ServiceModel.dll,HelloData.dll

El host y su archivo de configuración permanecen sin cambios, por lo que solo resta ejecutar HelloHost.exe.

Ahora pasamos al cliente. Primero regeneramos los artefactos cliente con svcutil.exe como hasta ahora, y después modificamos el código de la aplicación cliente, tal como se aprecia a continuación:

Listado de Client.cs

using System;

public class Client
{
  static void Main(string[] args)
  {
    String arg = null;
    String result = null;
    if (args.Length > 0) {
      arg = args[0];
    }
    else {
      arg = "Anónimo";
    }
    try {
      hello.IHello service = new hello.HelloClient();
      hello.data.Person person = new hello.data.Person();
      person.FirstName = arg;
      hello.data.HelloCard card = service.SayHello(person);
      result = card.Greeting;
    }
    catch (System.ServiceModel.FaultException fault) 
    { 
      result = fault.Message; 
    }
    catch (Exception ex) {
      result = ex.ToString();
    }
    finally{
      System.Console.WriteLine(result);
    }
  }
}

Compilamos los archivos del proxy y el cliente, y ejecutamos Client.exe como hasta ahora.

Nota: Además de DataContractSerializer, WCF también admite (de forma excluyente) la clase XmlSerializer, que es el mismo mecanismo de serialización utilizado en Servicios Web ASP.NET (aka ASMX). Aunque XmlSerializer solo admite un conjunto reducido de tipos, permite un mayor control sobre el XML resultante y admite mejor la norma de XSD. Para más información consulte Utilización de XMLSerializer.

posted Thursday, July 03, 2008 12:01 PM by vbpuntonet with 0 Comments




Powered by Dot Net Junkies, by Telligent Systems