Jump to content


Photo

Crear y consumir un WebService con Delphi (Parte I, II y III)


  • Please log in to reply
41 replies to this topic

#1 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 10 December 2008 - 04:20 PM

Crear la Aplicación Servidor:


Crear un nuevo proyecto
 

File, New, Other, WebServices, SOAP Server Application

 

WS_1.png

 

En este caso práctico se ha decidido usar ISAPI/NSAPI Dynamic Link Library
 

WS_2.png

 

Aceptamos crear la interfase del módulo SOAP
 

WS_3.png

 

Agregamos un nuevo WebService y le asignamos un nombre en este ejemplo utilicé wsDemo y asignamos la generación de código que tiene por omisión.
 

WS_4.png

 

Delphi nos creará las unidades correspondientes, veamos como se generó la interfase invocable de nuestro proyecto wsDemoIntf.pas
 

WS_5.png

 

El siguiente paso es darle forma a las funciones que deseamos utilizar, usaremos operaciones aritméticas básicas (suma, resta, multiplicación y division) y se deben incluir dentro del cuerpo de nuestra interfáz.

Dichas funciones cuentan con dos parámetros de entrada A y B y un retorno, todos de tipo "double". 
 


delphi
  1. { Invokable interface IwsDemo }
  2.  
  3. unit wsDemoIntf;
  4.  
  5. interface
  6.  
  7. uses InvokeRegistry, Types, XSBuiltIns;
  8.  
  9. type
  10.  
  11. { Invokable interfaces must derive from IInvokable }
  12. IwsDemo = interface(IInvokable)
  13. ['{4C3D382F-31E7-4B42-B7DA-CB48311D7D71}']
  14. { Methods of Invokable interface must not use the default }
  15. { calling convention; stdcall is recommended }
  16.  
  17. function suma(const A,B: double): double; stdcall;
  18. function resta(const A,B: double): double; stdcall;
  19. function multiplicacion(const A,B: double): double; stdcall;
  20. function division(const A,B: double): double; stdcall;
  21.  
  22. end;
  23.  
  24. implementation
  25.  
  26. initialization
  27. { Invokable interfaces must be registered }
  28. InvRegistry.RegisterInterface(TypeInfo(IwsDemo));
  29.  
  30. end.

 
También se ha creado una unidad wsDemoImpl.pas para la implementación de la clase que será invocada, en la cual copiaremos las funciones creadas en la unidad wsDemoIntf.pas
 


delphi
  1. { Invokable implementation File for TwsDemo which implements IwsDemo }
  2.  
  3. unit wsDemoImpl;
  4.  
  5. interface
  6.  
  7. uses InvokeRegistry, Types, XSBuiltIns, wsDemoIntf;
  8.  
  9. type
  10.  
  11. { TwsDemo }
  12. TwsDemo = class(TInvokableClass, IwsDemo)
  13. public
  14. function suma(const A,B: double): double; stdcall;
  15. function resta(const A,B: double): double; stdcall;
  16. function multiplicacion(const A,B: double): double; stdcall;
  17. function division(const A,B: double): double; stdcall;
  18. end;
  19.  
  20. implementation
  21.  
  22.  
  23. { TwsDemo }
  24.  
  25. function TwsDemo.suma(const A, B: double): double;
  26. begin
  27.  
  28. end;
  29.  
  30. function TwsDemo.resta(const A, B: double): double;
  31. begin
  32.  
  33. end;
  34.  
  35. function TwsDemo.multiplicacion(const A, B: double): double;
  36. begin
  37.  
  38. end;
  39.  
  40. function TwsDemo.division(const A, B: double): double;
  41. begin
  42.  
  43. end;
  44.  
  45. initialization
  46. { Invokable classes must be registered }
  47. InvRegistry.RegisterInvokableClass(TwsDemo);
  48. end.

Ahora, solo nos resta escribir el código de las funciones suma, resta, multiplicación y división.
 


delphi
  1. function TwsDemo.suma(const A, B: double): double;
  2. begin
  3. result := A + B;
  4. end;


delphi
  1. function TwsDemo.resta(const A, B: double): double;
  2. begin
  3. result := A - B;
  4. end;


delphi
  1. function TwsDemo.multiplicacion(const A, B: double): double;
  2. begin
  3. result := A * B;
  4. end;


delphi
  1. function TwsDemo.division(const A, B: double): double;
  2. begin
  3. result := A / B;
  4. end;

Nota: Si alguien se pregunta, que pasará con las excepciones generadas por el divisior cero, es parte del ejercicio, no es un bug   :D
 
 
Fin Parte I


  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 10 December 2008 - 04:22 PM

Crear el directorio virtual de nuestro WebService:

Para realizar esto, ir al Panel de Control, Herramientas Administrativas y abrir el programa Internet Information Services, y crear un directorio virtual dentro de los Sitios Web, Sitio Web Predeterminado, clic derecho del mouse y seleccionar del menu contextual, Nuevo, Directorio Virtual.

Imagen Enviada


Clic en Siguiente y asignamos un Alias a nuestro WebService:

Imagen Enviada


Clic en Siguiente y seleccionamos el directorio que contiene nuestro WebService:

Imagen Enviada


Asignamos los permisos a nuestro directorio virtual, (por omisión no trae seleccionado Ejecutar (ISAPI, CGI), habrá que seleccionarlo para que nuestro directorio funcione correctamente:

Imagen Enviada


Clic en Finalizar y nuestro WebService está listo para ser llamado:

Imagen Enviada


Al llamarlo desde cualquier explorador nos aseguramos que funcione correctamente nuestro WebService:

Imagen Enviada


Imagen Enviada


Fin Parte II
  • 1

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 10 December 2008 - 04:23 PM

Crear la aplicación cliente que consumirá nuestro WebService:

Creamos un nuevo proyecto (VCL Form Application).

Agregamos el WSDL a nuestro proyecto, File, New, Other, WebServices, WSDL Importer.

Imagen Enviada


Clic en OK y nos mostrará una forma para incluir el URL de nuestro WSDL, para obtener esto podemos abrir nuestro WebServices con el explorador de Internet y clic en WSDL, como se muestra a continuación

Imagen Enviada


La dirección que nos muestra es la que debemos de colocar en la ventana que lo solicita.

Imagen Enviada


Imagen Enviada


Clic en Finish y Delphi nos crea la unidad con la que vamos a poder consumir nuestro WebService.

Imagen Enviada


Imagen Enviada


Ahora solo nos resta generar las llamadas a las funciones, para ello incluimos en nuestro proyecto,

2 Componentes Edit para la captura de datos

1 Componente Label para el Resultado

4 Botones (Suma, Resta, Multiplicación y División)

3 Componentes Label para comentarios.

Nos quedaría algo así:

Imagen Enviada


Ahora, agregamos en nuestro proyecto la unidad IwsDemo1 y generamos el código para cada uno de los botones:

Imagen Enviada


Ejecutamos el proyecto y si todo nos quedo como lo soñamos  :D nos mostrará los resultados correspondientes a cada operación.

Suma:

Imagen Enviada


Resta:

Imagen Enviada


Multiplicación:

Imagen Enviada


División:

Imagen Enviada


Con eso hemos terminado nuestro ejemplo teórico/práctico, espero que les haya gustado tanto como a mi y sobre todo que sea de utilidad para futuras aplicaciónes donde se requiera de programación multicapa.

Ah, se me olvidaba, la división en cero nos dará una excepción que debemos de manejar, eso se los dejo de tarea :).

Salud OS

PD, Disfruten de todo lo que nos proporciona nuestra herramienta, siempre hay algo nuevo que aprender.

  • 0

#4 felipe

felipe

    Advanced Member

  • Administrador
  • 3283 posts
  • LocationColombia

Posted 10 December 2008 - 04:30 PM

Que tal Eliseo, algo que quieras corregir en el mensaje  *-)...  :p

Muy buen ejemplo, gracias...
  • 0

#5 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 10 December 2008 - 04:36 PM

Que tal Eliseo, algo que quieras corregir en el mensaje  *-)...  :p

Muy buen ejemplo, gracias...


Gracias amigo, esto es una transcripción del tutorial publicado aquí

Salud OS

PD. Publicado con permiso del autor :p

Edito: Modifiqué la ruta de este artículo a la nueva bitácora :D
  • 0

#6 felipe

felipe

    Advanced Member

  • Administrador
  • 3283 posts
  • LocationColombia

Posted 10 December 2008 - 05:14 PM

Claro Eliseo... son derechos de autor  :D
  • 0

#7 Caral

Caral

    Advanced Member

  • Moderador
  • PipPipPip
  • 4266 posts
  • LocationCosta Rica

Posted 10 December 2008 - 05:26 PM

Hola
Muy bueno amigo, lo voy a probar, se ve sencillo, claro esta muy bien explicado.
Saludos
  • 0

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 10 December 2008 - 05:32 PM

Hola
Muy bueno amigo, lo voy a probar, se ve sencillo, claro esta muy bien explicado.
Saludos


Asi es amigo, es fácil, solo me falto acotar que esto lo hice en una maquina con Windows XP Profesional, parece que por ahi hay problemas con Vista....

Salud OS
  • 0

#9 enecumene

enecumene

    Webmaster

  • Administrador
  • 7419 posts
  • LocationRepública Dominicana

Posted 11 December 2008 - 07:27 AM

Excelente Eliseo (y), pregunta, ¿en vez de usar IIS, puedo trabajar con Apache?.

Saludos.
  • 0

#10 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 11 December 2008 - 09:39 AM

Excelente Eliseo (y), pregunta, ¿en vez de usar IIS, puedo trabajar con Apache?.

Saludos.


Pues no sabria decirte, no uso Apache, pero hasta donde entiendo deberia poderse,

¿Alguien en la sala usa Apache que nos pueda ilustar con este asunto?  *-)

Salud OS
  • 0

#11 axesys

axesys

    Advanced Member

  • Moderadores
  • PipPipPip
  • 640 posts
  • LocationLos Mochis

Posted 05 January 2009 - 11:21 AM

No saben como se puede consumir los webservices de un servidor Glassfish desde delphi 2009?
  • 0

#12 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 05 January 2009 - 11:28 AM

No saben como se puede consumir los webservices de un servidor Glassfish desde delphi 2009?


Vaya, nunca lo habia escuchado, pero buscando vi esto

https://glassfish.de...wsmgmthome.html

Salud OS
  • 0

#13 axesys

axesys

    Advanced Member

  • Moderadores
  • PipPipPip
  • 640 posts
  • LocationLos Mochis

Posted 05 January 2009 - 12:04 PM

Crear los webservices en glassfish si lo puedo hacer. Estos webservices los puedo consumir desde java y .net sin problemas pero en delphi 2009 solo me consume los webservices sin parametros, en cambio cuando mando parametros es como si no mandara nada.

Alguien sabe como consumir los webservices de glassfish usando delphi 2009 con parametros?
  • 0

#14 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 05 January 2009 - 12:10 PM

No le veo problema, deberia de funcionar con parámetros, ya hiciste un debug en tu aplicación para ver que es lo que envía y que es lo que recupera al y del webservices?

Salud OS

Edito: Puedes mostrarnos que es lo que te deja Delphi en el archivo Intf, me refiero a la interfaz invocable y sus funciones.

Salud OS


  • 0

#15 axesys

axesys

    Advanced Member

  • Moderadores
  • PipPipPip
  • 640 posts
  • LocationLos Mochis

Posted 05 January 2009 - 01:05 PM

Este es el codigo que se genera a partir del wsdl


delphi
  1. unit Hola1;
  2.  
  3. interface
  4.  
  5. uses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;
  6.  
  7. const
  8.   IS_OPTN = $0001;
  9.   IS_UNQL = $0008;
  10.  
  11.  
  12. type
  13. Hola = interface(IInvokable)
  14.   ['{B73ACEDC-B21B-A805-777D-C86443A1C94A}']
  15.     function  hola(const arg0: string): string; stdcall;
  16.   end;
  17.  
  18. function GetHola(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): Hola;
  19.  
  20.  
  21. implementation
  22.   uses SysUtils;
  23.  
  24. function GetHola(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): Hola;
  25. const
  26.   defWSDL = 'http://localhost:8080/HolaService/Hola?wsdl';
  27.   defURL  = 'http://localhost:8080/HolaService/Hola';
  28.   defSvc  = 'HolaService';
  29.   defPrt  = 'HolaPort';
  30. var
  31.   RIO: THTTPRIO;
  32. begin
  33.   Result := nil;
  34.   if (Addr = '') then
  35.   begin
  36.     if UseWSDL then
  37.       Addr := defWSDL
  38.     else
  39.       Addr := defURL;
  40.   end;
  41.   if HTTPRIO = nil then
  42.     RIO := THTTPRIO.Create(nil)
  43.   else
  44.     RIO := HTTPRIO;
  45.   try
  46.     Result := (RIO as Hola);
  47.     if UseWSDL then
  48.     begin
  49.       RIO.WSDLLocation := Addr;
  50.       RIO.Service := defSvc;
  51.       RIO.Port := defPrt;
  52.     end else
  53.       RIO.URL := Addr;
  54.   finally
  55.     if (Result = nil) and (HTTPRIO = nil) then
  56.       RIO.Free;
  57.   end;
  58. end;
  59.  
  60.  
  61. initialization
  62.   InvRegistry.RegisterInterface(TypeInfo(Hola), 'http://hola/', 'UTF-8');
  63.   InvRegistry.RegisterDefaultSOAPAction(TypeInfo(Hola), '');
  64.   InvRegistry.RegisterInvokeOptions(TypeInfo(Hola), ioDocument);
  65.  
  66. end.



Y estos son los xml que se envian y reciben por el webservice



xml
  1. Request
  2.  
  3. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Header/><SOAP-ENV:Body><hola xmlns="http://hola/"><arg0>Daniel</arg0></hola></SOAP-ENV:Body></SOAP-ENV:Envelope>
  4.  
  5. Response
  6.  
  7. <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:holaResponse xmlns:ns2="http://hola/"><return>Hola: null</return></ns2:holaResponse></S:Body></S:Envelope>


El código del webservice es



delphi
  1. package hola;
  2.  
  3. import javax.ejb.Stateless;
  4. import javax.jws.WebMethod;
  5. import javax.jws.WebService;
  6.  
  7. @WebService
  8. @Stateless(name = "Hola")
  9. public class Hola {
  10.  
  11. @WebMethod
  12. public String hola(String param) {
  13. return "Hola: " + param;
  14. }
  15.  
  16. }



Me debería regresar "Hola: Daniel" pero regresa "Hola: null"
  • 0

#16 Héctor Randolph

Héctor Randolph

    501st Legion

  • Moderadores
  • PipPipPip
  • 664 posts
  • LocationMéxico

Posted 05 January 2009 - 03:37 PM

Con respecto a utilizar Apache para los servicios web puedo comentar lo siguiente.

En las versiones 6 y 7 de Delphi, se daba soporte para crear servicios web como módulos de Apache, esto ocurría porque en aquel momento se trabajaba en paralelo con las versiones de Kylix, esto obligaba a dejar abierta una opción para generar los servicios en ambientes multiplataforma. Sin embargo, como sabemos este proyecto quedó suspendido y en las nuevas versiones de Delphi se tiene únicamente la opción de crear servicios web para Windows con la tecnología ISAPI/NSAPI (para Microsoft para IIS), o bien, como un ejecutable CGI.

Si tienes instalado Apache en Windows con soporte para CGI, Puedes crear desde Delphi un servicio web con la opción "CGI-Stand-alone executable". Este ejecutable lo debes colocar en la carpeta que Apache destina para los scripts CGI, le cambias la extensión de EXE a CGI y listo lo puedes utilizar desde el servidor web.

CGI no es la tecnología más recomendada para los servicios web, por cuestiones de rendimiento y seguridad. En este caso sería mejor utilizar ISAPI.

Por otra parte puedes instalar un módulo para ISAP en apache http://httpd.apache..../mod_isapi.html, pero esto es un poquito más complicado.

Saludos




  • 0

#17 enecumene

enecumene

    Webmaster

  • Administrador
  • 7419 posts
  • LocationRepública Dominicana

Posted 05 January 2009 - 03:40 PM

Muchas gracias Héctor, me ha sido claro y útil tus comentarios. (y).

Saludos.
  • 0

#18 axesys

axesys

    Advanced Member

  • Moderadores
  • PipPipPip
  • 640 posts
  • LocationLos Mochis

Posted 05 January 2009 - 07:10 PM

Hice la prueba con un webservice de NetWeaver 7.1 y tambien pasa lo mismo que no reconoce el parametro

En cambio si llamo el webservice con Web Service Navigator de NetWeaver los xml enviados y recibidos son diferentes que los de delphi

Parámetros de entrada


delphi
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  3.   <SOAP-ENV:Body>
  4.     <yq1:hola xmlns:yq1="http://demo/">
  5.       <arg0>Daniel</arg0>
  6.     </yq1:hola>
  7.   </SOAP-ENV:Body>
  8. </SOAP-ENV:Envelope>



Resultado


delphi
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  3.   <SOAP-ENV:Body>
  4.     <ns2:holaResponse xmlns:ns2="http://demo/">
  5.       <return>Hola: Daniel</return>
  6.     </ns2:holaResponse>
  7.   </SOAP-ENV:Body>
  8. </SOAP-ENV:Envelope>



Alguien tiene idea de como solucionar esto para que funcione desde delphi tambien?
  • 0

#19 axesys

axesys

    Advanced Member

  • Moderadores
  • PipPipPip
  • 640 posts
  • LocationLos Mochis

Posted 05 January 2009 - 07:28 PM

Con el tester de GlassFish estos son los xml enviados y recibidos

SOAP Request



delphi
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  3. <S:Header/>
  4. <S:Body>
  5. <ns2:hola xmlns:ns2="http://hola/">
  6. <arg0>Daniel</arg0>
  7. </ns2:hola>
  8. </S:Body>
  9. </S:Envelope>




SOAP Response


delphi
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  3. <S:Body>
  4. <ns2:holaResponse xmlns:ns2="http://hola/">
  5. <return>Hola: Daniel</return>
  6. </ns2:holaResponse>
  7. </S:Body>
  8. </S:Envelope>



  • 0

#20 axesys

axesys

    Advanced Member

  • Moderadores
  • PipPipPip
  • 640 posts
  • LocationLos Mochis

Posted 07 January 2009 - 08:10 PM

Ya me funciono solo habia que cambiar esta linea InvRegistry.RegisterInvokeOptions(TypeInfo(Hola), ioDocument); por esta InvRegistry.RegisterInvokeOptions(TypeInfo(Hola), ioDefault); y ya me regresa correctamente "Hola: Daniel"
  • 0




IP.Board spam blocked by CleanTalk.