Windows Communication Foundation–Callbacks [C#]

Hola de nuevo, aquí les vengo a traer nuevo material. Trata de WCF Callbacks.

Que es WCF Callbacks?

Un callback, es un termino muy conocido en programación, al menos yo lo he escuchado seguido. Si has trabajado por ejemplo con javascript y jQuery, sabrás de lo que significan las Callbacks. Una callback es una devolución de llamada, o sea, hay una acción o una llamada a una función inicial que al terminar esa función nos devuelve otra acción. Es como un evento.

Como se observa en la imagen, una llamada a una función del cliente al servicio o servidor, y el servicio llama a una función en el cliente. Esto en WCF son las callbacks.

Se pueden hacer una infinidad de cosas con las funciones callbacks. Imagen dropbox, un cliente desde una computadora sube un archivo (llamada al servidor) y una vez que el archivo se subió, los clientes (en otras computadoras claro) deben descargarlo. El servidor provoca un callback diciendo que se subió un archivo nuevo, se los mandaré a los clientes. Y así todos los clientes comienzan a descargar el archivo que subió un cliente.

Un callback necesita un canal bidireccional, para poder hacer llamadas al servicio y el servicio al cliente. En WCF tenemos distintos bindings que soportan canales bidireccionales, de los que tenemos: wsDualHttpBinding (ideal solo para servidor-servidor) y netTcpBinding (ideal para un cliente detras de NAT y routers).

Es necesario usar TCP para no meternos en problemas con routers y NAT si queremos que un cliente normal se conecte en un canal bidireccional. Http por definición es de un unidireccional pero con wsDualHttpBinding se convierte bidireccional, pero es necesario crear un doble canal (por lo tanto el cliente funcionaria como servidor, es por eso el problema de los routers, NAT, etc).

En fin, comencemos.

Tengo un proyecto recién creado, una aplicación WCF (puede ser con .NET 3.0)

image

 

Este post, supongo que es para experimentados (al menos un poquito) en WCF, podemos borrar el Service que se nos creó o hacer un refactor (recalco… REFACTOR, no un renombramiento normal).

En pocas palabras, tengo mi WCF service que se llama IWcfService, tengo definidos varios datacontract y el callback, que son los siguientes:

IWcfService

image

IMyCallback

image

User

image

Message

image

Todo lo anterior, lo agregué en un solo archivo .cs, uds. decidan si lo separan o no.

Primero que nada tenemos nuestro WebService principal que se llama WcfService, y como se puede ver tiene una propiedad CallbackContract, que es donde le decimos la interfaz que corresponde a nuestro callback.

Tenemos 3 métodos en WcfService, uno para suscribirnos al chat, otro para desuscribirnos y finalmente uno para enviar mensajes. La interfaz IMyCallback tiene un método que tiene la nomenclatura como si se tratase de un evento, OnNewMessage. Evidentemente lo dispararemos cuando se envíen nuevos mensajes.

Los datacontracts simplemente son para enviar datos del cliente al webservice, no hay necesidad de explicarlos.

Archivo IWcfService.cs

image

Ahora, recuerden que al crear el proyecto se nos crearon 2 archivos, la interfaz y el webservice, les dije que hicieran refactor. En mi caso mi WebService se llama WcfService.svc

Entonces, este webservice obviamente utilizará la interfaz IWcfService. La lógica esta fácil, veámosla.

image

A nuestro WcfService le agregamos un comportamiento (ServiceBehavior) y estamos diciendo el modo en que se crearan las instancias de nuestro WebService, en este caso será un WebService singleton, o sea, una sola instancia para todos los clientes.

A su vez creamos una coleccion de IMyCallback, para guardar todos los clientes conectados y mandar a ejecutar las callbacks cuando sea necesario. Recuerden que WCF Callbacks funciona como cliente-servidor servidor-cliente, como si fuera P2P. Es importante recalcar que en este ejemplo estamos usando wsDualHttpBinding para el binding, y como ya lo comente, por definicion Http es one way, por lo que se necesitarian crear dos conexiones, y si queremos crear una aplicación que se comunique a través del Internet será un problema si utilizamos wsDualHttpBinding, para ese caso, será mejor utilizar tcpBinding (por definición es bidireccional) .

Método Subscribe

image

Lo único que hacemos, es obtener el canal Callback que se envía desde el cliente (en el cliente se implementará la Interfaz IMyCallback, mas delante lo veremos). Si la guardamos en una colección, podremos hacer  currentContext[indice].OnNewMessage(“LALALA”); y la función OnNewMessage se ejecutará en el cliente (según como se haya definido en el cliente).

Método Unsubscribe

image

Creo no hay necesidad de explicar.

Método SendMessage

image

Aqui estamos creando una cadena con toda la información que fue enviada desde el cliente (clase Message). Se hace una iteración a todos los elementos guardados en la colección connectedUsers. Por cada cliente se ejecuta el delegate dado por parametro, callback es el elemento actual que se itera de la colección.

Se verifica que el canal siga abierto (Opened) y si es así, se ejecuta la función en el cliente correspondiente al callback, si la conexión se perdió, se elimina de la colección.

Archivo de configuración.

image

Basicamente esta es la implementación para crear Callbacks con WCF, lo tricky se encuentra en el cliente. En el cliente debemos de enviar un InstanceContext que me va a diferenciar de los mas posibles clientes que se conecten. El instanceContext será una instancia que implemente IMyCallback.

Para crear un cliente, creamos un nuevo proyecto en la solución existente, será un proyecto de Winforms con framework 3.0.

image

En el proyecto WcfCallbackClient, agregamos un nuevo Service Reference dando clic derecho en references y en add service reference.

image

En Discover, le decimos que queremos agregar un nuevo WebServices desde la solución y automáticamente detectará el WebService que hemos creado.

En la imagen se ve que el Namespace es ServiceReference2, pero en realidad es con un “1”.

Despues de eso, renombraremos el Form a MainForm.cs como se aprecia en la imagen

image

El MainForm será el mejor diseño de la historia…

image (claro, solo es para explicar… jaja)

app.config

image

Bueno, aqui viene lo tricky.

Una vez creado la asombrosa interfaz grafica, nos vamos al código del MainForm. Crearemos 2 clases mas en este mismo archivo (por simplicidad, lo mejor es separar en archivos diferentes).

image

Tenemos MainForm, la clase clásica que se crea por el formulario, creamos dos clases mas; Sender y Listener.

Sender envia nuevos mensajes y provoca los callbacks. Listener, mantiene un canal abierto y escucha los Callbacks.

Clase Sender

image

La clase utiliza 2 interfaces, IWcfServiceCallback y IDisposable. IWcfServiceCallback fue creado al momento de agregar el Service reference y contiene el método OnNeMessage. IDisposable contiene el método Dispose. El comportamiento que le estamos agregando es el modo de concurrencia, en Reentrant se pueden recibir varios callbacks o algo así (es para poder interrumpir si hay uno en ejecución o algo así).

El clientProxy de la clase WcfServiceClient, es creado al agregar también el Service reference.

    SendNewMessage.

image

Creamos una nueva instancia que se enviará al servicio, y se da por parametro al objeto clientProxy en su constructor (notese que ahora el WcfServiceClient siempre tiene argumentos). la cadena que se da por parámetro es el nombre de la configuración que el service reference nos creó en el app.config.

     OnNewMessage y Dispose.

image

 

Clase Listener y sus métodos.

image

 

Al igual que el anterior, se envía un InstanceContext (en el método BeginConnection), pero este manda a llamar el método Subscribe, este guardará InstanceContext en la colección del WebService. Aquí si esta implementado OnNewMessage, este método se ejecutará cuando sea llamado en el ForEach que se encuentra en el WebService.

Dispose, elimina el InstanceContext de la colección del Servidor y cierra el Proxy.

Clase MainForm.

image

Aquí tenemos los eventos de los botones y el Form y su código correspondiente (simplemente son llamadas a los métodos de Listener y Sender).

Una vez que se mande a llamar el método BeginConnection, el cliente estará disponible para recibir mensajes por medio de un Callback.

Compila y corre el WebService y 2 clientes y has la prueba.

image

image

Código fuente: WcfCallbacksProject

 

Saludos! y feliz navidad Risa.

Anuncios

7 comentarios sobre “Windows Communication Foundation–Callbacks [C#]

  1. ola isaac me gustaria saver si tienes algun conocimiento sobre la utilizacion de sockets sucede que kiero hacer una coneccion lan y kiero manipularlos con wake on lan y kisiera hacerlo en c#
    saludos!!!

  2. Hola, muy bueno el ejemplo!.
    Estoy probandoló y estoy con un par de problemas, te lo cuento para ver si me podes ayudar.
    En principio tuve que agregar clientBaseAddress en el binding (wsDualHttpBinding) ya que cada vez que lo ejecutaba me marcaba el error de HTTP no pudo registrar la dirección URL http://+:80/Temporary_Listen_Addresses/.
    Una vez aplicado eso yo pude al menos conectarme al servicio sin problemas.
    Quise pasarselo a un compañero de trabajo para probarlo (estamos en lan de la empresa y no hay router entre nosotros.)
    Pero el no llega a conectarse, cuando arme la referencia en el cliente no utilice localhost sino que utilice la ip de mi maquina.

    Podrías dejarme algun tip como para ver por donde puede venir el problema?
    Las pruebas q vos hiciste utilizaste el clientBaseAddress?

    Saludos

    1. Para que funcione wsDualHttpBinding se necesita que los dos funcionen como clientes y servidores, por lo tanto en el cliente debes de abrir el puerto que vas a utilizar. El servicio de WCF debe ser hospedado en un servidor IIS (en este ejemplo, lo corro desde IIS express, que es para puro desarrollo) por lo tanto será el puerto 80 (el default) o el que tu eligas, ese puerto como te acabo de mencionar, debe de ser abierto en el cliente. Otra opción es que uses tcpBinding en vez de wsDualHttp, pero eso requiere de configuración adicional al querer implantarlo en un IIS.

      Saludos!

  3. Disculpa estuve leyendo acerca de esto y deseo que el cliente deje de usar el puerto 80 para hacer el callback como lo logro?

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s