miércoles, 17 de septiembre de 2008

Introducción a WCF ABC, con cliente ASMX

WCF

Windows Comunication Foundation es un SDK para desarrollar servicio de Microsoft, es parte del framework 3, necesita framework 2 y el framework 3.5 agrega algunas extensiones como el soporte para servicios REST.

La idea principal detrás de WCF es un modelo unificado de desarrollo de servicios independiente de detalles de implementación como el protocolo de transporte, la seguridad, etc

Entonces podemos tener un único servicio programado de una manera particular y exponerlo de diferentes formas, cada punto de contacto con el exterior de un servicio en WCF se conoce como Endpoint. Por lo tanto decimos que un servicio WCF tiene un numero de Endpoints, cada cual diferenciado por dirección, puerto, protocolo de transporte, etc.

El ABC

Cada vez que veamos una introducción a WCF vamos a ver que se habla del ABC, esto es,

A: Address, la dirección del servicio. Está relacionado obviamente con el protocolo, ya que si es http seguramente el address comenzará con http.

B: Binding, el protocolo de transporte o mejor dicho el esquema de transporte porque es algo más que el protoloco, entre ellos HTTP, TCP, Named pipes, MSMQ, etc.

C: Contract, el contrato, es decir las acciones y tipos que expone el servicio.

Hosting

Seguramente se están preguntando cómo "hostear" los servicio, bien, hay un par de alternativas, IIS, en una aplicación .net cualquiera (un servicio de windows, una aplicación de consola) o con WAS (Windows activation service), en estos ejemplos vamos a utilizar una aplicación de consola .net.

Vamos a los bifes.

Como no me gusta dar vueltas, me parece que lo mejor es ver cómo hacemos para crear un servicio y tener varios Endpoint (por ahora uno y lo vamos a ir modificando en otros posts). Antes que nada necesitamos Visual Studio 2005 + la extensiones para framework 3 o directamente cualquier versión de Visual Studio 2008.

Agregamos el assemblie System.ServiceModel.dll y listo, veámos el código auto-descriptivo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace PruebaWCF
{
    /// <summary>
    /// Con ServiceContract indicamos que éste es un contrato de servicio
    /// </summary>
    [ServiceContract]
    public class MiServicio
    {
        /// <summary>
        /// Con OperationContract indicamos que esta operación es un operación del servicio
        /// </summary>
        [OperationContract]
        public string Saludo(string nombre)
        {
            return string.Concat("Hola ", nombre);
        }
    }
}}

Como vemos es una simple clase con un par de atributos para indicar algunas cosas al WCF ( más adelante vamos a ver que es más interesante extraer la interface con los atributos pero por ahora lo dejamos así para que se más fácil).

Con esto tenemos el servicio terminado, sólo falta "hostearlo", vamos a ver cómo se hace y cómo configuramos los bindings, behaviors, endpoints y etc./p>

Hosteando nuestro primer servicio WCF

Para el primer ejemplo vamos a utilizar un Binding que nos permite utlizar este servicio con un cliente .net 2.0 clásico, el binding que nos permite esto es el BasicHttpBinding.

La configuración

La configuración es un tema medio pesado, ya que hay muchas cosas que configurar (cuanto más flexible mas complejo), si bien se han agregado algunos "factories" para facilitar la creación de servicios cuando se "hostean" en IIS, nosotros por el momento vamos a ver alguinos ejemplos sencillos. La configuración puede hacerce por código o por archivo de configuración, la segunda opción permite más flexibilidad ya que podemos cambiar muchas cosas sin recompilar como agregar un registro de sucesos, autenticación, endonints, etc. si bien no todo se puede hacer por configuración es un poco pesado el tema, por lo tanto vamos a ver los ejemplos haciéndolo por código que de paso quedan más claros los conceptos.

Behaviors

Lo último que voy a contar antes del código es sobre los behaviors o comportamientos, hay de dos niveles, de nivel servicio (afectan a todos los endpoints) y a nivel endpoint, qué permiten hacer? por ejemplo registrar los mensajes, publicar la metadata, algo personalizado, etc.

Ahora sí, el código de nuestro host

namespace PruebaWCF
{
    class Program
    {
        static void Main(string[] args)
        {
            string uri = "http://localhost:8080/servicio/";

            using(ServiceHost host = new ServiceHost(typeof(MiServicio)))
            {
                //definimos un endpoint para el servicio del tipo
                //basicHttpBinding que es compatible con servicios asmx
                //como vemos en la forma más sencilla sólo necesitamos 2 líneas
                //de código para configurar un servicio WCF
                ServiceEndpoint endPoint = new ServiceEndpoint(
                        ContractDescription.GetContract(typeof(MiServicio)),
                        new BasicHttpBinding(), new EndpointAddress(uri));

                host.Description.Endpoints.Add(endPoint);

                //este comportamiento indica que se va a publicar la metadata del servicio
                //para poder generar el proxy desde el lado del cliente más facilmente
                //una vez que tenemos el proxy generado no es necesario esto
                ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                behavior.HttpGetEnabled = true;
                behavior.HttpGetUrl = new Uri(uri);

                host.Description.Behaviors.Add(behavior);

                //por último abrimos el host
                host.Open();

                Console.WriteLine("iniciado..");
                Console.ReadLine();
                //cuando se presiona enter ser cierra el servicio
                host.Close();
                Console.WriteLine("finalizado..");
            }
        }
    }
}

La clase ServiceHost se encarga de "hostear" nuestro servicio, entonces creamos un Endpoint con:

Contrato: ContractDescription.GetContract(typeof(MiServicio))

Binding: BasicHttpBinding para que sea compatible con un cliente asmx

Address: new EndpointAddress(url)

Los agregadomos al host con host.Description.Endpoints.Add(endPoint)

y listo, ya funciona haciendo host.Open().

Le agregué el ServiceMetadataBehavior para que se publique la metadata del servicio apra poder generar el proxy desde Visual Studio 2005 con un cliente asmx, después se puede quitar este behavior y diría que es casi recomendable, un detalle es que puedo publicar la metadata en otra url, yo lo hice en la misma por comodidad.

Consumiendo un servicio WCF desde ASMX

Y llegamos a la parte interesante, si tuvieramos un servicio publicado cuyos clientes con asmx y se nos ocurre actulizarlo a WCF por motivos valederos (como por ejemplo porque es más lindo) nada está perdido, el servicio que acabamos de generar es compatible con asmx y lo vamos a demostrar.

Agregamos la referencia como simpre

Un poco de código del lado del cliente para invocar al servicio WCF

class Program
{
    static void Main(string[] args)
    {
        WCFService.MiServicio servicio = new WCFService.MiServicio();
        Console.WriteLine(servicio.Saludo("leonardo"));

        Console.ReadLine();
    }
}

Y listo, mágico.Hasta la próxima

Referencias:

Visión global de la arquitectura de WCF MSDN

ABC de la programación de WCF

3 comentarios:

marianoams dijo...

Muy buen artículo como para iniciar el aprendizaje con un ejemplo sencillo. Gracias por publicar estas cosas.

Leonardo Micheloni dijo...

Gracias a vos por dejar tu comentario.

Fernando dijo...

Buen articulo, solo una duda, configurando binding="basicHttpBinding" es iagual a un servicio web asmx con protocolo SOAP 1.1, y si configuro el binding="wsHttpBinding" en este caso ya es distinto a los asmx, aqui los clientes que consumen un servicio web asmx se tendrian que modificar para que consuman el servicio de WCF y son protocolo SOAP 1.2