Índice de la sección dedicada a .NET (en el Guille) Cómo... en .NET

Usar un servicio Web XML desde VB6

Publicado el 20/Jun/2003
Actualizado el 29/Jun/2003 (14/Dic/03)

Modificación para NO usar el Internet Transfer Control para acceder al servicio Web (29/Jun/03)

 

 

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.Text

Con 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 Web

Sí, 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?


Código para Visual Basic 6

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 Basic

Bueno, ahora si vamos a ver el código.
Si quieres bajarte el código ya "hecho", pulsa este link. ClienteVB6CF2.zip 8.91 KB

El 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 Sub

El 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 Sub

Si 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


la Luna del Guille o... el Guille que está en la Luna... tanto monta...