WebServices: Comunicación sin fronteras
Cómo comunicar sistemas basados en .NET y otras tecnologías

Fecha: 28/Feb/2005 (26/02/2005)
Autor: Mariano Szklanny (mszklanny@ciudad.com.ar)

 


Los WebServices han alcanzado la cima con .NET: la facilidad y rapidez que nos ofrece Visual Studio .NET para generarlos ha causado la migración de muchos usuarios a ASP.NET. Pero aun así, existen muchos sistemas basados en otras tecnologías. En esta oportunidad veremos cómo unir los dos mundos a través del poderoso XML.

El uso de los Web Services está muy de moda hoy en día, eso es evidente. Las ventajas que nos ofrece .NET hacen de estos servicios un método de comunicación muy eficiente y, a la vez, fácil de lograr. Con unos pocos clics y algunos drag & drop en Visual Studio .NET, podemos armar nuestro propio Web Service “Hola Mundo" en cuestión de segundos.

Pero ¿qué sucede cuando los sistemas que queremos comunicar no pueden ser montados en .NET? ¿Qué pasa si queremos utilizar nuestro viejo website implementado en PHP, o ASP, para que se comunique con un sistema en .NET? La respuesta está en acudir a la base de los Web Services: XML. Porque una de las grandes ventajas de los Web Services es, justamente, que están basados en XML, lo cual permite abrir las fronteras de la comunicación hasta lugares impensables.

XML: el ‘Pase Libre’ de la Web

Desde sus comienzos, XML fue pensado como la solución definitiva a los problemas de almacenamiento de datos y a los obstáculos en la comunicación entre sistemas. Respecto al tema que nos concierne, los documentos XML serán la base de la comunicación entre los sistemas que utilicemos, ya que al ser archivos de texto planos, podrán viajar por la Web sin ninguna dificultad, a través del protocolo HTTP. Aprovecharemos, entonces, una de las principales cualidades de XML para entablar la comunicación entre los mundos, pues XML es independiente de cualquier plataforma de hardware o de software.

Por lo tanto, para poder utilizar los Web Services bastará con que nuestros sistemas “no .NET” puedan interpretar XML y, a la vez, puedan hacer uso del protocolo HTTP.

En el ejemplo que veremos a continuación, emplearemos ASP 3.0 como lenguaje que cumple estos requerimientos, pero esto no significa que quede descartada la posibilidad de comunicar sistemas implementados en otras plataformas, tales como PHP o J2EE.

El lenguaje de los Web Services

Hemos mencionado la utilidad de XML en el uso de Web Services, pero no podemos dejar de nombrar a su amigo inseparable: el protocolo de comunicación SOAP (Simple Object Access Protocol, http://www.w3.org/TR/soap). Este establece cómo debe escribirse un documento XML para que los Web Services puedan entenderlo. En otras palabras, SOAP define el formato que debe tener un archivo XML para poder ser interpretado por un Web Service; De este modo, un documento XML no podrá ser leído por un Web Service si éste no está escrito de acuerdo con el protocolo SOAP.

Preparar el terreno

Para abarcar el tema en cuestión, veremos paso a paso cómo crear un sistema de inscripción de alumnos a un curso, a través de diversos sitios web que se comunican con una base de datos centralizada. El acceso a los datos estará controlado por una aplicación diseñada en ASP.NET (C#) que expondrá al mundo el WebMethod “AddAlumno()”, consumido por los sitios web para inscribir a los estudiantes. En este caso, nuestro Web Service funcionará como una interfaz entre la base de datos y los sitios web que lo consuman.

Crearemos un sitio en ASP 3.0, como representante de toda la gama de plataformas capaces de comunicarse con nuestro Web Service. Este contendrá un formulario de inscripción, que, al ser completado, invocará al WebMethod antes mencionado y le enviará como parámetros los datos del formulario.

Creación del Web Service

En primera instancia, vamos a crear en Visual Studio .NET el servicio web, al que llamaremos “InscripcionWS". Este contendrá, a modo de ejemplo, un único WebMethod que invocará al método “Add()” de la clase “Alumno”, el cual se encargará de registrar al estudiante en la base de datos y devolverá el nuevo código del mismo, autogenerado por el motor de la base de datos. No entraremos en detalle acerca de la implementación de esta clase, simplemente bastará con saber que posee las siguientes propiedades y métodos:

Alumno
-int ID
-string Nombre
-string Apellido
-string Email
+int Add()

Para comenzar, abrimos Visual Studio y creamos un nuevo proyecto de tipo “ASP.NET Web Service”, dentro de Visual C# Projects. Como nombre del proyecto, usaremos “InscripcionWS”.

Le damos OK y, dentro del Solution Explorer, cambiamos el nombre del archivo “Service.asmx” por “Inscripcion. asmx”. Luego abrimos el código fuente correspondiente y cambiamos el nombre a la clase y al constructor por “Inscripcion”. Y ahora sí, implementamos el WebMethod “AddAlumno()”, que recibe un objeto del tipo Alumno por parámetro y devuelve el código del nuevo alumno:

[WebMethod]
public int AddAlumno(Alumno oAlumno)
{
    return oAlumno.Add();
}

Recuerden que para que nuestro Web Service funcione, debemos agregar la referencia al proyecto que contiene la clase alumno e incluirlo dentro de nuestro asmx a través de la directiva “using”.

Una vez asegurado esto, compilamos el proyecto y vemos sus resultados, haciendo clic con el botón derecho sobre el archivo Inscripcion.asmx (Solution Explorer) y luego en “View in Browser”. Si todo salió bien, deberíamos ver listado nuestro WebMethod. Al hacer clic en él, accederemos a una página que nos brindará la información necesaria para acceder a él desde un sistema remoto. Estas líneas de código están escritas en SOAP, y son los “mensajes” que deben enviarse los sistemas que comuniquemos, de manera que puedan entenderse.

En el primer recuadro sombreado que nos brinda ASP.NET, podemos apreciar el código SOAP que necesitamos para invocar al Web Service (Request):

<?xml version="1.0" encoding="utf-8"?>
<soap:envelope xmlns:xsi="http:"//www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:body>
  <addalumno xmlns="http:"//localhost/inscripcionWS/">
   <oalumno>
    <id>int</id>
    <nombre>string</nombre>
    <apellido>string</apellido>
    <email>string</email>
   </oalumno>
  </addalumno>
 </soap:body>
</soap:envelope>

Una de las ventajas de XML es que, además de ser entendible por sistemas informáticos, por lo general es legible también para los seres humanos. A simple vista podemos distinguir la estructura del SOAP: es un sobre (soap:Envelope) que contiene dentro el cuerpo del mensaje (soap:Body), en el cual se detalla el método por ejecutar (AddAlumno) y sus respectivos parámetros (oAlumno).

Nótese que donde se lee “string” e “int”, colocaremos luego los valores ingresados por el usuario .

En el segundo recuadro tenemos el SOAP que se usa para obtener la respuesta (Response):

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http:"//www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
  <AddAlumnoResponse xmlns="http:"//localhost/inscripcionWS/">
   <AddAlumnoResult>int</AddAlumnoResult>
  </AddAlumnoResponse>
 </soap:Body>
</soap:Envelope>

En este caso simplemente tenemos, dentro del Body, la respuesta de la ejecución del WebMethod (AddAlumnoResponse), cuyo resultado será el valor que figure entre los tags <AddAlumnoResult> y </AddAlumnoResult>.

Consumir Web Services desde ASP

Para entablar la comunicación desde nuestro sitio web en ASP, utilizaremos el componente MSXML2.ServerXMLHTTP, que nos permite establecer una conexión entre dos servidores remotos a través del protocolo HTTP. En nuestro ejemplo, lo emplearemos para enviar el mensaje SOAP que invocará al Web Service y, al mismo tiempo, para recibir la respuesta desde el servidor.

Los métodos que usaremos son:

Para poder reutilizar nuestro código, crearemos un archivo funciones. asp, que incluiremos en la página que invoque al InscripcionWS. En él implementaremos una función llamada “InvokeWebService()”:

<%
Function InvokeWebService (strSoap, strSOAPAction, strURL, ByRef xmlResponse)
    '*****************************************************************************
    ' Descripción: Invoca un WebService y obtiene su resultado.
    '
    ' Inputs:
    '    strSoap:        Petición HTTP a enviar, en formato SOAP. Contiene la    
    '                llamada al WebMethod y sus parámetros 
    '                correspondientes.
    '    strSOAPAction:    Namespace y nombre del WebMethod a utilizar.
    '    strURL:        URL del WebService.
    '
    ' Returns:
    '    La función retornará False si ha fallado la ejecución del WebService o si
    '    ha habido error en la comunicación con el servidor remoto. De lo contrario
    '    retornará True.
    '
    '    xmlResponse:    Respuesta obtenida desde el WebService, parseada 
    '                por el MSXML.
    '*****************************************************************************

    Dim xmlhttp
    Dim blnSuccess

        'Creamos el objeto ServerXMLHTTP
        Set xmlhttp = Server.CreateObject("Msxml2.ServerXMLHTTP")

        'Abrimos la conexión con el método POST, ya que estamos enviando una
        'petición.
        xmlhttp.Open "POST", strURL

        'Agregamos encabezados HTTP requeridos por el WebService
        xmlhttp.setRequestHeader "Man", "POST " & strURL & " HTTP/1.1"
        xmlhttp.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
        xmlhttp.setRequestHeader "SOAPAction", strSOAPAction

        'El SOAPAction es importante ya que el WebService lo utilizará para
        'verificar qué WebMethod estamos usando en la operación.

        'Enviamos la petición
        xmlhttp.send(strSoap)

        'Verificamos el estado de la comunicación
        If xmlhttp.Status = 200 Then

            'El código 200 implica que la comunicación se puedo establecer y que
            'el WebService se ejecutó con éxito.
            blnSuccess = True
        Else

            'Si el código es distinto de 200, la comunicación falló o el
            'WebService provocó un Error.
            blnSuccess = False
        End If

        'Obtenemos la respuesta del servidor remoto, parseada por el MSXML.
        Set xmlResponse = xmlhttp.responseXML

        InvokeWebService = blnSuccess

        'Destruimos el objeto, acá no hay GarbageCollector ;)
        Set xmlhttp = Nothing
End Function
%>

Ahora vamos a crear un archivo que tendrá un sencillo formulario, llamado form.asp. Establecemos que el action del form sea el archivo invoke.asp, el cual hará la llamada al Web Service:

<html>
<head>
<title>Inscripción al Super-Curso</title>
</head>
<body>

<h1>Inscripción al Super-Curso</h1>

<form method="post" action="invoke.asp">
Nombre:<br><input type="text" name="nombre"><br>

Apellido:<br><input type="text" name="apellido"><br>

Email:<br><input type="text" name="email"><br>

<input type="submit" value="Inscribirme!"><br><br>
</form>

</body>
</html>

Y ahora sí, la parte interesante: la llamada al Web Service. Creamos el archivo invoke.asp y lo primero que vamos a hacer es incluir el archivo funciones.asp:

<!-- #include file = ”funciones.asp” -->

A continuación, vamos a combinar los datos ingresados en el formulario, con el código SOAP obtenido anteriormente (Request), de modo que se genere el mensaje completo que enviaremos al Web Service:

'Asignamos los datos del formulario a variables internas
strNombre = Request.Form("nombre")
strApellido = Request.Form("apellido")
strEmail = Request.Form("email")


'Copiamos el SOAP (Request) obtenido en el asmx y reemplazamos "string" por los
'valores que ingresó el usuario. Omitimos el campo ID debido a que no es
'necesario para la ejecución del método AddAlumno.

strSoap    = "<?xml version=""1.0"" encoding=""utf-8""?>" & _
"<soap:Envelope xmlns:xsi=""http:"//www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
 "<soap:Body>" & _
  "<AddAlumno xmlns=""http:"//localhost/inscripcionWS/"">" & _
   "<oAlumno>" & _
    "<Nombre>" & strNombre & "</Nombre>" & _
    "<Apellido>" & strApellido & "</Apellido>" & _
    "<Email>" & strEmail & "</Email>" & _
   "</oAlumno>" & _
  "</AddAlumno>" & _
 "</soap:Body>" & _
"</soap:Envelope>"

Una vez que tenemos el mensaje SOAP armado, procedemos a invocar al Web Service. Para hacerlo, necesitamos el SOAPAction, el cual se forma con el namespace del Web Service / el nombre del WebMethod:

strSOAPAction = "http://localhost/inscripcionWS/AddAlumno"

Ahora sí estamos listos para llamar a la función InvokeWebService(). Conociendo la estructura del XML de respuesta (SOAP Response), obtenemos el resultado de la ejecución:

'Dimensionamos la variable donde obtendremos la respuesta del WebService 
Dim xmlResponse

'Realizamos la llamada a la función InvokeWebService(), brindándole los parámetros correspondientes
If InvokeWebService (strSoap, strSOAPAction, "http:"//localhost/inscripcionWS/inscripcion.asmx", xmlResponse) Then

    'Si el WebService se ejecutó con éxito, obtenemos la respuesta y la imprimimos utilizando MSXML.DOMDocument
    intCodigoAlumno = xmlResponse.documentElement.selectSingleNode("soap:Body/AddAlumnoResponse/AddAlumnoResult").text

    Response.Write "Gracias " & strNombre & " " & strApellido & " por Inscribirse! Su nuevo código es: " & intCodigoAlumno
Else
    'Pero si hubo algún problema, le informamos al usuario
    Response.Write = "Ha ocurrido un error!"
End If

'Liberamos la memoria del objeto xmlResponse 
Set xmlResponse = Nothing

De este modo concluimos nuestro pequeño sistema. Para probarlo, podemos correr el archivo form.asp y registrar un alumno.

Conclusión

Actualizar un sistema a .NET suele traer grandes beneficios, pero no siempre los costos que implica cambiar servidores, volver a diseñar y/o programar gran parte del sistema y capacitar personal superan a los beneficios que la tecnología de punta puede ofrecernos.

Como vimos, usar Web Services en sistemas no .NET es posible y no muy complicado. Este tipo de soluciones puede ser muy útil en desarrollos que requieran mantener la plataforma actual, ya sea por cuestiones económicas, prácticas o de otra índole. La intención de este artículo es, entonces, ofrecer una solución práctica y más económica para esta clase de situaciones. Espero que en estas páginas hayan podido encontrar material que les sea de utilidad.

Microsoft Soap Toolkit

Así se conoce a un componente desarrollado por Microsoft cuyo objetivo es permitir el uso (publicación y consumo) de Web Services en plataformas “no .NET” que utilicen objetos COM, como ASP. Si bien en ciertos casos puede ofrecer soluciones más simples que las presentadas en este artículo, se ha optado por el método del “SOAP escrito a mano”, debido a varias razones. Una de ellas es que el Soap Toolkit no se encuentra disponible en todos los servidores web (es un componente que se debe bajar e instalar en el servidor), por lo tanto no está al alcance de todos los usuarios. Otro aspecto importante es que este componente no permite el uso de todos los tipos de datos soportados por SOAP y, como es de esperarse, no permite el uso de tipos definidos por el usuario. Nuestro ejemplo no podría haberse realizado con el Soap Toolkit si estuviéramos estrictamente trabajando con programación orientada a objetos. Además, el trabajo con Recordsets/Datasets se hace muy engorroso con este componente, mientras que mediante el método utilizado en este artículo, obtener objetos de este tipo es tan simple como obtener un integer. Por otro lado, la explicación del método de la escritura manual del SOAP permite que desarrolladores de otras plataformas puedan implementarlo en sus aplicaciones. La teoría que usamos en este artículo para una aplicación en ASP puede aplicarse perfectamente a otros entornos, pero no en todos los entornos existentes hay un Soap Toolkit que facilite la tarea. Más información sobre Soap Toolkit en: http://msdn.microsoft.com/webservices/building/soaptk.

 


Fichero con el código de ejemplo: mszklanny_WebServices_con_plataformas_no_NET.zip - 42 KB


ir al índice