sábado, 16 de agosto de 2014

Web Services

Después de una gran ausencia ¡Hemos regresado! y hoy conversaremos de un tema sumamente interesante, básico y esencial para el desarrollo móvil, conocido como los Web Services.

En el área de Windows Phone y cualquier desarrollo móvil ya sea iOS, Android, Firefox OS, etc. Es sumamente importante la gestión de datos, ya sea para obtener las ubicaciones de los lugares que hemos visitado, actualizar nuestro perfil, un simple Login con Facebook, Outlook, Google, etc.

Pero la pregunta es y esas APIs que nos han provisto para hacer esos Logins o que simplemente hemos usado en alguna App, ¿Qué son?, ¿Cómo funcionan?
Simple, son un Web Service, toda esa información es controlada de dicha forma y generalmente nos devuelve un tipo especial de Datos llamado JSON.

Ahora nos preguntamos y además de hacer un Login con una Red Social, tiene más utilidades y la respuesta es SÍ, si tienen debido a que muchas veces necesitamos procesar información y como sabemos ningún dispositivo móvil tiene SQL Server, Oracle, MySQL u otra base de datos instalada y a pesar que algunos dispositivos como Android pueden soportar MySQL, sería un gran error tratar de presionar a un usuario a que tenga que instalar algo tan complejo y SQLite no es la solución a todos nuestros problemas en esos casos se tiene que utilizar un Web Service porque el tiene el poder de acceder a Bases de Datos, procesar información, manipular datos, actualizar, eliminar, etc.

Ahora que hemos hablado un poco del tema, indagaremos en los Web Service, Microsoft nos ofrece muchas opciones como los WCF, ASMX (Web Service) y otros como los más simples conocidos como Handlers y serán de ellos de los cuales conversaremos un poco.

Durante este tema nos enfocaremos en el tipo de datos JSON a pesar que es posible devolver XML, Texto Plano, entre otros, debido su gran facilidad de uso para las Apps, Sitios Web y otros servicios ya que la gestión de XML u otro tipo de datos termina siendo muy engorrasa durante el proceso.

Handlers

Son el tipo de Web Service, más básicos de Microsoft pero tienen una gran flexibilidad de uso debido a que no siguen patrones establecidos y podemos adaptarlos a nuestras necesidades.

Para este ejemplo utilizaremos:
  • Un navegador ya sea Internet Explorer, Google Chrome, Firefox, Maxthon, etc.
  • Microsoft Visual Studio 2013
  • Microsoft SQL Server 2012
  • C# como lenguaje base.
  • La Base de Datos Adventure Works 2012

Creación de un Handler

Paso 1

Creación de Sitio Web

Crearemos un Sitio Web (New Web Site) con Visual Studio y se elijira la opción: ASP.NET Empty Web Site y le pondremos como nombre WSTest. Por el momento trabajaremos con C# sin embargo es indiferente el proceso si se utiliza VB.

Agregar librerías básicas

Para este Web Service utilizaremos la BD de Ejemplo de Microsoft: Adventure Works y agregaremos una Clase para conexión con la BD que será además configurada en el Web.config

Síno poseen la BD de ejemplo, se puede descargar desde aquí:
http://msftdbprodsamples.codeplex.com/

Creación de Clase de Conexión:
Agregaremos a nuestro proyecto una clase llamada: sqlServerConnection, la cual nos servira durante todo el proyecto para gestionar el acceso a la Base de Datos.


Dicha clase tendrá la siguiente información y tiene diversas cualidades como la facilidad de usar Consultas Parametrizadas, creación de consultas de tipo SELECT, INSERT, etc., Manejo de procedimientos almacenados y funciones.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Data.SqlClient;
using System.Configuration;

public class sqlServerConnection
{
    private SqlConnection MSSqlCn;
    private SqlCommand Query;
    public SqlDataReader Data;
    private SqlParameterCollection Parameters;
    private string ConnString;

    public sqlServerConnection()
    {
        ConnString = ConfigurationManager.ConnectionStrings["wsExample"].ConnectionString;

        try
        {
            MSSqlCn = new SqlConnection(ConnString);
            MSSqlCn.Open();
            Query = new SqlCommand();
            Query.Connection = MSSqlCn;
        }
        catch (Exception ex)
        {
            Console.Write("Imposible de conectar con la base de datos seleccionada." + ex.ToString());
        }
    }

    public void Close()
    {
        MSSqlCn.Close();
    }

    public void Add_Param(string Name, ref object Value)
    {
        Query.Parameters.Add(new SqlParameter(Name, Value));
    }

    public int Exec_Query(string SQL_Sentence)
    {
        int result = 0;
        Free();
        Query.CommandText = SQL_Sentence;
        result = Query.ExecuteNonQuery;
        Query.Parameters.Clear();
        return result;
    }

    public void Exec_Proc(string Proc)
    {
        Proc = "Exec dbo." + Proc;
        Exec_Query(Proc);
    }

    public string Exec_Func(string Func)
    {
        Func = "dbo.Select " + Func + ";";
        return Exec_Query(Func).ToString();
    }

    public void Get_DB_Data(string SQL_Sentence)
    {
        Free();
        Query.CommandText = SQL_Sentence;
        Data = Query.ExecuteReader();
        Query.Parameters.Clear();
    }

    public object Get_DB_Val(string SQL_Sentence)
    {
        Free();
        Query.CommandText = SQL_Sentence;
        return Query.ExecuteScalar();
    }

    public int Set_DB_Data(string SQL_Sentence)
    {
        int result = 0;

        Free();
        Query.CommandText = SQL_Sentence;
        result = Query.ExecuteNonQuery();

        Query.Parameters.Clear();
        return result;
    }

    private void Free()
    {
        try
        {
            if (Data.IsClosed == false)
                Data.Close();

        }
        catch (Exception ex)
        {
        }
    }
}

Modificación del Web.config
Primero es imporatante conseguir la conexión de la BD que vamos a acceder a ello utilizaremos el VS para obtener la cadena de conexión.



Ahora que ya hemos hecho la conexión con nuestra BD, obtendremos su cadena de conexión la cual agregaremos a nuestro web.Config, está tecnica es muy útil cuando podremos manejar diversas BDs en una empresa como por ejemplo una BD para los clientes y otra para el sistema contable de nuestra organización.


Mediante dicha cadena de conexión podremos modificar nuestro web.Config y dentro de la sección <configuration> se agregara un elemento llamado <connectionStrings>, el cual será el encargado de la gestión de nuestras conexiones a la BD. Nuestro web.Config final se verá así:

<?xml version="1.0"?>

<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->

<configuration>

  <connectionStrings>
    <add name="wsExample" connectionString="Data Source=FANMIXCO-PC\SQLEXPRESS;Initial Catalog=AdventureWorks2012;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
 
    <system.web>
      <compilation debug="true" targetFramework="4.5.1" />
      <httpRuntime targetFramework="4.5.1" />
    </system.web>

</configuration>

OJO, es importante considerar que en el connectionString, es donde se hará la hará el copy-paste de nuestra cadena de conexión.

Paso 2

Click Derecho sobre el proyecto o carpeta donde se desea crear el Handler y elegir la opción Add y dentro de ella Add New Item…

Paso 3

Elegir la opción C# en los lenguajes instalados y buscar Generic Handler en la parte baja esta un cuadro de texto para agregar el nombre del Web Service (Name) a crear por ejemplo Example.ashx y al final se le da click a Add.

Paso 4

Creado el Web Service, se puede comenzar a programar dentro de el, sin embargo es necesario agregar una serie de librerías para devolver los valores JSON.

Paso 5

Agregar la siguiente librería:
using System.Web.Script.Serialization; //Librería para devolución de Datos en Formato JSON

Inicializar el evento ProcessRequest con los datos de uso de la URL desde cualquier lugar y retornar data tipo JSON
public void ProcessRequest (HttpContext context) {
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); //Permitir el acceso del Web Service desde lugares externos al proyecto de no ser agregada el web service dará error, si es tratado de ser ejecutado fuera de su servidor o en un formato http://
    context.Response.ContentType = "application/json"; //Devolver información tipo JSON
}

Paso 6

Se debe crear una clase con la siguiente estructura para el retorno de la información dicha información debe ir arriba de ProcessRequest.
public class dataUser
{
    private string _FirstName; //variable que guarda el primer nombre del Usuario
    private string _LastName; //variable que guarda el primer nombre del Usuario

    public string FirstName //función que guarda o muestra el primer nombre del Usuario
    {
        get { return _FirstName; }
        set { _FirstName = value; }
    }

    public string LastName
    {
        get { return _LastName; }
        set { _LastName = value; }
    }
}

Paso 7

Ahora, obtendremos información de la Base de Datos y se explicara en el siguiente código comentado todo eso se debe hacer dentro de una función que debe devolver un string obligatoriamente, independiente si en un futuro se piensa devolver XML.


public string returnJSON()
    {
        //Clase para Acceso a la BD
        sqlServerConnection cnn = new sqlServerConnection();

        //objeto para la gestión de la información a presentar
        List<dataUser> data = new List<dataUser>();

        //se inicializa la consulta con el dato a buscar y devolveremos los primeros 15 resultados
        string SQL = "SELECT TOP 15 * FROM Person.Person WHERE title=@title";

        //inicializamos el parametro de suffix
        cnn.Add_Param("title", dataPublic.Request.QueryString["title"].ToString());

        //obtenemos el resultado de la BD
        cnn.Get_DB_Data(SQL);

        //leemos el resultado de la BD si existe data
        while (cnn.Data.Read())
        {
            //agregamos a lista data por dato del resultado del arreglo
            data.Add(new dataUser() { FirstName = cnn.Data["FirstName"].ToString(), LastName = cnn.Data["LastName"].ToString() });
        }

        //devolvemos el resultado en formato JSON
        return new JavaScriptSerializer().Serialize(data);
    }

Paso 8

Se manda a llamar el resultado en formato JSON para poderlo imprimir en el navegador o ser leído por AJAX u otra tecnología capaz de interpretar dicho formato como .NET, Java, PHP, etc.

public void ProcessRequest (HttpContext context) {
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); //Permitir el acceso del Web Service desde lugares externos al proyecto
    context.Response.ContentType = "application/json"; //Devolver información tipo JSON

    /*Ejemplos extras:
        * Si se enviaran parametros por GET se leen así:
        * context.Request.QueryString["Nombre"]
        * Si se enviaran parametros por POST se leen así:
        * context.Request.Form["Nombre"]
    */
       
    //Impresión del resultado en formato JSON
    context.Response.Write(returnJSON());
}

Ejemplo completo

<%@ WebHandler Language="C#" Class="Example" %>

using System;
using System.Web;
using System.Web.Script.Serialization; //Librería para devolución de Datos en Formato JSON
using System.Collections.Generic;

public class Example : IHttpHandler
{
    HttpContext dataPublic;
   
    public class dataUser
    {
        private string _FirstName; //variable que guarda el primer nombre del Usuario
        private string _LastName; //variable que guarda el primer nombre del Usuario

        public string FirstName //función que guarda o muestra el primer nombre del Usuario
        {
            get { return _FirstName; }
            set { _FirstName = value; }
        }

        public string LastName
        {
            get { return _LastName; }
            set { _LastName = value; }
        }
    }
   
    public void ProcessRequest(HttpContext context)
    {
        //El objeto dataPublic nos permitira acceder a los valores POST y GET enviados a nuestro servicio lo que nos simplifica no enviar información adicional a nuestra función de retorno       
        //context es el objeto que trae por defecto dicha información
        dataPublic = context;
       
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); //Permitir el acceso del Web Service desde lugares externos al proyecto de no ser agregada el web service dará error, si es tratado de ser ejecutado fuera de su servidor o en un formato http://
        context.Response.ContentType = "application/json"; //Devolver información tipo JSON      
        context.Response.Write(returnJSON());
    }

    public string returnJSON()
    {
        //Clase para Acceso a la BD
        sqlServerConnection cnn = new sqlServerConnection();

        //objeto para la gestión de la información a presentar
        List<dataUser> data = new List<dataUser>();

        //se inicializa la consulta con el dato a buscar y devolveremos los primeros 15 resultados
        string SQL = "SELECT TOP 15 * FROM Person.Person WHERE title=@title";

        //inicializamos el parametro de suffix
        cnn.Add_Param("title", dataPublic.Request.QueryString["title"].ToString());

        //obtenemos el resultado de la BD
        cnn.Get_DB_Data(SQL);

        //leemos el resultado de la BD si existe data
        while (cnn.Data.Read())
        {
            //agregamos a lista data por dato del resultado del arreglo
            data.Add(new dataUser() { FirstName = cnn.Data["FirstName"].ToString(), LastName = cnn.Data["LastName"].ToString() });
        }

        //devolvemos el resultado en formato JSON
        return new JavaScriptSerializer().Serialize(data);
    }
   
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}
Ahora que ya tenemos el código solo es de ejecutar el proyecto y con una dirección similar a esta podremos obtener el resultado:

El Resultado en un navegador se verá así:
[{"FirstName":"Jossef","LastName":"Goldberg"},{"FirstName":"Hung-Fu","LastName":"Ting"},{"FirstName":"Brian","LastName":"Welcker"},{"FirstName":"Tete","LastName":"Mensa-Annan"},{"FirstName":"Syed","LastName":"Abbas"},{"FirstName":"Gustavo","LastName":"Achong"},{"FirstName":"Jay","LastName":"Adams"},{"FirstName":"Ronald","LastName":"Adina"},{"FirstName":"Samuel","LastName":"Agcaoili"},{"FirstName":"James","LastName":"Aguilar"},{"FirstName":"Robert","LastName":"Ahlering"},{"FirstName":"François","LastName":"Ferrier"},{"FirstName":"Milton","LastName":"Albury"},{"FirstName":"Paul","LastName":"Alcorn"},{"FirstName":"Gregory","LastName":"Alderson"}]
Con esa URL ya podremos trabajarlo desde nuestros proyectos, en una próxima liberación hablaremos de como utilizarlo desde nuestros dispositivos móviles. ¡Nos vemos pronto!

No hay comentarios:

Publicar un comentario