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.