¿Servicios Web Polimórficos? (Parte 2 – Solución con WCF y Framework 3.5)

Hace ya bastantes artí­culos atrás estuvimos hablando de Servicios Web y Polimorfismo (aquí­). Introdujimos el tema y le dimos alguna vuelta a la necesidad de poder aplicar el concepto de polimorfismo a las llamadas de un servicio web. Es más, incluso lo intentamos utilizando Servicios Web en .NET mediante el Framework 2.0… y… comprobamos que no era posible.
Quedaron abiertas otras soluciones, pero hasta el momento no habí­a podido invertir tiempo en este tema, así­ que ahora que ya tengo algo que mostraros, allá vamos!
Para empezar, como habréis podido observar la solución parte del uso de WCF (Windows Communication Foundation). En concreto para la solución he empleado Visual Studio 2008 y el Framework 3.5 (remarco lo de la versión del Framework, ya que esta misma solución utilizando el WCF y el Framework 3.0 no os va a funcionar, ya que no se hace igual). Estamos de suerte y la solución con el Framework 3.5 la verdad es que es sencillí­sima.
Paso a mostraros fragmentos de código sueltos y luego os adjuntaré el proyecto para que podáis ver y probar vosotros mismos que funciona. Eso sí­, avanzo que el código del proyecto es simplemente para probar el funcionamiento así­ que le faltarán comentarios y demás cosas que intentaré añadir directamente aquí­.
Bien, antes de nada empezar diciendo que voy a intentar seguir la guí­a del primer intento que hicimos de Servicios Web Polimórficos, en la que la idea era conseguir tener un íºnico Servicio Web que nos ofreciera la posibilidad de realizar el mantenimiento de infinitas entidades de datos, en lugar de tener un servicio diferente para cada una de ellas. Para hacerlo necesitábamos que el cliente que consume el servicio recibiera en la definición de su WSDL las clases que implementaban la interfaz IDTO, pero no habí­a manera de que la aplicación de servicios al generar el WSDL lo hiciera de forma automática.
La idea serí­a tener un servicio web que tuviera métodos como los siguientes (para los que no conozcan la teorí­a de los DAO, DTO y Factorí­as, podéis encontrar literatura en la categorí­a de patrones de este mismo blog):
public void Insert(IDTO dto)
{
    Factory.GetDAO(dto).Insert(dto);
}
public void Update(IDTO dto)
{
    Factory.GetDAO(dto).Update(dto);
}
public void Delete(IDTO dto)
{
   Factory.GetDAO(dto).Delete(dto);

Como véis esto serí­a la leche ya que cualquier llamada al servicio serí­a capaz de ejecutar la acción independientemente del DTO que le llegue…
Por aquí­ dejo el código de la factorí­a, que como véis, segíºn el DTO que recibe, retorna el DAO correspondiente.
public class Factory
{
   public static IDAO GetDAO(IDTO dto)
   {
       if (dto is CocheDTO)
       {
          return CocheDAO.GetInstance();
       }
       else if (dto is MarcaDTO)
       {
          return MarcaDAO.GetInstance();
       }
       throw new Exception(“no existe este dto”);
    }
}
Además, como podréis observar, todos los DAO heredan de IDAO, que es quien define los métodos con los que un DAO puede trabajar, y es lo que usa la factorí­a para actuar con independencia.
Pero bueno, vamos al grano y a lo que interesa, que es cómo conseguir que se entere el cliente que recibe el servicio de los DTO que pueden heredar de IDTO. La clave está cuando definimos la clase IDTO.
[DataContract]
[KnownType(typeof(DTO.CocheDTO))]
[KnownType(typeof(DTO.MarcaDTO))]
public class IDTO
{
}
Sobre la clave DataContract, ya hablaremos cuando hagamos la introducción a WCF, en lo que quiero que os fijéis es en las claves KnowType. Aquí­ es donde estamos marcando al servicio que IDTO tiene como tipos conocidos otras clases, que son las que heredan de ella. Por cierto, habréis visto que IDTO es una clase y no un interfaz… por lo visto el atributo KnowType no puede utilizarse con interfaces, pero bueno nos da lo mismo en este caso.
Con todas estas combinaciones que os he presentando, y si probáis el ejemplo donde tenéis más código, veréis que en el cliente que se ha montado (que es una aplicación de escritorio con un botón), podréis leer el siguiente código:
Servicio.MiServicioClient cliente = new Servicio.MiServicioClient();
Servicio.CocheDTO coche = new Servicio.CocheDTO();    
Servicio.MarcaDTO marca = new Servicio.MarcaDTO();     
coche.Codigo =1;
coche.Matricula=”IB-4444-TRT”;
coche.NumeroPuertas=1;
cliente.Insert(coche);
marca.Codigo = 4;
marca.Nombre = “Mercedes”;
marca.Pais = “España”;
cliente.Update(marca);
Bingo! El cliente es capaz de instanciar objetos que no son retornados o pasados por parámetro explí­citamente por un método de un servicio (que era uno de los problemas que tení­amos con el Framework 2.0). “Mágicamente” podemos utilizar los DTO en cliente, rellenarlos y pasárlos a los correspondientes métodos de Insert y Update. Al llegar la petición al servicio, la factorí­a decide el DAO a llamar en tiempo de ejecución y a correr.
Con un íºnico servicio podrí­amos realizar toda la fachada para mantener y consultar infinitas entidades de negocio. ¡Objetivo cumplido!
Os invito a descargar la solución de ejemplo que os adjunto y a lanzarla en modo debug, veréis que si lo seguí­s la ejecución mantiene el flujo que hemos definido sin problemas.
Servicio WCF Polimórfico
Saludos.
Miguel.

6 thoughts on “¿Servicios Web Polimórficos? (Parte 2 – Solución con WCF y Framework 3.5)”

  1. Esta parte suena muy bien
    “Como véis esto serí­a la leche ya que cualquier llamada al servicio serí­a capaz de ejecutar la acción independientemente del DTO que le llegue…
    Por aquí­ dejo el código de la factorí­a, que como véis, segíºn el DTO que recibe, retorna el DAO correspondiente.”
    Pero que hay de esta parte si tengo mucho objetos DAO que mantener 100 o 200, aqui tendria un case o un if de 200 posibilidades? ¿Como se podria manejar esto?
    public static IDAO GetDAO(IDTO dto)
    {
    if (dto is CocheDTO)
    {
    return CocheDAO.GetInstance();
    }
    else if (dto is MarcaDTO)
    {
    return MarcaDAO.GetInstance();
    }
    throw new Exception(”no existe este dto”);
    }

  2. Hola Fernando,
    Efectivamente con la solución que se ha planteado se está obligando a que si tienes 200 DAO, necesites un switch con 200 condiciones.
    A priori puede parecer descabellado, pero ten en cuenta que se está gestionando de forma interna y transparente a los clientes que llaman a la capa de negocio. Puede que necesites un switch con 200 casos, pero para acceder a esos 200 objetos de negocio expones hacia fuera un íºnico servicio con cuatro o cinco métodos que permiten hacer las operaciones básicas para cualquiera de los 200 DAO.
    De ahí­ la gracia de todo este sistema, que sea estupendo para preparar por ejemplo una tí­pica aplicación de mantenimiento.
    Eso sí­, como bien dices, y centrándonos íºnicamente en el “problema” del switch, el manejo de la factorí­a es mejorable, déjame pensar en algo a ver qué se me ocurre, puede que encontremos una manera de hacer que esta parte del código aumente en mantenibilidad y legibilidad.
    Cualquier aportación al respecto será bienvenida 🙂
    Saludos!
    Miguel.

  3. Estimado Miguel, primero que todo, felicitaciones por el artí­culo, mi consulta es la siguiente, ¿como puedo implementar los métodos que son propios de una clase?, se muestra el funcionamiento de implementación de los métodos de la interface, pero no se como tratar los métodos propios. Y segundo, Si tengo un método del tipo: “public System.Collections.Generic.List Get()” como lo paso a su correspondiente tipo de clase para devolverlo al controlador.
    Gracias

  4. Miguel excelentisimo post estos de DAO + DTO.
    Me confundo un poco todavia pero creo q es practica nomas.
    German, cn respecto a tu pregunta; la verdad nose VB Net pero como me gusto el tema me puse a ver q onda tu problema. No te aseguro que este bien… pero no podrias resolverlo asi:
    Tratar Metodos Propios:
    SERVICE:
    Public Function getString(ByVal cadena As String) As String
    Dim _newCadena As String
    Dim _marcaDTO As MarcaDTO
    Dim objMarcaDao As MarcaDAO = DAOFactory.GetDAO(_marcaDTO)
    _newCadena = objMarcaDao.OtroMetodo(cadena)
    Return _newCadena
    End Function

  5. la continuacion…. MARCADAO
    Public Function OtroMetodo(ByVal cadena As String) As String
    Try
    ‘Lo que le quiere hacer a la cadena xD
    cadena = cadena & ” .”
    Return cadena
    Catch ex As Exception
    Throw New Exception(“Error en nuevo metodo!”)
    End Try
    End Function
    Como ya te dije nose si realmente respecto lo de las capas, pero creo que buscaria por ese lado… el segundo tema te lo dejo de tarea ja!
    Saludos!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.