Blog de Oxxigeno


Nuevas Tecnolog铆as – Windows Comunication Foundation

Escrito por Israel Vi帽uales en .NET, Desarrollo

Este nuevo modulo incluido en el .NET Framework 3.5 establece un modelo de programaci贸n unificado para la implementaci贸n de sistemas distribuidos, especialmente orientado a servicios.

Esta tecnolog铆a integra en una 煤nica metodolog铆a de programaci贸n las hasta ahora incompatibles COM+ (Serviced Components), .NET Remoting y Servicios Web. Para ello, un servicio WCF debe definir una serie de puntos de acceso (denominados EndPoints) que representan una puerta de entrada al servicio publicado, permitiendo as铆 que un mismo servicio sea consultado mediante distintos tipos de comunicaci贸n.
Los EndPoints deben presentar:

  • Direcci贸n: representada por la clase EndPointAddress, indica d贸nde est谩 la aplicaci贸n
  • Enlace: representada por la clase Binding, indica c贸mo se puede accesar esa aplicaci贸n: Protocolo del transporte, Codificaci贸n y Seguridad.
  • Contrato: representada por una clase con atributos de tipo ServiceContractAttribute, se trata de una definici贸n de los datos que van a ser comunicados por el aplicativo.

WCF utiliza mensajes SOAP para la comunicaci贸n de estos datos, siguiendo as铆 un est谩ndar de comunicaci贸n. Sin embargo, cuando se realiza una comunicaci贸n entre dos procesos WCF se optimiza esta comunicaci贸n, aplicando una codificaci贸n en formato binario para los mensajes SOAP. De esto podemos olvidarnos totalmente, ya que al fin podemos crear un servicio sin preocuparnos de c贸mo ni qui茅n va a acceder a 茅l.

Vayamos con un ejemplo y veamos si es realmente lo que nos venden. Creamos una interfaz y una entidad que ser谩n las que utilizaremos para dar vida al servicio.

[ServiceContract]
    public interface IExample
    {
        [OperationContract]
        string GetData(int value);
 
        [OperationContract]
        ExampleType GetDataUsingDataContract(ExampleType composite);
 
        [OperationContract]
        string[] GetNames();
    }
 
    [DataContract]
    public class ExampleType
    {
        bool _delete = false;
        string _name = "Name";
 
        [DataMember]
        public bool Delete
        {
            get { return _delete; }
            set { _delete = value; }
        }
 
        [DataMember]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
    }

Los atributos DataContract y OperationContract son, para entendernos, los atributos que sustituyen a WebService y WebMethod. Mientras que los atributos DataContract y DataMember son los atributos que servir谩n para serializar las entidades que se publicar谩n a trav茅s del servicio.

Ahora, una vez creada la interfaz que publicar谩 el servicio y la entidad, procedemos a implementar la funcionalidad del servicio.

public class ExampleService : IExample
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
 
        public ExampleType GetDataUsingDataContract(ExampleType composite)
        {
            if (!composite.Delete)
            {
                composite.Name += " y Apellido";
            }
            return composite;
        }
 
        public string[] GetNames()
        {
            List<string> lista = new List<string>();
            for (int i = 0; i < 5; i++)
            {
                lista.Add("nombre" + i.ToString());
            }
            return lista.ToArray();
        }
    }

Con esto ya tenemos el c贸digo necesario para crear un servicio con WCF. Nos falta darle posibles puntos de entrada, para poder publicarlo. Lo hacemos a trav茅s del web.config del servicio.

<system.serviceModel>
    <services>
      <service name="Namespace.ExampleService" behaviorConfiguration="Namespace.ExampleServiceBehavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="wsHttpBinding" contract="Namespace.IExample">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Namespace.ExampleServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Voy a intentar explicarlo de forma esquem谩tica. Dentro de la etiqueta 鈥渟ervices鈥 creamos cada uno de los servicios que queramos publicar, mientras que dentro de la etiqueta 鈥渂ehaviors鈥 definiremos diferentes comportamientos que podr谩n utilizarse en los servicios publicados.

Pero volvamos a la etiqueta 鈥渟ervices鈥. Dentro de ella crearemos tantas etiquetas 鈥渟ervice鈥 como servicios queramos publicar. Cada una se define mediante nombre y comportamiento (鈥渘ame鈥 y 鈥渂ehaviorConfiguration鈥). Adem谩s debemos definir una serie de puntos de entrada (鈥渆ndpoint鈥) con las propiedades 鈥渁ddress鈥, 鈥渂inding鈥 y 鈥渃ontract鈥, y un nodo interno de tipo 鈥渋dentity鈥 (como se ve en el c贸digo). Vamos con ellos:

  • Etiqueta Service:
    • Address: Especificamos la URI, que puede estar como cadena vac铆a.
    • Binding: Especificamos el binding a utilizar, lo cual define el tipo de transporte, la seguridad y el encoding utilizado. Podemos utilizar un binding definido por nosotros.
    • Contract: Especifica la interfaz que define se publicar谩 con el servicio.
  • Etiqueta Behavior:
    • Name: Nombre del behavior, 煤nico en el web.config
    • ServiceMetadata: Especifica la publicaci贸n de los metadatos del servicio y de la informaci贸n asociada.
    • ServiceDebug: Especifica las caracter铆sticas de la informaci贸n de depuraci贸n y de la ayuda para un servicio de la WCF.

Para una descripci贸n m谩s detallada podemos recurrir a la siguiente url de Microsoft: http://msdn.microsoft.com/en-us/library/ms733932.aspx

Respecto al cliente, su uso es tan sencillo como agregar la referencia al servicio a la solucion e invocarlo desde el c贸digo.

Al agregar la referencia al servicio podemos ver que el web.config ha sido modificado, a帽adiendo la configuracion necesaria para accesar dicho servicio. Veamos qu茅 ha a帽adido:

<system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IExample" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:3153/ExampleService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IExample"
                contract="ExampleServiceReference.IExample" name="WSHttpBinding_IExample">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>

脡l solo ha creado todo el arbol de etiquetas de configuracion necesario para acceder al servicio mediante el endpoint que deseemos. Si nos fijamos en la etiqueta 鈥渆ndpoint鈥 dentro de 鈥渃lient鈥 podemos ver c贸mo ha agregado la direccion del servicio, el tipo de binding, la configuracion del mismo, la interfaz que presenta y el nombre (que es lo que utilizaremos para crear el objeto client en c贸digo):

ExampleClient clientDefault = new ExampleClient("WSHttpBinding_IExample");
            string[] namesDefault = clientDefault.GetNames();

Vamos a crear otro endpoint en el web.config del servicio y vamos a refrescar la referencia en el cliente para ver c贸mo cambia el web.config, a帽adiendo el nuevo endpoint y veremos c贸mo referenciarlo. Agregamos dos endpoints:

 <endpoint address="Soap11" contract="Namespace.IExample" binding="basicHttpBinding"/>
            <endpoint address="Soap12" contract="Namespace.IExample" binding="wsHttpBinding"/>

Y refrescamos la referencia al servicio en el cliente. Miramos el web.config y descubrimos que tenemos nuevas formas de acceder al servicio:

 <endpoint address="http://localhost:3153/ExampleService.svc/Soap11"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IExample"
                contract="ExampleServiceReference.IExample" name="BasicHttpBinding_IExample" />
            <endpoint address="http://localhost:3153/ExampleService.svc/Soap12"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IExample"
                contract="ExampleServiceReference.IExample" name="WSHttpBinding_IExample1">
                <identity>
                    <userPrincipalName value="ivinuales@oxxigeno-networks.spain" />
                </identity>
            </endpoint>

Adem谩s, nos ha creado una nueva entrada dentro de bindings:

<basicHttpBinding>
                <binding name="BasicHttpBinding_IExample" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
                </binding>
            </basicHttpBinding>

De tal forma que ahora en el c贸digo fuente podemos instanciarlo de 3 formas distintas:

            ExampleClient clientDefault = new ExampleClient("WSHttpBinding_IExample");
            string[] namesDefault = clientDefault.GetNames();
 
            ExampleClient clientSOAP11 = new ExampleClient("BasicHttpBinding_IExample");
            string[] namesSOAP11 = clientSOAP11.GetNames();
 
            ExampleClient clientSOAP12 = new ExampleClient("WSHttpBinding_IExample1");
            string[] namesSOAP12 = clientSOAP12.GetNames();

Deja un comentario


Nuestras oficinas:

Oxxigeno Espa帽a
C/Luchana, 23. 28010 - Madrid
Tel.: 91 144 12 00
Fax: 91 144 12 01
E-mail:

Oxxigeno France
77, rue La Bo毛tie. 75008 - Paris
Tel.: +33 (0)1 45 61 68 99
Fax: +33 (0)1 45 61 51 05
E-mail: