Introducción
La idea central es invocar un servicio web desde otro (servicio web naturalmente)
pasandole parametros
de tipo clase. Detallo a continuacion el problema a solucionar:
Un cliente invoca un servicio web "A" y envia como parametro una clase (objeto definido
en "A"), el servicio recibe la peticion e invoca a otro servicio web ("B"), este
servicio recibe como parametro una clase parecida
pero no igual a la definida en "A", el servicio web "A" hace la llamada
a "B" , este retorna el resultado
al servicio web "A" y este se encarga de reenviarlo finalmente al cliente.
Aparentemente no tiene nada de extraordinario, sin embargo existe varios puntos
a considerar:
- 1ro el cliente usa solo un metodo para obtener la información, se conecta a "A"
asimismo instancia su clase y la envia como parametro. Para el la consulta a otro servicios
es transparente (osea nunca se entera de ello).
- 2do el servicio web "A" se encarga de ingresar los parametros al servicio "B".
Es decir hace una transformacion de su clase a la clase que necesita
para invocar
a "B".
Contenido
Veamos como vamos a resolver este problema:
Definimos la clase de "A"
y el servicio web:
' Es clase es el parametro que debemos enviar al servicio
"A"
public class clpersona()
{
public string nombre;
public string apellido;
public
string direccion;
}
El servicio web :
[WebService(Namespace= "http://200.43.48.125/servicioA")]
public class servicioA : System.web.services.webservice{
[WebMethod]
[XmlInclude(typeof(clpersona))]
public string obtenerpersonaA(clpersona parampersonaA){
.........
}
}
Definimos a la clase de "B" y el servicio web
' Esta clase es el parametro
que debemos enviar al servicio "B"
public class clpersona()
{
public string nombre;
public string apellido;
}
El servicio web:
[WebService(Namespace= "http://200.40.78.155/servicioB")]
public class servicioB : System.web.services.webservice{
[WebMethod]
[XmlInclude(typeof(clpersona))]
public string obtenerpersonaB(clpersona parampersona){
.........
}
}
Note que las clases clpersona de A y clpersona de B son casi identicas salvo el
atributo direccion de la clase clpersona de A. Cuando invoquemos al servicio
de B se debería asignar solamente los campos comunes y obviar los demas.
El cliente instancia la clase clpersonaA y hace la llamada al servicio A.
clpersona varpersonaA =
new clpersona();
servicioA servicio =
new servicioA();
varpersonaA.nombre = "Juanito";
varpersonaA.apellido = "Alimana";
varpersonaA.direccion = "direccion";
servicio.obtenerpersonaA(varpersonaA);
El servicio A recibe la clase y ahora debe invocar al servicio B
clpersona varpersonaB =
new clpersona();
servicioB servicio =
new servicioB();
varpersonaB.nombre = parampersonaA.nombre
varpersonaB.apellido = parampersonaA.apellido
servicio.obtenerpersonaB(varpersonaB);
Ahora como vemos es simple, sin embargo cuando la clase persona de A sea mas compleja,
por decir tenga herencia, tenga mas de 15 parametros o quizas en vez de una instancia
de la clase sea todo un arreglo de clases, pues la cosa se complica y el problema
se presenta en la asignacion de una clase a la otra.
La solucion que encontre es la siguiente:
- Definir un proceso de serializacion de la clase persona de A y deserializacion
en la clase persona de B. Es decir llevo la clase persona de A a xml y luego de
xml construyo la clase persona de B.
- Modificar el namespaces http://200.40.78.155/servicioB al serializar persona
de A porque si quiero deserializaro en la clase persona de B no voy a poder puesto
que persona de B tiene otro nombre de espacio.
- Acotamos que las clases pueden o no tener los mismos atributos, pueden o no tener
el mismo nombre (para este caso es necesario hacer mas cambios en la serialización
que en este ejemplo no estamos considerando).
- Cuando se deserialice solo se asignaran los campos comunes y es necesario que
los nombres de las clases sean las mismas.
Serializacion
El procedimiento sera el siguiente:
XmlSerializer serializer=
null;
FileStream stream=
null;
string path= HttpContext.CurrentServer.MapPath(".")
+ "archivoserializado.xml";
XmlAttributes atributos =
new XmlAttributes();
XmlTypeAttribute tipo =
new XmlTypeAttribute();
//sin esta linea la deserializacion no funcionara
tipo.namespace="namespace del servicio B";
atributos.XmlType= tipo;
XmlAttributesOverrides atributosserialisation
= new XmlAttributesOverrides();
atributosserialisation.Add(typeof(servicioA.clpersona),
atributos );
serializer= new XmlSerializer(typeof(servicioA.clpersonaA),atributosserialisation);
stream= new FileStream(path,
FileMode.Create, FileAcces.Write);
serializer.Serialize(stream,< instancia de la clase A>);
Ahora veamos la deserializacion.
Deserializacion
clPersona resultadopersona= new
clPersona();
XmlSerializer deserializer=
new XmlSerializer(typeof(clpersona);//persona
de B
//estas dos lineas de codigo para controlar las excepciones
en caso de que algun campo no coincida
desserializer.UnKnownNode=+
new XmlNodeEventHandler(nombredeevento1);
desserializer.UnKnownAttribute=+ new XmlNodeEventHandler(nombredeevento2);
string path= HttpContext.CurrentServer.MapPath(".")
+ "archivoserializado.xml";
XmlReader lector =
new XmlAttributes();
resultadopersona = (clpersona)deserializer.Deserialize(lector);
Espero que el ejemplo este comprensible y sobre todo que pueda servir para aquellos
que desean implementar sistemas con mas de un servicio web y que se encuentren distribuidos
en toda la red.
GBY
Espacios de nombres usados en el código de este artículo:
System.xml
System.xml.serialization.
System.IO.
|