Uno de los temas más comunes en el proceso de acceso a datos en ambientes heterogéneos es el cómo brindar soporte a diferentes aplicaciones con distintas tecnologías a múltiples servidores. Quizás así suene complicado de imaginar pero hagamos un ejemplo práctico, supongamos que tenemos 3 aplicativos que necesitan acceder a datos y estos se encuentran en 3 fuentes de datos diferentes ¿Cómo hacemos? La respuesta no es simple y depende de las condiciones particulares de cada necesidad, pero una de las formas más comunes para atacar este inconveniente es el uso de Servicios Web (Web Services).
Los Servicios Web permiten brindar acceso a operaciones a través de protocolos específicos que facilitan las operaciones, además de que están soportados en diferentes lenguajes de programación y plataformas. No entraré en profundidad en este tema pues no es la idea del post pero si deseas saber más puedes consultar aquí.
Empecemos, lo primero que haremos es ir a nuestro Visual Studio y crear un proyecto Web de tipo Aplicación web vacía de ASP.NET, le das el nombre que prefieras, en mi caso he escogido «WebServiceDemo» y seleccionamos Aceptar con lo que se generará el proyecto. Una vez cargado el proyecto presionaremos ctrl+mayúsculas+a para agregar un nuevo elemento y seleccionaremos Servicio Web, le asignaremos un nombre descriptivo corto y hacemos clic en Aceptar, en mi caso utilizaré como nombre «Demo.asmx», se desplegará un archivo con el siguiente código:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; namespace WebServiceDemo { /// <summary> /// Descripción breve de Demo /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] // Para permitir que se llame a este servicio Web desde un script, usando ASP.NET AJAX, quite la marca de comentario de la línea siguiente. // [System.Web.Script.Services.ScriptService] public class Demo : System.Web.Services.WebService { [WebMethod] public string HelloWorld() { return "Hello World"; } } }
Del código anterior existen varias cuestiones que debemos tener en cuenta, la primera es que una vez en producción debemos cambiar el namespace en la etiqueta [WebService(Namespace = «http://tempuri.org/»)] por un URI significativo, puede consultar las recomendaciones de la W3C al respecto aquí (en inglés). La siguiente es que si planificamos utilizar scripts AJAX (como bien lo indica el comentario) se debe descomentar la línea con la etiqueta [System.Web.Script.Services.ScriptService].
Lo siguiente que observaremos que es ya está implementado un método Web llamado «HelloWorld» que devuelve una cadena (string) que no recibe parámetros y está adornada con la etiqueta [WebMethod] lo que habilita las acciones para que este método esté disponible como parte del servicio. Si ejecutamos el proyecto tal como está se desplegará una página en la que se muestran diferentes operaciones que tiene el Servicio Web, en este caso se mostrará «HelloWorld», adicionalmente se verá la advertencia del espacio de nombres (namespace) junto con instrucciones de cómo corregir esto. Podemos visualizar también la descripción del servicio.
Si hacemos clic en «HelloWorld» podemos ver la página en la que podemos hacer la invocación para probar el servicio y además se muestran ejemplos de solicitudes y respuestas tanto en SOAP como en HTTP POST. Al hacer clic en invocar veremos que se nos muestra el XML con la respuesta que esperábamos.
Invocamos el método y veremos el resultado que esperábamos en XML :
En efecto, esto no parece muy útil así que vamos a modificar el servicio por algo más «útil», en primera instancia convertiremos HelloWorld en HolaFulano y al mismo le agregaremos un parámetro de tipo string llamado «nombre» y que será el nombre para el saludo. El código quedará como el siguiente:
[WebMethod] public string HolaFulano(string nombre) { if (String.IsNullOrEmpty(nombre)) { return "Hola desconocido"; } return String.Format("Hola {0}",nombre); }
Volveremos a compilar y ejecutar el proyecto y nuevamente entramos a la página de pruebas y veremos que ahora existe un campo donde podremos escribir el parámetro.
Escribiremos el nombre para probar e invocamos la petición y obtendremos algo como esto:
Con esto ya hemos probado un poco el uso de parámetros así que finalmente haremos algo más interesante, si has visto los post anteriores recordarás que tengo una base de datos en la que existe una tabla llamada Autores y que tiene 3 campos, idAutor, Nombre y Apellido, así que utilizaremos esto para el ejemplo, para ello, crearemos una nueva operación llamada «obtenerAutor» y agregaremos código para consultar la base de datos y obtener el nombre y apellido de un autor suministrándole el id del autor. El código se verá como sigue:
[WebMethod] public string getAuthor(int idAutor) { string constr = "Data Source=SASHA\MSSQL11;Initial Catalog=tiendaDeLibros;Integrated Security=True"; string query = "SELECT Nombre, Apellido FROM Autores WHERE idAutor = @id"; SqlConnection conexion = new SqlConnection(constr); SqlCommand comando = new SqlCommand(query, conexion); comando.Parameters.AddWithValue("@id", idAutor); try { conexion.Open(); SqlDataReader dr = comando.ExecuteReader(); string retval; if (dr.HasRows) { dr.Read(); retval = String.Format("{0} {1}", dr.GetString(0), dr.GetString(1)); } else { retval = "No disponible"; } return retval; } catch (Exception ex) { return ex.Message; } }
Primero les digo que el código anterior no representa las mejores prácticas y se utiliza sólo con fines de demostración, dicho esto, el código es bastante auto-explicativo por lo que no me detendré mucho en ello. Lo primero es que existen ahora 2 operaciones en el servicio Web, la primera es la que habíamos visto anteriormente y la segunda la que acabamos de crear.
Compilamos y ejecutamos, ahora podremos apreciar que aparecen las 2 operaciones en la lista que se muestran en la página del servicio Web:
Seleccionaremos «obtenerAutor» que es el que deseamos probar y vamos a su página de prueba:
Y finalmente proporcionamos el id del autor e invocamos el servicio para obtener finalmente un documento XML con el resultado que esperamos:
Bien, ahora pueden experimentar diversas combinaciones con respecto a los tipos de entrada y salida, algo que es importante acotar es que cuando se tratan tipos de datos complejos (clases, listas, otros) la página de pruebas no está disponible, en estos casos será necesario implementar algún aplicativo de pruebas.
Esperando que haya sido de utilidad, hasta una próxima.