sábado, 22 de diciembre de 2012

WSDualHttpBinding - Ejemplo sobre como usar WCF Dúplex (servidor)

En el artículo de hoy veremos un ejemplo paso a paso sobre como usar WCF Dúplex. ¿Qué nos permite WCF Dúplex? Por ejemplo, tenemos implementada una solución servidor que accede a negocio/datos y por otro lado tenemos aplicaciones cliente que intercambian información con el servidor vía servicios WCF. Podríamos definir un servicio de notificaciones en servidor que avise los clientes interesados cuando se produzcan determinados eventos que les afectan en servidor.

Necesitaremos 3 soluciones; AreaTicServer, AreaTicClient y AreaTicShared.
  • AreaTicServer: Imaginemos que es una solución que expone diversos servicios WCF a los que acceden un número considerable de clientes y llevan a cabo acciones sobre la base de datos. Aquí implementaremos el servicio Duplex y simularemos algún evento para este ejemplo que devuelva notificaciones a los clientes que se han "suscrito".

  • AreaTicClient: Simularemos un cliente, aquí ubicaremos el código que conectará al servicio dúplex a modo de suscriptor y recibirá notificaciones cuando se produzcan eventos clave en servidor.

  • AreaTicShared: Es una biblioteca de clases que contiene clases/interfaces que se usarán en el intercambio de información entre cliente y servidor. Hemos de añadir este proyecto como referencia en ambas soluciones.

En primer lugar atacaremos el código compartido, necesitaremos crear un tipo (clase) Notification que usaremos en el intercambio.
namespace AreaTicShared.Duplex
{
    [DataContract]
    public class Notification
    {
        [DataMember]
        public int CodigoUsuario { get; set; }
        [DataMember]
        public NotificationType Tipo { get; set; }
        [DataMember]
        public string Detalle { get; set; }
    }
   
    public enum NotificationType
    {
        TipoNotificacion1,
        TipoNotificacion2
    }
}
Definiremos también en esta librería la interfaz para el CallBack, es importante incluir la referencia de esta dll tanto en Servidor como en Cliente ya que estas clases se usarán en ambas soluciones (hemos creado una tercera solución para evitar duplicar código).
namespace AreaTicShared.Duplex
{
    interface IServerNotificationsCallBack
    {
        [OperationContract(IsOneWay = true)]
        void RecibeNotificaciones(List<Notification> pListaNotificaciones);
    }
}
Ya hemos definido el contrato de CallBack, es importante fijarse en los atributos IsOneWay que son necesarios para este tipo de comunicación Dúplex. Veamos ahora como implementar el servicio dúplex, para ello como en todo servicio WCF necesitaremos una clase interfaz (servicecontract) y una clase que la implemente. La interfaz la definiremos en AreaTicShared porque se compartirá con la solución cliente. Es importante especificar el atributo CallBackContract.
namespace AreaTicShared.Duplex
{
    [ServiceContract(CallbackContract = typeof(IServerNotificationsCallBack))]
    interface IServerNotifications
    {
        [OperationContract(IsOneWay = true)]
        void SubscripcionListaNovedades(int pIdCliente);
    }
}
Crearemos ya en servidor una clase que se encargue de almacenar una lista persistente de suscripciones cliente (IdCliente,CallBackReference) a la que iremos añadiendo o quitando elementos en función de los clientes suscritos. Nos vale con un diccionario definido con el modificador static.
namespace WCFDuplexServer.Services
{
    public static class GestionCallBackClientes
    {
        public static Dictionary<int, IServerNotificationsCallBack> CallBackClientRelation = new Dictionary<int, IServerNotificationsCallBack>();
    }
}
El siguiente paso es crear un archivo ServerNotifications.cs que implemente la interfaz IServerNotifications.
namespace AreaTicServer.Services.Duplex
{
[ServiceBehavior(InstanceContextMode= InstanceContextMode.PerCall)]
public class ServerNotifications : IServerNotifications
{
  #region Miembros de IServerNotifications

   public void SubscripcionListaNotificaciones(int pIdCliente)
   {
     try
     {
      // Guardamos la referencia de callback en un lista persistente para utilizarla cuando sea necesario.

        if (!GestionCallBackClientes.CallBackClientRelation.ContainsKey(pIdCliente))
        {
          GestionCallBackClientes.CallBackClientRelation.Add(pIdCliente, OperationContext.Current.GetCallbackChannel<IServerNotificationsCallBack>());
        }
     }
     catch (Exception ex)
     {
       throw ex;
     }
  }

  #endregion
 }
}
En cualquier punto de la solución servidor podríamos usar el diccionario del siguiente modo para devolver información al cliente que creamos oportuno. Por ejemplo, vamos a ver como le pasaríamos una lista de notificaciones al cliente con id 2.
public void Evento()
{
  List<Notification> notificaciones = new List<Notification>();

  notificaciones.Add(new Notification(){ CodigoUsuario = 2, Detalle = "Se ha producido un evento en servidor que podría afectarle",Tipo=NotificationType.TipoNotificacion1});

 GestionCallBackClientes.CallBackClientRelation[2].RecibeNotificaciones(notificaciones);

}
Por último veremos como configurar el binding/endpoint para nuestro servicio por código que hemos de asegurarnos que se ejecute al iniciar la aplicación o web (la alternativa es añadir la configuración en app.config/web.config del proyecto).
mHost = new ServiceHost(typeof(IServerNotifications));
mHost.AddServiceEndpoint(typeof(IServerNotifications), new WSDualHttpBinding(), "http://personalizarURL:2100");
Hasta aquí el ejemplo de hoy, la semana que viene veremos como implementar la parte dúplex en cliente que se suscribirá al servicio de notificaciones y gestionaremos el callBack en caso de que nos llegue una lista de notificaciones procedentes del servidor. Os recordamos que podéis seguir areaTIC en las redes sociales!


2 comentarios:

Tonny dijo...

Muy buen articulo, la verdad es que habia buscado y hasta ahora encontre buena informacion sobre el tema... sin embargo lo unico que no he podido configurar es el binding/endpoint porque pongo una direccion http://localhost:8080/servicio y no esta disponible a ver si me pueden ayudar en que estare mal. Gracias

Carlos Cañizares dijo...

Buenas Tonny, me alegra que te haya sido útil. Si te he entendido tienes problemas para levantar el servicio ¿verdad? al hacer el host.Open()... Creo que ya se a que excepción te refieres me ha pasado alguna vez.
Me parece recordar que si ejecutas Visual Studio o directamente la aplicación como Administrador de sistema te dejará levantar el servicio.

En caso que no sea este problema envíame si quieres a c.canizaresestevez@gmail.com con un poco más de información y el detalle de la excepción que se produce.

Saludos!

Publicar un comentario