martes, 10 de enero de 2017

Acceso a Servicios Web SOAP en Android (1/2)

En este primer artículo que vamos a dedicar a los servicios web dentro del Curso de Programación Android nos vamos a centrar en los servicios web que utilizan el estándar SOAP como mecanismo de comunicación.
A diferencia de otros tutoriales, no sólo vamos describir cómo acceder a este tipo de servicios desde una aplicación Android, sino que también veremos como crear un servicio web SOAP mediante ASP.NET para acceder a una base de datos SQL Server. De esta forma pretendo ilustrar la “arquitectura” completa de una aplicación Android que acceda a datos almacenados en un servidor de base de datos externo. Nota: Aunque intentaré aportar el máximo número de detalles, es imposible abarcarlo todo en un solo artículo, por lo que el texto supondrá unos conocimientos mínimos de Visual Studio y del lenguaje C#.
Como caso de ejemplo, vamos a crear una aplicación sencilla capaz de gestionar un listado de “clientes” que contendrá el nombre y teléfono de cada uno de ellos. Nuestra aplicación será capaz de consultar el listado actual de clientes almacenados en el servidor externo y de insertar nuevos clientes en la base de datos. Como siempre, se trata de un ejemplo muy sencillo pero creo que lo suficientemente completo como para que sirva de base para crear otras aplicaciones más complejas.
Como software necesario, en este caso utilizaré Visual Studio 2010 y SQL Server 2008 R2 para crear el servicio web y la base de datos respectivamente.  Podéis descargar de forma gratuita las versiones Express de ambos productos (más que suficientes para crear una aplicación como la que describiremos en este artículo) desde la web oficial de Microsoft. También es recomendable instalar SQL Server 2008 Management Studio Express, descargable también de forma gratuita desde esta web. Esta aplicación no es más que un gestor gráfico para acceder y manipular nuestras bases de datos  SQL Server con total comodidad.
Vamos comenzar por la base de todo el sistema, y esto es la base de datos a la que accederá el servicio web y, a través de éste, también la aplicación Android que crearemos más adelante. Para ello abrimos SQL Server Management Studio, nos conectamos a nuestro servidor SQL Server local, y pulsamos sobre la sección “Databases” del árbol de objetos que aparece a la izquierda. Sobre esta carpeta podemos acceder a la opción “New Database…” del menú contextual para crear una nueva base de datos.
sqlserver-new-database
En el cuadro de diálogo que aparece tan sólo indicaremos el nombre de la nueva base de datos, en mi caso la llamaré DBCLIENTES, y dejaremos el resto de opciones con sus valores por defecto.
sqlserver-new-database-2
Desplegamos el árbol de carpetas de nuestra recién creada base de datos DBCLIENTES y sobre la carpeta “Tables” ejecutamos la opción “New table…” para crear una nueva tabla.
sqlserver-new-table
Vamos a añadir sólo 3 campos a la tabla:
  • IdCliente, de tipo int, que será un código único identificativo del cliente.
  • Nombre, de tipo nvarchar(50), que contendrá el nombre del cliente.
  • Telefono, de tipo int, que contendrá el teléfono del cliente.
Marcaremos además el campo IdCliente como clave principal de la tabla, y también como campo de identidad autoincremental, de modo que se calcule automáticamente cada vez que insertemos un nuevo cliente.
sqlserver-diseno-tabla-identity
Con esto ya tenemos nuestra tabla finalizada, por lo que sólo nos queda guardarla con el nombre que deseemos, que para este ejemplo será “Clientes“.
Hecho, ya tenemos nuestra base de datos SQL Server creada y una tabla preparada para almacenar los datos asociados a nuestros clientes. El siguiente paso será crear el servicio web que manipulará los datos de esta tabla.
Para crear el servicio abriremos Visual Studio 2010 y crearemos un nuevo proyecto web en C# utilizando la plantilla “ASP.NET Empty Web Application“. En un alarde de originalidad lo llamaremos “ServicioWebSoap“.
nuevo-proyecto-web
Una vez creado el proyecto, añadiremos a éste un nuevo servicio web mediante el menú “Project / Add new item…“. Lo llamaremos “ServicioClientes.asmx“.
nuevo-servicio-web
Una vez añadido aparecerá en pantalla el código fuente por defecto del nuevo servicio web, que contiene un único método de ejemplo llamado HelloWorld(). Este método podemos eliminarlo ya que no nos servirá de nada, y además modificaremos el atributo WebService de la clase para indicar que el namespace será “http://sgoliver.net/” (en vuestro caso podéis indicar otro valor). Con esto, nos quedaría un código base como éste:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace ServicioWebSoap
{
    /// <summary>
    /// Summary description for ServicioClientes
    /// </summary>
    [WebService(Namespace = "http://sgoliver.net/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
 
    public class ServicioClientes : System.Web.Services.WebService
    {
        //Métodos del servicio web
        //...
    }
}
Pues bien, dentro de esta clase ServicioClientes es donde añadiremos todos los métodos públicos que queramos tener accesibles a través de nuestro servicio web, siempre precedidos por el atributo [WebMethod] como veremos en breve. Para nuestro ejemplo vamos a crear tres métodos, el primero para obtener el listado completo de clientes almacenados en la base de datos, y los otros dos para insertar nuevos clientes (más adelante explicaré por qué dos, aunque adelanto que es tan sólo por motivos didácticos).
Antes de crear estos métodos, vamos a crear una nueva clase sencilla que nos sirva para encapsular los datos de un cliente. La añadiremos mediante la opción “Project / Add class…” de Visual Studio y la llamaremos “Cliente.cs“. Esta clase contendrá únicamente los 3 campos que ya comentamos al crear la base de datos y dos constructores, uno de ellos por defecto que tan solo inicializará los campos y otro con parámetros para crear clientes a partir de sus datos identificativos. El código de la clase es muy sencillo, y tan solo cabe mencionar que definiremos sus tres atributos como propiedades automáticas de C# utilizando para ello la notación abreviada {get; set;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace ServicioWebSoap
{
    public class Cliente
    {
        public int Id {get; set;}
        public string Nombre {get; set;}
        public int Telefono {get; set;}
 
        public Cliente()
        {
            this.Id = 0;
            this.Nombre = "";
            this.Telefono = 0;
        }
 
        public Cliente(int id, string nombre, int telefono)
        {
            this.Id = id;
            this.Nombre = nombre;
            this.Telefono = telefono;
        }
    }
}
Vamos ahora a escribir el primero de los métodos que haremos accesible a través de nuestro servicio web. Lo llamaremos NuevoCliente(), recibirá como parámetros de entrada un nombre y un teléfono, y se encargará de insertar un nuevo registro en nuestra tabla de clientes con dichos datos. Recordemos que el ID del cliente no será necesario insertarlo de forma explícita ya que lo hemos definido en la base de datos como campo autoincremental. Para el trabajo con la base de datos vamos a utilizar la API clásica de ADO.NET, aunque podríamos utilizar cualquier otro mécanismo de acceso a datos, como por ejemplo Entity FrameworkNHibernate, etc.
De esta forma, el primer paso será crear una conexión a SQL Server mediante la clase SQLConnection, pasando como parámetro la cadena de conexión correspondiente (en vuestro caso tendréis que modificarla para adaptarla a vuestro entorno). Tras esto abriremos la conexión mediante una llamada al método Open(), definiremos el comando SQL que queremos ejecutar creando un objeto SQLCommand. Ejecutaremos el comando llamando al método ExecuteNonQuery() recogiendo el resultado en una variable, y finalmente cerraremos la conexión llamando a Close(). Por último devolveremos el resultado del comando SQL como valor de retorno del método web.
Como podéis ver en el código siguiente, los valores a insertar en la base de datos los hemos especificado en la consulta SQL como parámetros variable (precedidos por el carácter ‘@’). Los valores de estos parámetros los definimos y añadimos al comando SQL mediante el método Add() de su propiedad Parameters. Esta opción es más recomendable que la opción clásica de concatenar directamente la cadena de texto de la sentencia SQL con los parámetros variables, ya que entre otras cosas servirá para evitar [en gran medida] posibles ataques de inyección SQL. El resultado devuelto por este método será el número de registros afectados por la sentencia SQL ejecutada, por lo que para verificar si se ha ejecutado correctamente bastará con comprobar que el resultado es igual a 1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[WebMethod]
public int NuevoClienteSimple(string nombre, int telefono)
{
    SqlConnection con =
        new SqlConnection(
            @"Data Source=SGOLIVERPC\SQLEXPRESS;Initial Catalog=DBCLIENTES;Integrated Security=True");
 
    con.Open();
 
    string sql = "INSERT INTO Clientes (Nombre, Telefono) VALUES (@nombre, @telefono)";
 
    SqlCommand cmd = new SqlCommand(sql, con);
 
    cmd.Parameters.Add("@nombre", System.Data.SqlDbType.NVarChar).Value = nombre;
    cmd.Parameters.Add("@telefono", System.Data.SqlDbType.Int).Value = telefono;
 
    int res = cmd.ExecuteNonQuery();
 
    con.Close();
 
    return res;
}
En el código anterior, podéis ver que hemos precedido el método con el atributo [WebMethod]. Con este atributo estamos indicando que el método será accesible a través de nuestro servicio web y podrá ser llamado desde cualquier aplicación que se conecte con éste.
La siguiente operación que vamos a añadir a nuestro servicio web será la que nos permita obtener el listado completo de clientes registrados en la base de datos. Llamaremos al método ListadoClientes() y devolverá un array de objetos de tipo Cliente. El código del método será muy similar al ya comentado para la operación de inserción, con la única diferencia de que en esta ocasión la sentencia SQL será obviamente un SELECT y que utilizaremos un objeto SqlDataReader para leer los resultados devueltos por la consulta. Los registros leídos los iremos añadiendo a una lista de tipo List<Clientes> y una vez completada la lectura convertiremos esta lista en un array de clientes llamando al método ToArray(). Este último array será el que devolveremos como resultado del método. Veamos el código completo del método:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[WebMethod]
public Cliente[] ListadoClientes()
{
    SqlConnection con =
        new SqlConnection(
            @"Data Source=SGOLIVERPC\SQLEXPRESS;Initial Catalog=DBCLIENTES;Integrated Security=True");
 
    con.Open();
 
    string sql = "SELECT IdCliente, Nombre, Telefono FROM Clientes";
 
    SqlCommand cmd = new SqlCommand(sql, con);
 
    SqlDataReader reader = cmd.ExecuteReader();
 
    List<Cliente> lista = new List<Cliente>();
 
    while (reader.Read())
    {
        lista.Add(
            new Cliente(reader.GetInt32(0),
                        reader.GetString(1),
                        reader.GetInt32(2)));
    }
 
    con.Close();
 
    return lista.ToArray();
}
Por último, como dijimos al principio, vamos a añadir un tercer método web con fines puramente didácticos. Si os fijáis en los dos métodos anteriores, veréis que en uno de los casos devolvemos como resultado un valor simple, un número entero, y en el otro caso un objeto complejo, en concreto un array de objetos de tipo Cliente. Sin embargo, ninguno de ellos recibe como parámetro un tipo complejo, tan sólo valores simples (enteros y strings). Esto no tiene mucha relevancia en el código de nuestro servicio web, pero sí tiene ciertas peculiaridades a la hora de realizar la llamada al servicio desde la aplicación Android. Por lo que para poder explicar esto más adelante añadiremos un nuevo método de inserción de clientes que, en vez de recibir los parámetros de nombre y teléfono por separado, recibirá como dato de entrada un objeto Cliente.
El código de este método, que llamaremos NuevoClienteObjeto(), será exactamente igual al anterior método de inserción, con la única diferencia de los parámetros de entrada, por lo que no nos detendremos en comentar nada más.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[WebMethod]
public int NuevoClienteObjeto(Cliente cliente)
{
    SqlConnection con = new SqlConnection(@"Data Source=SGOLIVERPC\SQLEXPRESS;Initial Catalog=DBCLIENTES;Integrated Security=True");
 
    con.Open();
 
    string sql = "INSERT INTO Clientes (Nombre, Telefono) VALUES (@nombre, @telefono)";
 
    SqlCommand cmd = new SqlCommand(sql, con);
 
    cmd.Parameters.Add("@nombre", System.Data.SqlDbType.NVarChar).Value = cliente.Nombre;
    cmd.Parameters.Add("@telefono", System.Data.SqlDbType.Int).Value = cliente.Telefono;
 
    int res = cmd.ExecuteNonQuery();
 
    con.Close();
 
    return res;
}
Y con esto hemos finalizado nuestro servicio web. Podemos probar su funcionamiento con la página de prueba que proporciona ASP.NET al ejecutar el proyecto en Visual Studio. Si ejecutamos el proyecto se abrirá automáticamente un explorador web que mostrará una página con todas las operaciones que hemos definido en el servicio web.
operaciones-ws
Si pulsamos sobre cualquiera de ellas pasaremos a una nueva página que nos permitirá dar valores a sus parámetros y ejecutar el método correspondiente para visualizar sus resultados. Si pulsamos por ejemplo en la operación NuevoCliente(string, int) llegaremos a esta página:
operaciones-nuevocliente
Aquí podemos dar valores a los dos parámetros y ejecutar el método (botón “Invoke“), lo que nos devolverá la respuesta codificada en un XML según el estandar SOAP.
operaciones-nuevocliente-res
Como podéis comprobar, en principio el XML devuelto no es fácil de interpretar, pero esto es algo que no debe preocuparnos demasiado ya que en principio será transparente para nosotros, las librerías que utilizaremos más adelante en Android para la llamada a servicios SOAP se encargarán de parsear convenientemente estas respuestas y de darnos tan sólo aquella parte que necesitamos.

No hay comentarios:

Publicar un comentario