Menu

¿Cómo depurar un Servicio Web?

octubre 18, 2012 - Delphi

Índice

● Introducción
● Crear Aplicación SOAP Servidor
● Crear la aplicación Cliente
● Probando la depuración de nuestro Web Service
● Descargas


Introducción


 

Hace tiempo escribí dos pequeños tutoriales acerca de los Servicios Web, el primero Crear y consumir un WebService con Delphi (Parte I, II y III) y el segundo  Consumir WebService con acceso a Base de Datos.

Ahora he creado una tercera entrega a raíz de un hilo de mi amigo y colega Marc en los foros de la Comunidad DelphiAccess, donde preguntaba ¿Un WebService no puede usar Componentes no gráficos? , y durante las preguntas y respuestas, vi la necesidad de desarrollar un nuevo tutorial aprovechando la experiencia que he adquirido en la creación y consumo de Servicios Web y específicamente por la necesidad de contar con documentación de cómo depurar y encontrar de una forma «amable» problemas que no se pueden ver a simple vista.

Dado que éste tutorial no se centra en el desarrollo del Servicio Web, sino en como depurarlo, vamos a utilizar lo que ya vimos en el primer tutorial de ésta serie, usando las operaciones aritméticas básicas, Suma, Resta, Multiplicación y División y por tal razón me tomo el atrevimiento de hacer un «copy&paste» de dicho tutorial para enfocarnos en el tema de la depuración.

Éste tutorial fué desarrollado con XE3 pero puede realizarse con XE y XE2 también, para versiones anteriores a XE se desarrollará otro tutorial ya que se crea de forma diferente, en breve lo publicaré.

Como siempre, agradeceré todos los comentarios y críticas (en cualquier sentido) de éste tutorial.

regresar al Índice


Crear Aplicación SOAP Servidor


 

Comenzaremos creando nuestra Aplicación Servidor siguiendo los pasos que ya habíamos visto: File, New, Other, WebServices, seleccionamos SOAP Server Application y finalmente presionamos OK.

En Delphi XE2 y XE3 se mostrará una ventana donde elegiremos la opción Stand-Alone VCL application la cual es un servidor Web que es mostrado en una aplicación VCL y que utiliza el componente Indy HTTP Server. Presionamos el botón [Next>>] para continuar.

La versión XE de Delphi nos proporciona dos opciones para crear el depurador, en éste tutorial vamos a ver sólo la creación de una aplicación Stand Alone y elegiremos la opción Indy VCL Application, la otra opción llamada Web App Debuguer executable, la trataremos en un tutorial aparte ya que su funcionamiento es diferente y un poco más elaborado y es la que las versiones anteriores a XE traen por omisión.

La siguiente ventana nos preguntará que puerto queremos usar para que la aplicación Web escuche las peticiones del programa cliente, cuenta con un botón [Test Port] para asegurarnos que el puerto seleccionado no esté en uso por otra aplicación. Si se desea se puede utilizar un puerto seguro HTTPS, para éste tutorial utilizaremos el puerto 8080. Para continuar presionamos el botón [Finish].

En esta parte ya podemos ver que Delphi nos creó una aplicación VCL con todo lo necesario para iniciar y detener el servicio Web y nos preguntará si queremos crear la interfaz del módulo SOAP, presionamos el botón [No] ya que vamos a aprovechar el código que se tiene del primer tutorial que realizamos (Si ya cuentas con un servicio web, utiliza las unidades de implementación y de interfáz; si no, al final encontrarás un enlace donde prodrás descargar el código de éste tutorial).

Con el clásico Copy&Paste, agregamos a nuestro proyecto las unidades del servicio Web que creamos en nuestro primer tutorial y copiamos específicamente las unidades de Interfaz y de Implementación, en éste caso wsServerIntf.pas y wsServerImpl.pas respectivamente.

Finalmente agregamos las unidades que copiamos a nuestro proyecto y estamos listos para ejecutar nuestro depurador, una vez en ejecución, podemos ver que tiene un botón para iniciar y otro para detener nuestro servicio Web, una caja de texto para asignar el puerto http que queremos utilizar en nuestro depurador y un botón que nos abrirá el explorador de internet para ver la estructura de nuestro servicio Web.

Presionamos el botón [Start] y es posible que Windows te pida autorización para desbloquear la aplicación, como lo muestro en la siguiente imagen, presiona el botón [Permitir acceso] para continuar.

Una vez que hemos permitido el acceso a nuestra aplicación, presionamos el botón [Open Browser] e inmediatamente nos mostrará la página de información de nuestro Servicio Web. Damos clic en el enlace al WSDL del tipo de puerto IwsServer como se muestra en la siguiente imagen y como preparación de nuestro siguiente capítulo Crear la aplicación Cliente

regresar al Indice


Crear la aplicación Cliente


 

Después de dar clic al enlace WSDL, veremos una página con la definición de los métodos de nuestro servicio Web, seleccionamos la url de la página y la copiamos para utilizarla en la creación de la aplicación cliente que consumirá nuestro sevicios Web.

Abrimos otra instancia de Delphi para crear la aplicación cliente y creamos un nuevo proyecto VCL, posteriormente importamos el WSDL y para ello damos clic en File –> New –> Other –> WebServices –> WSDL Importer, éste «asistente» importa el documento WSDL y genera todas las definiciones de clases necesarias para llamar los servicios Web usando un objeto de interfaz remota llamado THTTPRIO. Presionamos el botón [OK] para continuar.

La siguiente pantalla no permitirá especificar la dirección URL donde está publicado el documento WSDL, como ya tenemos la ubicación del WSDL en el portapapeles, sólo pegamos la URL copiada. También nos permite especificar los datos de autenticación para acceder al documento WSDL, como son, Usuario, Contraseña y Proxy si tuviese. Para continuar presionamos el botón [Next>>].

La siguiente pantalla nos permitirá seleccionar la versión SOAP que es usada por el documento WSDL, ésta puede ser 1.1 o 1.2, pero también podemos permitir que se seleccione la versión automáticamente. Para prevenir un error porque la versión no coincida, se recomienda elegir la opción Automatic SOAP versioning

Finalmente se nos muestra la pantalla de Opciones de importación del WSDL, donde se podrá configurar la forma como el «asistente» generará el código para representar las definiciones del documento WSDL, por lo general, se debe de utilizar las opciones que por defecto están seleccionadas, ya que dichos valores proporcionarán la forma más segura de importar documentos WSDL. Para terminar el asistente presionamos el botón [Finish]

Ya tenemos la clase que nos permitirá consumir los métodos de nuestro servicios Web. Ahora sólo nos queda crear la interfaz de usuario, para no aburrirlos sólo les mostraré la aplicación después de agregar los componentes necesarios (Si desean ver el detalle pueden leer la sección correspondiente del primer tutorial de ésta serie donde se muestra el paso a paso). De cualquier forma, al final de éste tutorial podrán acceder al código fuente de todo el ejercicio.

A continuación les muestro el código para cada método del servicio Web, es realmente simple.

 

 
unit Unit1;

interface

uses
  Vcl.Forms, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Controls,
  System.SysUtils, System.Classes,
  IwsServer2;

type
  TForm1 = class(TForm)
    btnSuma: TButton;
    btnResta: TButton;
    btnMultiplica: TButton;
    btnDivide: TButton;
    leValor1: TLabeledEdit;
    leValor2: TLabeledEdit;
    btnCerrar: TButton;
    leResultado: TLabeledEdit;
    procedure btnSumaClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnRestaClick(Sender: TObject);
    procedure btnMultiplicaClick(Sender: TObject);
    procedure btnDivideClick(Sender: TObject);
    procedure btnCerrarClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Server: IwsServer;

implementation

{$R *.dfm}

procedure TForm1.btnSumaClick(Sender: TObject);
begin
  leResultado.Text := format('%f',[Server.Suma(strtofloat(leValor1.Text),
                                           strtofloat(leValor2.Text))]) ;
end;

procedure TForm1.btnRestaClick(Sender: TObject);
begin
  leResultado.Text := format('%f',[Server.Resta(strtofloat(leValor1.Text),
                                            strtofloat(leValor2.Text))]) ;
end;

procedure TForm1.btnMultiplicaClick(Sender: TObject);
begin
  leResultado.Text := format('%f',[Server.Multiplica(strtofloat(leValor1.Text),
                                                  strtofloat(leValor2.Text))]);
end;

procedure TForm1.btnDivideClick(Sender: TObject);
begin
  leResultado.Text := format('%f',[Server.Divide(strtofloat(leValor1.Text),
                                              strtofloat(leValor2.Text))]);
end;

procedure TForm1.btnCerrarClick(Sender: TObject);
begin
  close;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Server := GetIwsServer();
end;

end.

regresar al Índice


Probando la depuración de nuestro Web Service


 

Ya tenemos nuestro proyecto terminado, Servidor y Cliente, ahora sólo nos resta probar que realmente funciona. Para ello, abrimos nuestro proyecto «Server» y agregamos «BreakPoints» en los 4 métodos como se muestra en la siguiente imagen.

Antes de ejecutar nuestros proyectos, vamos a agregar unas líneas a la clase generada por el importador WSDL en nuestra aplicación cliente que en éste caso se llama IwsServer1.pas, dado que los servicios Web reciben las peticiones y su respuesta es de inmediato, es necesario agregar timeouts para que no se reciban errores por estar depurando nuestro servicio Web, basta con agregar tres lineas a dicha clase.

 

      RIO.HTTPWebNode.ConnectTimeout := 120000;
      RIO.HTTPWebNode.SendTimeout := 120000;
      RIO.HTTPWebNode.ReceiveTimeout := 120000;

 

Éstas líneas deben agregarse en la función GetIwsServer como se muestra en la siguiente imagen.

Ya podemos ejecutar nuestro servicio web en modo de depuración (F9) y nuestra aplicación Cliente sin depurador (Ctrl+Shift+F9).

Asignamos los valores a cada uno de los campos de edición y presionamos la operación que se desea depurar, en éste caso se ha presionado el botón de división y una vez que se ha presionado, el servicio Web es detenido en el método correspondiente, podemos entonces ir paso a paso por cada una de las líneas y ver qué es lo que se está ejecutando en cada una.

Con ésto hemos terminado éste sencillo ejercicio, espero que les proporcione las bases para poder crear sus propios depuradores de servicios Web.

regresar al Índice


Descargas


Si lo deseas puedes descargar el código fuente de éste tutorial, espero te sea de utilidad.

[download id=»1″]
[download id=»2″]


 

———-Éste tutorial y su código fuente son libres para su uso y publicación, lo único que te pido es mencionar la fuente.

 

20 pensamientos sobre “¿Cómo depurar un Servicio Web?

Neftalí -Germán Estévez-

Fantastico tutorial eliseo, un muy buen inicio para «estrenar» el blog.

Un saludo.

Respuesta
EliseoGN

Gracias Germán, estamos intentando colaborar con nuestro granito de arena, espero algún día tener la calidad de muchos otros compañeros blogueros, por lo pronto como dicen por ahí «es lo que hay» :).

Saludos

Respuesta
Edgar

Esto si que nos hacia falta al momento de trabajar con nuestros servicios web…

gracias por el tutorial

Respuesta
    EliseoGN

    Espero que te sea de utilidad brother

    Saludos

    Respuesta
Delphius

Yo me leí en su momento tus tutos, y ahora este.
Espero algún día estudiar del tema.

Saludos,

Respuesta
    EliseoGN

    Gracias por leerme amigo Marcelo.

    Saludos

    Respuesta
Alex

Estimado, buenas tardes, soy chileno y trabajo con delphi.
Por favor me podrias ayudar???. Tengo una aplicación de webservice standalone en delphi 7, pero al consumirla por php me arroja un error de timeout, ¿sabes porque razon sucede esto?.
La aplicación la hice hace un par de años, y ahora al retomar ese proyecto, me comenzo a dar esos problemas, que antiguamente no tenia.
En php ocupo la libreria «nusoap».
Estare muy agradecido si me puedes ayudar.. de antemano muchas gracias.
Slds,
Alex.

Respuesta
EliseoGN

Ya te contesté en Club Delphi. Gracias por leer esté espacio.

Saludos

Respuesta
EliseoGN

Hola, he visto que ya hay descargas del código fuente, ¿ Alguien tendrá comentarios acerca de éste tutorial ?

Me gustaría tener retroalimentación sobre el tema.

Muchas gracias por su interés en el código.

Saludos

Respuesta
Osain115

Muchas Gracias, verificare el codigo y realizare el comentario constructivo, tratare de adaptarlo para ISAPI…

Respuesta
    Osain115

    Hola Eliseo, Te cuento que segui paso a paso el tutorial y me funciono muy bien. Gracias!, por cierto. Al ver como realizaste el desarrollo de este proyecto segui la metodologia para la creacion de una dll para un web site. cree las funciones y procedimientos en un proyecto SOAP, luego realice el proceso de la WSDL Importer. Seguidamente cree otro proyecto, el del cliente, pero no utilizando una aplicacion vcl sino WEb Server Aplication, mediante ISAPI dynamic link library, desde alli cree la instancia de la wsdl y empece a utilizar las funciones y procedimientos del proyecto inicial, (me funciono muy bien de hecho). Finalmente segui este manual para crear el WebServices mediante la aplicacion VCl, importe mis archivos .pas : WebSiteIntl y WebSiteIntf donde estan las funciones y coloque los «breakpoints», como lo indicas. El problema es que al ser una aplicacion Web me encuentro con los siguientes problemas: 1) ejecuto en modo de depuracion (F9) el proyecto WebServices, inicio el servicio, posteriormente me arroja un mensaje diciendome que el puerto esta en uso, (esto porque el website esta corriendo por el IIS), entonces detengo el servicio en el IIS y lo ejecuto por la aplicacion, abro el index.htm de mi aplicacion y en vez de llevarme al sitioweb me abre la ventana del WSDL.
    2) Ejecuto la aplicacion web en un puerto distinto al que tengo configurado en el WebServices, para poder activar el IIS y lanzar el site, al abrir el site me carga correctamente, pero al utilizar las opciones no se detiene en los «breakpoints».
    3) trate de crear un log para de esta forma depurar el site, pero tampoco funciona por no ser una aplicacion VCL.

    Mi proposito es poder depurar mi WEBSITE utilizando los «breakpoints» de delphi, vi una luz con tu tutorial pero ahora ya no se como mas probar, suelo colocar variables que me muestren las exepciones en el site, pero no todas son por errores entonces no he podido avanzar mucho con esto. De antemano te agradezco si me puedes ayudar o por lo menos darme un consejo para depurar mi website en el codigo.

    si necesitas mas informacion, codigo o lo que sea, con gusto te lo enviare.

    Respuesta
      EliseoGN

      Hola Osain115

      Muchas gracias por la retroalimentación, es grato ver que es funcional.

      Referente a tu problema, ¿que versión de Delphi estás utlizando?.

      Hasta donde tengo entendido y como se hacia en versiones anteriores a XE2, el depurador se genera como una versión paralela al webservice, es decir, simula la operación real generando su propio ambiente y no debería de chocar. Sin embargo, no lo he hecho como Aplicación Web-Server.

      Si lo deseas envíame lo que has hecho y con gusto lo vemos, espero que podamos encontrar la solución.

      Saludos y gracias

      Respuesta
Juan Pablo Trípodi

Hola Eliseo: leo tus tutoriales y comentarios desde hace mucho tiempo. Empezamos (somos varios programando)a introducirnos en el mundo webServices con tus tutoriales de delphiaccess (los encontré primeo allí).
Estamos haciendo un WS para una aplicación WEB (de un tercero). Necesitamos administrar un SocketServer(SSv) para enviar mensajes a aplicaciones de escritorio (propias) en una intranet. Hicimos aplicaciones con el SSv y con SocketClient (SCl) y funcionan perfecto.
La idea es «tranformar» la aplicación SSv en un WS.
Dentro del WS, hasta ahora, logramos conectar el SSv y las aplicaciones con SCl se conectan. Pero luego, no logramos que los SSv y SCl capturen los eventos.
Sospecho que hay alguna «superposición» de recursos/variables globales para poder usar SocketServer dentro del WS. Alguna pista?? hay algún truco??

Saludos y muchas gracias.
Si lo logro antes prometo publicar…

Respuesta
EliseoGN

Hola Juan Pablo, gracias por el comentario y me alegra que de algo sirvan mis publicaciones aún y cuando son muy básicas.

Respecto a tu duda

Un Webservice es un servicio que funciona «OnDemand», es decir, el programa que consume el servicio web es quien ejecuta los métodos que están definidos en el WebService y no al contrario.

Si quieres enviame un correo con el esquema de tu WebService y ver que podemos hacer al respecto.

Saludos

Respuesta
    Juan Pablo Trípodi

    hola Eliseo, gracias por tu respuesta.
    En la implementación del WS creamos el SocketServer y lo conectamos a un puerto. Cuando hacemos esto, todos los Socketclients se conectan. Pero el SocketServer no recibe los eventos de conección de los clientes, «onClientConnect».
    Pusimos el SocketServer dentro de un formulario que se crea al iniciar la aplicación. Hacemos debug con el método que vos proponés aquí. A pesar de que los clientes se conectan, el server no los agrega.
    TServerWinSocket.GetActiveConnections == 0.
    En Debug, la ejecución nunca entra a TServerWinSocket.AddClient.
    Seguiré investigando, voy a hacer un ejemplo sencillo y te lo envío por mail.
    Nada mejor que un problema difícil para encender las neuronas.
    saludos y gracias desde Argentina!!

    Respuesta
      EliseoGN

      Espero el ejemplo, ojalá y pueda ayudarte a resolver éste detalle.

      Saludos

      Respuesta
Javier

Hola Eliseo, veo q usás procedure y no function …. hay problemas al usar function?.
Hice la prueba y da access violation cuando evalúa los nodos hijos del body en xml…
Hay alguna razón especial para no usar function?

Respuesta
    EliseoGN

    Que tal Javier, no tengo motivo o razón para preferir uno u otro, cuando te genera access violation, normalmente es por dos causas, porque no se ha creado el objeto y/o porque no estás recibiendo el XML y quieres procesar un objeto vacío.

    Si puedes mostrarme en que parte salta el error, intentaremos darle solución.

    Saludos

    Respuesta
      Javier

      Hola Eliseo, después de pelear mucho con el tema, deduje que no debo hacer web services en Delphi. No funciona ninguno.
      Como decía otro comentarista, no se puede depurar, porque al darle F9, como es un dll, exige un proceso al cual attacharse, ese proceso, sería el ejecutable del programa que lo consume… Hasta ahí todo bien.
      Cuando el consumidor ejecuta un método a través de la clase HTTPRIO siempre lo resuelve la clase, y nunca accede al dll.
      Al menos hasta ahora nunca llegué a ese resultado.
      Probando con Delphi XE3 cuando compila la dll, genera en la sección port en services, un «location» con el path soap en lugar de wsdl. Nunca pude revertir eso. Entonces, cuando el consumidor importa la definición wsdl le viene así:

      const
      defWSDL = ‘http://172.31.31.4/motos/wsMotos.dll/wsdl/IwsMotos’;
      defURL = ‘http://172.31.31.4/motos/wsMotos.dll/soap/IwsMotos’;
      defSvc = ‘IwsMotosservice’;
      defPrt = ‘IwsMotosPort’;
      var
      RIO: THTTPRIO;
      …..
      Fijate q en la defURL usa soap y en la defWSDL usa wsdl.
      Cuando el componente HTTPRIO intenta llamar a algún método definido en el dll, invoca al defURL, el cual no existe, devuelve un HTML idéntico al que se genera cuando uno escribe en el navegador http://172.31.31.4/motos/wsMotos.dll
      entonces, eso da un access violation porque espera contenido XML y recibe un HTML. En ningún lado tengo definido q sea soap, el WebModule del dll tiene PathInfo en WebDispatch como wsdl* y el WSDLHTMLPublish también en el PathInfo tiene wsdl*, sin embargo en el wsdl generado tras compilar pone soap!!

      Es un error de las clases internas de SOAP en XE3, supongo, hasta acá nunca llegó a contactar con el dll

      Respuesta
        EliseoGN

        Que tal Javier, en la llamada al Servicio Web tienes dos opciones, a través de su wsdl o a través del soap, el método Get..PortType tiene tres parámetros (UseWSDL: Boolean=System.False; Addr: string=»; HTTPRIO: THTTPRIO = nil)

        Dentro de ese método tiene filtros

        if (Addr = ») then
        begin
        if UseWSDL then
        Addr := defWSDL
        else
        Addr := defURL;
        end;

        Es decir, por default utiliza defURL ya que si no pasas parámetros a ese método asignará a la Addr el valor de defURL.

        Me gustaría ver tu código para darte una respuesta más certera.

        Si me envías un mensaje desde la página de contacto, nos ponemos de acuerdo.

        http://www.delphienmovimiento.mx/contactame/

        Saludos

        Respuesta

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *