ESB con WCF, ¿cómo puedo implementar Adaptadores?

Problema

Para un proyecto de plataforma móvil estamos haciendo un ESB pequeño que utiliza WCF. La idea es que este ESB permita agregarle nuevos servicios de manera administrativa sin volver a compilar. Estos servicios son expuestos por otros sistemas y no se puede normar los contratos que estos exponen.

WCF permite llamar servicios a los cuales se le conoce su interfaz mediante el uso de ChannelFactory. Esto serviría pero hay una complicación adicional, no tenemos las interfaces en tiempo de diseño sólo en tiempo de ejecución. En resumen se necesitan en este caso dos cosas:

  1. Llamar servicios en tiempo de ejecución sin volver a compilar el cliente.
  2. Soportar DataContract en las llamadas a los servicios.

 Este es el concepto de adaptador…….

Solución propuesta, Uso de Reflexión

Para el primer problema podemos usar reflexión [2]. La reflexión nos permitirá en tiempo de ejecución hacer una instancia del Proxy para el servicio y de los tipos DataContract [3] que este utilice. Esto quiere decir que en tiempo de ejecución cargamos el Assembly [4] que contenga en Proxy y lo invocamos.

Veamos un ejemplo de un servicio simple en WCF. El código uno muestra el contrato del servicio, esto es lo que describe que es lo que el servicio hace. Luego, el código dos muestra los tipos de datos específicos del contrato del servicio. Por último, el código 3 muestra la implementación del servicio.

 

[ServiceContract()]

public interface IService1

{

    [OperationContract]

    string MyOperation1(string myValue);

    [OperationContract]

    string MyOperation2(DataContract1 dataContractValue);

}

 

Código 1: Contrato de servicio.

 

 [DataContract]

public class DataContract1

{

    string firstName;

    string lastName;

 

    [DataMember]

    public string FirstName

    {

        get { return firstName; }

        set { firstName = value; }

    }

    [DataMember]

    public string LastName

    {

        get { return lastName; }

        set { lastName = value; }

    }

}

Código 2: Datos del Contrato de servicio.

 

 public class service1 : IService1

{

    public string MyOperation1(string myValue)

    {

        return "Hello: " + myValue;

    }

    public string MyOperation2(DataContract1 dataContractValue)

    {

      return "Hello: " + dataContractValue.FirstName + " " + dataContractValue.LastName;

    }

}

Código 3: Implementación del servicio.

Para que el cliente (ESB) invoque al servicio va a requerir de un Proxy que le permita llamar a los métodos del servicio. Generamos entonces un proxy en un Assembly separado que pueda ser entregado al administrador del ESB para que lo "instale". La instalación no requerirá de compilación del lado del cliente (ESB).

Una vez que tenemos el Assembly podemos hacer una instancia del Proxy y ejecutar sus métodos. Como ejemplo, primero llamaremos al método MyOperation1 del servicio de ejemplo. Para esto construimos un método de llamado en el cliente como se muestra en el código 4.

 

/// <summary>

/// Este método ejecuta el proxy usando reflexion

/// </summary>

/// <param name="pathAssembly">Ruta del Assembly del Proxy</param>

/// <param name="NombreTypoProxy">Tipo del proxy</param>

/// <param name="NombreOperacion">Nombre del método a Ejecutar</param>

/// <param name="mParametros">paramtros del método</param>

public static void EjecutarProxy(string pathAssembly, string NombreTypoProxy,string NombreOperacion, object[] mParametros)

{

    Console.WriteLine("LLamada a través de un Proxy Externo");

    //1.- Levantar el Assembly que contiene el Proxy.

    Assembly SampleAssembly = Assembly.LoadFile(pathAssembly);

    //2.- Hacen una inctancia de la clase Proxy       

    object myClassObj = SampleAssembly.CreateInstance(NombreTypoProxy);// ("ProxyIntermedio.localhost.Service1Client");

    // 3.- Obtener la información del tipo del Proxy

    Type myTypeObj = myClassObj.GetType();

    // 4.- Obtener información del método a llamar

    MethodInfo myMethodInfo = myTypeObj.GetMethod(NombreOperacion);//("MyOperation1");

    //5.- llamar al servicio, usando el Proxy

    Console.Write("\nLLamando a – " + myTypeObj.FullName + "\n Respuesta: " +

                         myMethodInfo.Invoke(myClassObj, mParametros) + "\n");

    Console.ReadLine();

}

Código 4: llamada a través del proxy externo.

Este ejemplo utiliza un tipo de datos "primitivo" lo cual puede ser muy común pero no necesariamente así es siempre. Para servicios más complejos se usan tipos de datos complejos los cuales se modelan utilizando DataContract. El próximo ejemplo llama al método MyOperation2 que usa un argumento del tipo DataContract1.

El código 5 muestra cómo podemos llamar a un servicio que tiene como argumento de entrada un tipo de dato complejo haciendo uso de un Proxy externo. El principio es el mismos que en el caos anterior, con la diferencia que ahora debemos instanciar un DataContract y asignarle los valores que correspondan. Para esto usamos las capacidades de Reflexión para instanciar tipos y asignarle valores a sus propiedades como se muestra en el punto 6 del código 5. El código que llama a este método se muestra en el código 6, ahí se puede ver que el parámetro de entrada al método EjecutarProxyTypoComplejo es un diccionario [5] con los valores, el cual será recorrido y asignado dentro del método.

 

/// <summary>

/// LLamada utilizando un proxy externo con un método de datos complejo

/// </summary>

/// <param name="pathAssembly">Ruta del Assembly del Proxy</param>

/// <param name="NombreTypoProxy">Tipo del proxy</param>

/// <param name="NombreTypoData">Nombre tipo del DataContract</param>

/// <param name="NombreOperacion">Nombre del método a Ejecutar</param>

/// <param name="mParametros">Diccionario con los valores a asignar al Datacontract</param>

public static void EjecutarProxyTypoComplejo(string pathAssembly, string NombreTypoProxy,string NombreTypoData,string NombreOperacion, Dictionary<string,string>  mParametros)

{

    Console.WriteLine("\nLLamada a través de un proxy externo con tipo de dato complejo");

    //1.- Levanatr Assembly

    Assembly SampleAssembly = Assembly.LoadFile(pathAssembly);

    //2.- Crear instancia del Proxy       

    object myClassProxy = SampleAssembly.CreateInstance(NombreTypoProxy);

    //3.- Crear Instancia del DataContract

    object myDataContract = SampleAssembly.CreateInstance(NombreTypoData);

    //4.- Obtener los tipos de datos

    Type myTypeProxy = myClassProxy.GetType();

    Type myTypeData = myDataContract.GetType();

    //5.- Obtener la información del método.

    MethodInfo myMethodInfo = myTypeProxy.GetMethod(NombreOperacion);

    //6.- Asignar los valores al Datacontract1

    PropertyInfo prop;

    foreach (KeyValuePair<string, string> kvp in mParametros)

    {

        prop = myTypeData.GetProperty(kvp.Key);

        prop.SetValue(myDataContract, kvp.Value, null);

    }

    //7.- Objeto para usar como argumento tipado.      

    object[] mParam = new object[] { myDataContract };

    //8.- llamar al servicio

    Console.Write("\nllamando a  – " + myTypeProxy.FullName + " \nRespuesta:  " +

                         myMethodInfo.Invoke(myClassProxy, mParam) + "\n");

    Console.ReadLine();

}

Código 5: llamada a través del proxy externo con un tipo de dato complejo.

 

//….. algun códiogo aqui

Dictionary<string,string> lala = new Dictionary<string,string>();

lala.Add("FirstName","Juan Pablo");

lala.Add("LastName","García González");

EjecutarProxyTypoComplejo(

    @"..\ProxyIntermedio.dll",

    "ProxyIntermedio.localhost.Service1Client",

    "ProxyIntermedio.localhost.DataContract1",

    "MyOperation2", lala);

//…. algun código aquií

Código 6: llamada a través del proxy externo con un tipo de dato complejo.

Con esta técnica todos los futuros servicios pueden ser enlazados utilizando el Proxy autogenerado para cada servicio.  

 

Referencias

[1] Adapter pattern, http://en.wikipedia.org/wiki/Adapter_pattern

[2] Información general sobre la reflexión, http://msdn2.microsoft.com/es-es/library/f7ykdhsy(VS.80).aspx

[3]Contratos de Datos, http://www.microsoft.com/spanish/msdn/articulos/archivo/041206/voices/LearnTheABCsOfP.mspx#E3H

[4] What is a .Net Assembly? , http://www.programmersheaven.com/2/FAQ-DOTNET-DOTNET-Assembly-Explained

[5] Dictionary Generic Class, http://msdn2.microsoft.com/en-us/library/xfhwa508.aspx

2 pensamientos en “ESB con WCF, ¿cómo puedo implementar Adaptadores?

  1. Rogelio

    Hola Juan Pablo, gusto de saludarte.Mi comentario es más enfocado hacia la plataforma móvil. Sería interesante para entender esta problemática conocer que tipo de arquitectura están usando para esta solución Mobil. Se me ocurre por lo leído que se debe a una solución móvil conectada, ósea.(Dispositivo Movil)  –> gprs –> Midleware(esb) –> BackEnd o Storage.¿O a la mejor es una solución desconectada?Disculpa por sacarte del tema de WCF, pero también me parece interesante el escenario móvil.

    Responder
  2. Juan Pablo

    Hola,
     
    No puedo dar muchos detalles ….. pero estamos hablando de una arquitectura OCC (es decir desconectada) orientada a servicios . Esto es habilitado por el Middleware Movil (ESB) que es capaz de hablar con los móviles y con el BackOffice. Algo así:
    (móviles)[Adaptador]-> EDGE / GPRS->[ServicioMiddleware] Middleware(Esb)-> [Servicio]BackOffice
     Tengo algunos link’s para ti si te interesa el tema móvil:
    OCC:
     http://liarjo.spaces.live.com/blog/cns!4131EA552C5BB029!2473.entry
    Seguridad en las comunicaciones con móviles:
    http://liarjo.spaces.live.com/blog/cns!4131EA552C5BB029!1724.entry
     Una idea de cómo integrar SAP a móviles:
    http://liarjo.spaces.live.com/blog/cns!4131EA552C5BB029!2474.entry
     
    Gracias por tu comentario, estamos en contacto!!!
     
    Salu2

    Responder

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