Usar un servicio Web XML desde VB6Publicado el 20/Jun/2003
|
Introducción
Sí, ya se que si vamos a crear un cliente de Visual Basic 6.0, no debería estar en la sección de .NET, pero... como de lo que se trata es de usar un Servicio Web creado con un lenguaje de .NET Framework (en particular con C#), pues creo que "también" debería estar en esta sección...
De lo que se trata es de saber qué es lo que tenemos que hacer para poder crear un cliente (una aplicación) de Visual Basic clásico para poder usar un servicio Web creado con .NET.
Lo bueno de usar los servicios Web es que al accederse a ellos mediante internet, no debe preocuparnos si está hecho en .NET o no... lo importante es que podemos usarlo y eso es lo que aquí vamos a ver:Cómo usar un servicio Web XML desde VB6
(o cómo crear un cliente VB6 para usar un servicio Web XML)Empecemos por lo que necesitamos para poder crear el proyecto (o usar el código del ejemplo incluido en el fichero zip).
1- Lo primero es el Visual Basic 6.0 (se supone que funcionará con el VB5, pero no lo he comprobado)
2- En el proyecto se usará el control Microsoft Internet Transfer Control (INET) para acceder al sitio en el que esté alojado el servicio Web (aunque sea en el propio equipo)
3- También se usará una referencia a Microsoft XML versión 2 (cualquiera posterior también valen)
4- Si vas a tener los servicios Web en tu propio equipo, necesitarás el Windows XP Profesional (o el Windows 2000) con el IIS instalado (para poder usarlo desde, por ejemplo, localhost), además de tener instalado el .NET Framework SDK, ya que los servicios Web de .NET necesitan la infraestructura del .NET (elemental), pero esto último sólo si no vas a usar el servicio Web que está publicado en mis páginas de Costasol.Una vez aclarado el tema de los requisitos, vamos a la explicación de cómo crear el cliente en VB6 para acceder a un servicio Web, en particular será el servicio Web que convierte de grados centígrados a Fahrenheit (Conversor.asmx, cuyo código puedes ver si sigues este link).
Nota:
Si quieres probar el servicio Web desde internet, tendrás que usar esta dirección:
http://www.elguille.info/Net/WebServices/conversor.asmx
desde ella puedes probarlo.Parte del código usado para enviar al servicio Web se consigue de la descripción que se muestra en el explorador, por ejemplo, la forma de llamar a cada una de las funciones. Por tanto, este ejemplo que te voy a mostrar sólo es válido para este servicio Web, en otra ocasión veremos cómo crear un cliente genérico para cualquier servicio Web, en ese ejemplo, veremos cómo saber qué funciones exporta el servicio Web y los parámetros que necesita recibir, para ello necesitaremos examinar y comprender el contenido un fichero del tipo WSDL (Web Service Description Language, lenguaje de descripción de servicio Web), pero, eso será en otra ocasión.
Cuando mandamos la información al servicio Web, tenemos que hacerlo usando los protocolos que el .NET entiende, el usado en este ejemplo es SOAP, no voy a entrar en detalles, simplemente decirte que el formato usado para la comunicación entre un servicio Web y el cliente siempre será usando XML (de ahí el nombre de estos servicios Web), por tanto el código SOAP que te voy a mostrar (el cual está tomado, como te comenté antes de la página mostrada por el explorador) está en ese formato, esa es la razón de que tengamos una referencia a Microsoft XML versión 2, ya que usaremos algunos de las clases incluidas en ella para poder manejar el código XML, bueno, vale, no me enrollo más, aquí tienes el código de una de las funciones, en particular la función que convierte de grados Centígrados a Fahrenheit:
<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> <CaF xmlns="http://elGuille/WebServices"> <valor>double</valor> </CaF> </soap:Body> </soap:Envelope>Cuando mandemos este código al servicio Web, tendremos que incluir en el sitio que está marcado con negrita (la palabra double) el valor del parámetro que queremos pasarle a esa función.
Esto lo haremos usando la clase DOMDocument del la librería msxml. El código sería algo así:Private Const cSOAPCaF = _ "<?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>" & _ "<CaF xmlns=""http:"//elGuille/WebServices"">" & _ "<valor>1</valor>" & _ "</CaF>" & _ "</soap:Body>" & _ "</soap:Envelope>"
Dim parser As DOMDocument Set parser = New DOMDocument ' cargar el código SOAP para CaF parser.loadXML cSOAPCaF ' ' Indicar el parámetro a enviar parser.selectSingleNode("/soap:Envelope/soap:Body/CaF/valor").Text = txtC.TextCon esta última línea lo que hacemos es asignar el parámetro que queremos pasarle a la función CaF, la cual espera un valor de tipo doble en un parámetro llamado valor.
Una vez que tenemos el código XML con los datos a enviar al servicio Web, usaremos el Internet Transfer para hacer ese envío, de eso se encarga la siguiente línea:
' Usar el control Inet para realizar la llamada al servicio Web Inet1.Execute txtURL.Text, "POST", parser.xml, "Content-Type: text/xml; charset=utf-8" & vbCrLf & "SOAPAction: http:"//elGuille/WebServices/CaF"Una vez que se haya ejecuta este comando, el servicio Web nos devolverá la respuesta, (incluso si se produce algún error).
Para recibir (e interpretar) la respuesta que nos mande el servicio Web, seguiremos usando el control Inet, en particular el evento StateChanged, veamos el código:Private Sub Inet1_StateChanged(ByVal State As Integer) ' If (State = icResponseCompleted) Then ' icResponseCompleted = 12 Dim s As String ' ' Leer los datos devueltos por el servidor s = Inet1.GetChunk(4096) ' ' Poner los datos en el analizador de XML Dim parser As DOMDocument Set parser = New DOMDocument parser.loadXML s ' On Error Resume Next txtF.Text = parser.selectSingleNode("/soap:Envelope/soap:Body/CaFResponse/CaFResult").Text End If End Sub¿Qué es lo que se hace en este evento?
Se comprueba si el estado del control es correcto (la descripción del estado icResponseCompleted es: La solicitud se completó y se recibieron todos los datos), es decir, que si State vale 12 quiere decir que tenemos la respuesta del servidor, así que, leemos esos datos, se los pasamos al objeto XML para que nos resulte más fácil interpretarlos y mostramos el resultado recibido en una caja de textos.Nota:
Es importante detectar los errores, ya que si la cadena que se mandó al servicio Web no es correcta, se producirá un error al leer el valor, sobre todo si la cadena recibida no está en formato XML, cosa que ocurrirá si, por ejemplo si en la dirección indicada no está el servicio Web, en este caso ser recibirá una página "normal" de HTML indicando que no se ha encontrado (el típico error 440).Y así a grandes rasgos esto es lo que necesitamos para crear el cliente de VB6, poca cosa ¿verdad?
El problema es saber qué código hay que usar para las llamadas a las distintas funciones, por suerte, si accedemos a un servicio Web desde el explorer, éste nos mostrará una página con lo necesario para crear el código que necesitamos. En la siguiente figura verás a qué me refiero:
Figura 1, el código SOAP para llamar a la función del servicio WebSí, ya se que eso no es muy aclaratorio que digamos, pero... una vez que se sabe cómo "entenderlo", la cosa resulta más fácil... yo, la verdad es que cuando veía ese código, pues... como si nada... pero, por suerte, cayó en mis manos un libro en el que, si bien no se explica a fondo cómo hacer esto, en la web del mismo sí que se incluía un ejemplo, el cual me ha servido para hacer este que te muestro hoy... que no te creas que yo me lo se todo... que también leo a otros autores..., en este caso es David S. Platt y su libro Introducing .NET (que me lo mandaron la gente de MSDN Latinoamérica al conseguir la primera estrella del desarrollador 5 estrellas, que todo hay que decirlo).
Bueno, te dejo el código completo, así como una captura del formulario además de, por supuesto, dejarte en un zip el código de ejemplo.
La captura del formulario de ejemplo:
Figura 2, Captura del formulario en tiempo de ejecución
El link al código completo (se incluye el fichero del servicio Web y el fichero WSDL) ClienteVB6CF.zip 10.20 KB
Nos vemos.
Guillermo
P.S.
Recuerda que dentro de poco publicaré el código genérico para acceder a cualquier servicio Web.
En ese ejemplo, mostraré la forma de crear una serie de colecciones con las distintas funciones que e incluyen en el servicio Web así como cada uno de los parámetros que recibe cada una de las funciones.
Pero eso será en unos días... o lo mismo mañana... ¿quién sabe?
Este es el código del formulario:
'------------------------------------------------------------------------------ ' Cliente VB6 del servicio Web conversor de ºC a ºF (18/Jun/03) ' ' Basado en un ejemplo del libro: Introducing .NET de David S. Platt ' ' ©Guillermo 'guille' Som, 2003 '------------------------------------------------------------------------------ Option Explicit Private Enum tipoConversion deCaF deFaC End Enum Private tipo As tipoConversion ' Estas definiciones están tomadas de lo mostrado en el explorador ' al seleccionar cada una de las funciones del servicio Web Private Const cSOAPCaF = _ "<?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>" & _ "<CaF xmlns=""http:"//elGuille/WebServices"">" & _ "<valor>1</valor>" & _ "</CaF>" & _ "</soap:Body>" & _ "</soap:Envelope>" Private Const cSOAPFaC = _ "<?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>" & _ "<FaC xmlns=""http:"//elGuille/WebServices"">" & _ "<valor>1</valor>" & _ "</FaC>" & _ "</soap:Body>" & _ "</soap:Envelope>" Private Sub cmdC2F_Click() tipo = deCaF Dim parser As DOMDocument Set parser = New DOMDocument ' cargar el código SOAP para CaF parser.loadXML cSOAPCaF ' ' Indicar el parámetro a enviar parser.selectSingleNode("/soap:Envelope/soap:Body/CaF/valor").Text = txtC.Text ' ' Mostrar el código XML enviado al servicio Web Text1.Text = parser.xml ' Usar el control Inet para realizar la operación HTTP POST Inet1.Execute txtURL.Text, "POST", parser.xml, "Content-Type: text/xml; charset=utf-8" & vbCrLf & "SOAPAction: http:"//elGuille/WebServices/CaF" End Sub Private Sub cmdF2C_Click() tipo = deFaC Dim parser As DOMDocument Set parser = New DOMDocument ' cargar el código SOAP para FaC parser.loadXML cSOAPFaC ' ' Indicar el parámetro a enviar parser.selectSingleNode("/soap:Envelope/soap:Body/FaC/valor").Text = txtF.Text ' ' Mostrar el código XML enviado al servicio Web Text1.Text = parser.xml ' Usar el control Inet para realizar la operación HTTP POST Inet1.Execute txtURL.Text, "POST", parser.xml, "Content-Type: text/xml; charset=utf-8" & vbCrLf & "SOAPAction: http:"//elGuille/WebServices/FaC" End Sub Private Sub Form_Load() Text1.Text = "Cliente VB6" & vbCrLf & "del Servicio Web Conversor de ºC a ºF" End Sub Private Sub Inet1_StateChanged(ByVal State As Integer) ' If (State = icResponseCompleted) Then ' icResponseCompleted = 12 Dim s As String ' ' Leer los datos devueltos por el servidor s = Inet1.GetChunk(4096) Text1.Text = s ' ' Poner los datos en el analizador de XML Dim parser As DOMDocument Set parser = New DOMDocument parser.loadXML s ' On Error Resume Next ' If tipo = deCaF Then txtF.Text = parser.selectSingleNode("/soap:Envelope/soap:Body/CaFResponse/CaFResult").Text Else txtC.Text = parser.selectSingleNode("/soap:Envelope/soap:Body/FaCResponse/FaCResult").Text End If ' If Err.Number > 0 Then Text1.SetFocus End If End If End Sub
El código del servicio Web creado con C#
Este es el código usado para crear el servicio Web.
Estará dentro de un fichero llamado Conversor.asmx el cual tendrá que estar copiado en una carpeta del servidor Web local (si tu intención es probarlo sin estar conectado a Internet).<%@ WebService Language="c#" Class="CelsiusFahrenheit.Conversor" %> using System.Web.Services; namespace CelsiusFahrenheit { ////// Descripción breve de Conversor. /// [WebService(Namespace="http:"//elGuille/WebServices", Description="Conversor de grados Fahrenheit a grados centígrados (Celsius)")] public class Conversor { // const double fc = (5.0 / 9.0); // [WebMethod(Description="Convierte de Fahrenheit a Celsius, devuelve un valor Double")] public double FaC(double valor) { return ((valor - 32) * fc); } [WebMethod(Description="Convierte de Celsius a Fahrenheit, devuelve un valor Double")] public double CaF(double valor) { return (valor / fc + 32); } // } }
Modificación para NO usar el Internet Transfer Control para acceder al servicio Web (29/Jun/03)
En el ejemplo que te mostré arriba, se utiliza el control INET (Internet Transfer Control) para acceder al servicio Web, tanto para enviar los datos como para recibirlos, pero si no quieres no hace falta ya que el Microsoft XML version 2.0 incluye un objeto para poder hacer esta tarea, se trata de XMLHTTPRequest.
Este objeto contiene una serie de métodos que nos permite enviar un comando al servicio Web para mandarle la información y también nos permite recibir los datos que el servicio Web nos envía.Veremos el código que habría que cambiar para que funcione el proyecto para acceder al servicio Web conversor de temperaturas.
Lo primero que no necesitamos es el control Inet, por tanto puedes quitarlo del formulario, así como la referencia que tenemos (en Proyecto/Componentes...).
También puedes quitar el evento Intet1_Statechanged ya que no lo necesitaremos.Aquí (dentro de unas líneas) te voy a mostrar el nuevo código. Lo primero que tendrás que hacer es sustituir el código de los eventos Click de los dos botones de conversión, además de añadir un par de nuevos procedimientos para enviar y recibir la información del servicio Web.
Aunque antes te voy a explicar un poco cómo funciona el objeto XMLHTTPRequest y cómo usarlo.Cuando enviamos un comando POST (ahora veremos cómo), se envía el comando al servicio Web (igual que hacíamos con el control Inet) y el servicio Web nos devolverá una respuesta, esa respuesta tendrá que procesarla también el objeto XMLHTTPRequest. Como puede ser que la respuesta tarde en llegar, se podría hacer que se nos notificara cuando esa respuesta llegue (forma asíncrona) o también podemos esperar hasta que la respuesta llegue y después continuar (forma síncrona). Esta última será la forma que vamos a utilizar, ya que la otra (la asíncrona) necesita algo de más código e incluso la creación de una clase, que sería la que recibiera la notificación de que se ha terminado de recibir los datos desde el servidor.
Nota:
Si quieres ver cómo se hace esto último te recomiendo que te bajes el Microsoft XML 4.0 Parser SDK y en la documentación está cómo hacerlo, (este otro link te llevará a la documentación de MSXML 4.0 SDK en línea y en inglés).
Si tienes la documentación del mencionado SDK puedes buscar estos temas:
Use the onReadyStateChange Property (Visual Basic)
Make XML Requests Over HTTP (Visual Basic)
Program with DOM in Visual BasicBueno, ahora si vamos a ver el código.
Si quieres bajarte el código ya "hecho", pulsa este link. ClienteVB6CF2.zip 8.91 KBEl código de los dos eventos Click (este código tendrás que reemplazarlo del código mostrado anteriormente)
Private Sub cmdC2F_Click() tipo = deCaF ' Dim parser As DOMDocument Set parser = New DOMDocument ' cargar el código SOAP para CaF parser.loadXML cSOAPCaF ' ' Indicar el parámetro a enviar parser.selectSingleNode("/soap:Envelope/soap:Body/CaF/valor").Text = txtC.Text ' ' Mostrar el código XML enviado al servicio Web Text1.Text = parser.xml ' ' enviarComando parser.xml, "http:"//elGuille/WebServices/CaF" ' End Sub Private Sub cmdF2C_Click() tipo = deFaC ' Dim parser As DOMDocument Set parser = New DOMDocument ' cargar el código SOAP para FaC parser.loadXML cSOAPFaC ' ' Indicar el parámetro a enviar parser.selectSingleNode("/soap:Envelope/soap:Body/FaC/valor").Text = txtF.Text ' ' Mostrar el código XML enviado al servicio Web Text1.Text = parser.xml ' ' enviarComando parser.xml, "http:"//elGuille/WebServices/FaC" ' End SubEl nuevo código para enviar el comando al servicio Web y el que procesa el código recibido del servicio Web.
Private Sub enviarComando(ByVal sXml As String, ByVal sSoapAction As String) ' Enviar el comando al servicio Web ' ' usar XMLHTTPRequest para enviar la información al servicio Web Dim oHttReq As XMLHTTPRequest Set oHttReq = New XMLHTTPRequest ' ' Enviar el comando de forma síncrona (se espera a que se reciba la respuesta) oHttReq.open "POST", txtURL.Text, False ' las cabeceras a enviar al servicio Web ' (no incluir los dos puntos en el nombre de la cabecera) oHttReq.setRequestHeader "Content-Type", "text/xml; charset=utf-8" oHttReq.setRequestHeader "SOAPAction", sSoapAction ' enviar el comando oHttReq.send sXml ' ' este será el texto recibido del servicio Web procesarRespuesta oHttReq.responseText ' End Sub Private Sub procesarRespuesta(ByVal s As String) ' procesar la respuesta recibida del servicio Web Text1.Text = s ' ' Poner los datos en el analizador de XML Dim parser As DOMDocument Set parser = New DOMDocument parser.loadXML s ' On Error Resume Next ' If tipo = deCaF Then txtF.Text = "Error" txtF.Text = parser.selectSingleNode("/soap:Envelope/soap:Body/CaFResponse/CaFResult").Text Else txtC.Text = "Error" txtC.Text = parser.selectSingleNode("/soap:Envelope/soap:Body/FaCResponse/FaCResult").Text End If ' If Err.Number > 0 Then Text1.SetFocus End If End SubSi observas los cambios, te darás cuenta que usando el objeto XMLHTTPRequest tenemos que indicar las cabeceras enviadas al servicio Web se indica usando el método setRequestHeader y el código XML se envía con el método send.
En fin... espero que ahora sepas otra forma de comunicarte con un servicio Web XML creado con .NET
Nos vemos.
Guillermo