miércoles, 15 de agosto de 2012

Consumir un Web Service desde Oracle

Hace algún tiempo tuve la oportunidad (a petición de mi jefe) de investigar una forma de consumir un servicio web elaborado con .NET desde un procedimiento o función de Oracle.

Como apenas estaba conociendo esta base de datos y el tan interesante PL/SQL, imaginé que sería algo difícil de conseguir, pero eso es lo que me gusta, así que acepté el reto.

Busqué y encontré varias formas, pero definitivamente lo que más me convenció fué un paquete de oracle llamado SOAP API.

http://www.oracle-base.com/dba/script.php?category=miscellaneous&file=soap_api.sql

Con este paquete, se puede crear una función o procedimiento con el cual se pueda invocar el servicio web; tenemos un ejemplo del uso de este paquete en el siguiente enlace:

http://www.oracle-base.com/articles/9i/consuming-web-services-9i.php

Ahora bien, a veces lo que cuesta con esto es comprender qué es cada cosa, así que vamos en orden.


CREATE OR REPLACE FUNCTION add_numbers (p_int_1  IN  NUMBER,
                                        p_int_2  IN  NUMBER)
  RETURN NUMBER
AS
  l_request   soap_api.t_request;
  l_response  soap_api.t_response;
  l_return    VARCHAR2(32767);
  
  l_url          VARCHAR2(32767);
  l_namespace    VARCHAR2(32767);
  l_method       VARCHAR2(32767);
  l_soap_action  VARCHAR2(32767);
  l_result_name  VARCHAR2(32767);
BEGIN
  l_url         := 'http://www.oracle-base.com/webservices/server.php';
  l_namespace   := 'xmlns="http://www.oracle-base.com/webservices/"';
  l_method      := 'ws_add';
  l_soap_action := 'http://www.oracle-base.com/webservices/server.php/ws_add';
  l_result_name := 'return';


El anterior bloque de código es únicamente para definir variables:

  • l_url es la url real donde se puede acceder al web service.
  • l_namespace es el espacio de nombres del web service. Más información sobre namespaces en este enlace.
  • l_method es el nombre del método del web service que se va a utilizar.
  • l_soap_action es la acción que se requiere en la petición SOAP. Por lo que he visto en el caso de los web services hechos con .NET, suele ser un URI formado por el valor del namespace (el valor de "xmlns") y el nombre del método.
  • l_result_name es el nombre del resultado que nos da el web service. En el caso de web services desarrollados con .NET, el nombre de esta respuesta suele ser el nombre del método seguido por "Result". Ejemplo: "MiMetodoWebResult " si el nombre del metodo es "MiMetodoWeb".



l_request := soap_api.new_request(p_method       => l_method,
                                    p_namespace    => l_namespace);


En esta llamada creamos el requerimiento al web service, noten que le pasamos unicamente el nombre del método y el espacio de nombres.


soap_api.add_parameter(p_request => l_request,
                         p_name    => 'int1',
                         p_type    => 'xsd:integer',
                         p_value   => p_int_1);

  soap_api.add_parameter(p_request => l_request,
                         p_name    => 'int2',
                         p_type    => 'xsd:integer',
                         p_value   => p_int_2);


En este bloque, añadimos los parámetros a nuestro requerimiento. Se debe hacer una llamada por parámetro, indicándole el request, el nombre del parámetro, el tipo del parámetro y el valor del mismo. Para más información acerca de los tipos de parámetros, puede ir a este enlace.


l_response := soap_api.invoke(p_request => l_request,
                                p_url     => l_url,
                                p_action  => l_soap_action);


Con esto ya se invoca el método del web service que vamos a consumir. Es el momento en el que se envía la petición y se obtiene la respuesta por parte del servicio web.


l_return := soap_api.get_return_value(p_response  => l_response,
                                        p_name      => l_result_name,
                                        p_namespace => NULL);


Esta función get_return_value es la encargada de darnos las respuestas que nos da el web service. Nótese que a diferencia de los métodos anteriores, en lugar de la petición, ahora le pasamos como parámetro la "response".

El parámetro p_name se refiere al nombre del resultado; aquí deseo aclarar que, en el caso de .NET, cuando se establecen parámetros en el método web como "ByRef", es que son parámetros pasados por referencia, por lo que cualquier cambio que tengan será reflejado.Así, si por ejemplo, el parámetro int1 estuviera como ByRef en la firma del método ws_add, entonces se puede obtener un valor de esa variable utilizando el método get_return_value, indicándole como p_name el nombre del parámetro tal como en la llamada a la función add_paramenter.

El parámetro p_namespace normalmente no lleva nada o puede llevar también el valor de la variable l_namespace.

Por último, ¿Que tal si al menos uno de los parámetros es un XML? Sencillo, todos los textos con formato XML han de enviarase encerrado por la etiqueta <![CDATA[ ]]>, así:


soap_api.add_parameter(p_request => l_request,
                         p_name    => 'v_xml',
                         p_type    => 'xsd:string',
                         p_value   => '<![CDATA[' || p_xml || ']]>');


Esta es una llamada de muestra, en caso el método web tuviera un parámetro llamado "v_xml" que requiriera un xml pero es tipo string.

Y así, de esta manera, pueden estar realizando una función que consuma un servicio web en unos cuantos minutos.

Espero esto les sea de ayuda y esté lo bastante claro. Saludos.

sábado, 11 de agosto de 2012

FTP y SFTP con Visual Basic .NET

Bien amigos, en esta oportunidad traigo algo interesante que aportar.

Estuve un buen tiempo investigando cómo se pueden hacer transferencias por medio de FTP con VB .NET, cosa que pude encontrar fácilmente en toda la red utilizando la clase FtpWebRequest de .NET.

Sin embargo, la cosa cambia cuando te encuentras en la situación en la que te dan un servidor que no funciona con el FTP simple, sino con una forma más nueva, el cual es el SFTP, y entonces ves cómo cae la ilusión de ver casi terminado tu proyecto.

Bueno, después de un par de maldiciones y mi respectivo vaso con agua, comencé a buscar información del SFTP, y alguna forma de lograr una transferencia con código nativo de Visual Basic .Net.

Lastimosamente, es algo no muy simple de hacer... bueno, NADA SIMPLE.

Finalmente opté por lo más práctico y rápido (por el tiempo, jeje): buscar una librería que me ayudara a realizar transferencias hacia un servidor SFTP, y después de algunos minutos de búsqueda, finalmente...  ¡¡¡la encontré!!!

Lo mejor, es que viene con todo y ejemplo de aplicación. Pueden ver la información en el siguiente enlace:

http://www.brudvik.org/2009/06/sshsftp-client-in-vbnet-with-sources/

Este ejemplo hace uso de las siguientes librerías:

Tamir's SharpSSH: http://www.tamirgal.com/blog/page/SharpSSH.aspx

Librería Crypto de Mentalis.org (esta es dependencia de la anterior): http://www.mentalis.org/soft/projects/crypto/

Ambas librerías están escritas en C#. En las respectivas páginas podrán encontrar el código fuente de ambas, por si quieren echar un vistazo de cómo se logra la conexión y transferencia de archivos con SFTP utilizando código nativo de .NET.

Espero les sea de ayuda.

Un abrazo y saludos.