¿Cómo llamar a servicios web desde C/C++?
Como últimamente me han realizado esta pregunta en varias ocasiones la voy a contestar en este post, seguro que a alguien le vendrá bien la respuesta.
Los servicios web se han extendido espectacularmente en los últimos años. Ya casi no existe ninguna aplicación que no exponga un API de integración basada en una fachada de servicios web. Una de las grandes ventajas de los servicios web es que se pueden llamar desde cualquier lenguaje de programación ya que lo único necesario es ser capaz de contruir un mensaje SOAP (que no es más que una cadena de texto) y poder realizar un POST (que en esencia es enviar datos por un socket). Aunque desde cualquier lenguaje se pueden realizar estas tareas a menudo es necesario utilizar un proxy de lado cliente que nos abstraiga de la dificultades de componer el mensaje SOAP y realizar el POST.
En C++ contamos con numerosas posibilidades a la hora de llamar a servicios web, aunque ninguna es evidente a primera vista.
En Visual Studio, formando parte parte de ATL Server contamos con una herramienta poco conocida, llamada sproxy, que es capaz de generarnos el proxy necesario para invocar a un servicio web a partir del WSDL del servicio. Sproxy genera un archivo .h que contiene las clases necesarias para llamar al servicio web. Sproxy tiene dos pegas: es una solución que solo funciona con el compilador de Microsoft y que depende de MSXML (tendremos que distribuirlo con nuestra aplicación) y de las librerias de ATL (por lo tanto no se puede compilar en la versión Express de Visual C++).
Otra opción es utilizar el Microsoft SOAP Toolkit, que aun se puede descargar pero que no ya no tiene soporte por parte de Microsoft. Salvo que se trate de mejorar una aplicación que ya usa este toolkit es casi mejor olvidar esta opción.
En Visual C++, contamos con la opción de utilizar C++/CLI y toda la potencia de las clases del framework de .Net para llamar a los servicios web. Dada la posibilidad de mezclar código manejado y código no manejado en aplicación este puede ser el camino más sencillo siempre que no nos importe exigir que el framework de .net esté instalado en la máquina cliente. Es la aproximación más sencilla pues solo es necesario agregar una referencia al servicio web para que se genere el proxy manejado necesario para llamar al servicio. El proceso es exactamente el mismo que cuando llamamos a un servicio web desde C#.
Por último, existe otra opción que tiene como principales ventajas que es mutiplataforma y que funciona con cualquier compilador de C o C++. Se trata de gSOAP, un proyecto libre que proporciona las herramientas necesarias para generar el proxy que nos permita llamar a un servicio web desde casi cualquier plataforma usando C o C++. No es tan facil de usar como las anteriores opciones pero funciona muy bien. Si la necesidad de usar Linux, Windows, Windows CE o Mac como cliente del servico es clave, gSoap es la elección clara. En la web de la herramienta hay documentación más que suficiente sobre como utilizar esta herramienta. Yo la he usado recientemente con bastante exito para llamar a un servicio de integración que expone una aplicación en la que estado trabajando los ultimos años. Os dejo un poco de ese código, para que veaís que una vez generardo el proxy la llamada es más o menos sencilla:
/Incluimos los archivos generados por gSOAP
//http://www.cs.fsu.edu/~engelen/soap.html
//que nos generan las clases proxy necesaria para llamar a servicio web
//Para que los proxys compilen correctamente, es necesario incluir en la
//compilación los archivos soapC.cpp, soapClient.cpp y stdsoap2.cpp
//además de las cabeceras necesarias, generadas por gSOAP
#include "soapproxy/soapSaveDataSoapProxy.h"
#include "soapproxy/savedatasoap.nsmap"
//Url en la que se encuenta el servicio de Prisma 3
//Es necesario establecerla correctamente al servidor concreto
const char endpoint[] = http://servidorprisma/prismaweb/webservices/public/savedata.asmx;
//Función que pemite llamar al servicio de carga de datosde Prisma 3
string SaveTableData(string& user, string& company, string& tableDataNode)
{
//Proxy SOAP generado con gSOAP
SaveDataSoap p;
p.endpoint = endpoint;
//Clase del proxy que contiene los parametros del servicio
_ns1__SaveTableData2 params;
params.user = &user;
params.company = &company;
params.tableDataNode = &tableDataNode;
//Clase del proxy que contiene la respuesta del servicio
_ns1__SaveTableData2Response response;
//Llamada al servicio
p.__ns1__SaveTableData2(¶ms, &response);
return *response.SaveTableData2Result;
}
Cabe reseñar que cuanto más simples y comunes sean los tipos que toman como parámetros los servicios web, más facil nos será llamarlos desde múltiples lenguajes o plataformas. Cualquier lenguaje sabe lo que es un string, pero solo los lenguajes .Net saben lo que es un Dataset.
Resaltar tambien que gSoap, permite generar el esqueleto de la parte servidora de un servicio web, algo muy util si necesitamos exponer servicios web desde C/C++. Pero de todos modos, en plataforma windows, para exponer servicios web desde Visual C++ es mucho más simple y potente usar ATL Server.
Da gusto ver que el C/C++ es como andar en bicicleta, una vez bien aprendido no se olvida y resulta útil cuando uno menos lo espera...