domingo, 22 de febrero de 2015

Conclusiones SOAP vs REST

SOAP
  • Está orientado a operaciones.
  • La descripción de un servicio debe ser hecha en WSDL.
    • WSDL: Es un lenguaje basado en XML que permite describir la interfaz, formas de acceso, ubicación y otras características de un Web Service.
  • El servidor puede mantener el estado de la conversación (Stateless o stateful)
  • Uso de XML, con lo que se consigue mejor acoplamiento.
  • Busca interoperabilidad.
  • Ve la web como medio para intercambio de mensajes.
  • Operaciones ilimitadas.

REST
  • Orientado a recursos.
  • El servidor no tiene estado (stateless).
  • Sintáxis XML, siendo JSON el más popular.
  • Busca escalabilidad y performance.
  • Ve la Web como un gran repositorio.
  • Conjunto limitado de operaciones
  • No hay estándares de seguridad, transaccionalidad, etc.

Conclusiones 
Actualmente existen dos ramas importantes en relación a los Servicios Web. Cada una dispone de una arquitectura propia, y por consiguiente su funcionamiento y características que ofrecen son distintas. 

Los Servicios Web basados en SOAP, se podrían catalogar como clásicos, siendo los componentes principales empleados:
  • XML (para codificar la información)
  • SOAP (para formar los mensajes)
  • WSDL (para definir los servicios ofrecidos, a modo de contrato entre el servidor y el cliente)
  • UDDI (que es un registro donde se publican los servicios).
Por el contrario, los Servicios Web REST, directamente trabajan sobre los protocolos de red (como HTTP) y hacen uso de XML, para enviar datos compuestos.

Ninguno es mejor que el otro. SOAP es mejor para integrar Sistemas heterogéneos, código legado, etc. y REST para aplicaciones Web dirigidas a clientes desconocidos.

Web Services REST (Representational State Transfer)

Es un estilo de arquitectura, no es una especificación ni un estándar. Aunque REST no es un estándar, está basado en estándares:
  • HTTP
  • URL
  • Representación de los recursos: XML/HTML/GIF/JPEG/...
  • Tipos MIME: text/xml, text/html, ...
Principios o Restricciones:
  • Recursos deben ser uniformemente accesibles (URI única).
  • Recursos son accedidos y actualizados por mediante operaciones GET, POST, PUT, DELETE
  • Metadatos para describir recursos
  • Comunicación entre cliente y servidor debe ser Stateless.
  • La descripción de un servicio debe ser hecha en WSDL.
    • Stateless (Sin estado): Cada petición de un cliente debe contener toda la información necesaria. No puede beneficiarse de contexto almacenado en servidor.

Web Services con REST y WCF
Primero, en la base de datos agregaremos la tabla “tb_empleado”, con la siguiente estructura: 

Segundo, crearemos un nuevo Proyecto en Visual Studio 2010 de tipo WCF de nombre RESTServices. 

Crearemos una carpeta "Dominio" y agregaremos la clase "Empleado.cs" con el siguiente código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace RESTServices.Dominio
{
    [DataContract]
    public class Empleado
    {
        [DataMember]
        public int Codigo { get; set; }
        [DataMember]
        public int DNI { get; set; }
        [DataMember]
        public string Nombre { get; set; }
        [DataMember]
        public string Apellido { get; set; }
        [DataMember]
        public string FechaNacimiento { get; set; }
        [DataMember]
        public string Telefono { get; set; }
        [DataMember]
        public int Estado { get; set; }
        [DataMember]
        public string Usuario { get; set; }
        [DataMember]
        public string Clave { get; set; }
    }
}
Crearemos otra carpeta "Persistencia" y agregaremos las clases "Conexion.cs", "EmpleadoDAO" con los siguientes códigos respectivamente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace RESTServices.Persistencia
{
    public class ConexionUtil
    {
        public static string Cadena
        {
            get
            {
                return "Data Source=(local);Initial Catalog=bd_peaje;Integrated Security=SSPI;";
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using RESTServices.Dominio;
using System.Data.SqlClient;
using System.ServiceModel.Web;
using System.Net;

namespace RESTServices.Persistencia
{
    public class EmpleadoDAO
    {
        public Empleado Crear(Empleado empleadoACrear)
        {
            Empleado empleadoNuevo = null;
            empleadoACrear.Codigo = ObtenerIdCorrelativo();
                string sql = "INSERT INTO tb_empleado VALUES (@cod,@dni, @nom,@ape, @fecnac, @fono,@estado,@usu,@clave)";
                using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
                {
                    con.Open();
                    using (SqlCommand com = new SqlCommand(sql, con))
                    {
                        com.Parameters.Add(new SqlParameter("@cod", empleadoACrear.Codigo));
                        com.Parameters.Add(new SqlParameter("@dni", empleadoACrear.DNI));
                        com.Parameters.Add(new SqlParameter("@nom", empleadoACrear.Nombre));
                        com.Parameters.Add(new SqlParameter("@ape", empleadoACrear.Apellido));
                        com.Parameters.Add(new SqlParameter("@fecnac", empleadoACrear.FechaNacimiento));
                        com.Parameters.Add(new SqlParameter("@fono", empleadoACrear.Telefono));
                        com.Parameters.Add(new SqlParameter("@estado", empleadoACrear.Estado));
                        com.Parameters.Add(new SqlParameter("@usu", empleadoACrear.Usuario));
                        com.Parameters.Add(new SqlParameter("@clave", empleadoACrear.Clave));
                        com.ExecuteNonQuery();
                    }
                }
                empleadoNuevo = Obtener(empleadoACrear.Codigo);
                return empleadoNuevo;
        }

        public Empleado Obtener(int codigo)
        {
            Empleado empleadoExistente = null;
            string sql = "SELECT * FROM tb_empleado WHERE codEmpleado=@cod";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    com.Parameters.Add(new SqlParameter("@cod", codigo));

                    using (SqlDataReader resultado = com.ExecuteReader())
                    {
                        if (resultado.Read())
                        {
                            empleadoExistente = new Empleado()
                            {
                                Codigo = (int)resultado["codEmpleado"],
                                DNI=(int)resultado["dni"],
                                Nombre = (string)resultado["nombres"],
                                Apellido = (string)resultado["apellidos"],
                                FechaNacimiento = (string)resultado["fechaNacimiento"],
                                Telefono = (string)resultado["telefono"],
                                Estado=(int)resultado["estado"],
                                Usuario = (string)resultado["usuario"],
                                Clave = (string)resultado["clave"]
                            };
                        }
                    }
                }
            }
            return empleadoExistente;
        }

        public Empleado ObtenerDNI(int dni)
        {
            Empleado empleadoExistente = null;
            string sql = "SELECT dni FROM tb_empleado WHERE dni=@dni";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    com.Parameters.Add(new SqlParameter("@dni", dni));
                    using (SqlDataReader resultado = com.ExecuteReader())
                    {
                        if (resultado.Read())
                        {
                            empleadoExistente = new Empleado()
                            {
                                DNI = (int)resultado["dni"],
                            };
                        }
                    }
                }
            }
            return empleadoExistente;
        }

        public Empleado ObtenerUsuario(string usuario)
        {
            Empleado empleadoExistente = null;
            string sql = "SELECT codEmpleado,usuario FROM tb_empleado WHERE usuario=@usuario";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    com.Parameters.Add(new SqlParameter("@usuario", usuario));
                    using (SqlDataReader resultado = com.ExecuteReader())
                    {
                        if (resultado.Read())
                        {
                            empleadoExistente = new Empleado()
                            {
                                Codigo = (int)resultado["codEmpleado"],
                                Usuario = (string)resultado["usuario"]
                            };
                        }
                    }
                }
            }
            return empleadoExistente;
        }

        public Empleado Modificar(Empleado empleadoAModificar)
        {
            Empleado empleadoModificado = null;
            string sql = "UPDATE tb_empleado SET dni=@dni,nombres=@nom,apellidos=@ape,fechaNacimiento=@fecnac,telefono=@tel,estado=@est,usuario=@usu,clave@cla WHERE codEmpleado=@cod";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    com.Parameters.Add(new SqlParameter("@cod", empleadoAModificar.Codigo));
                    com.Parameters.Add(new SqlParameter("@dni", empleadoAModificar.DNI));
                    com.Parameters.Add(new SqlParameter("@nom", empleadoAModificar.Nombre));
                    com.Parameters.Add(new SqlParameter("@ape", empleadoAModificar.Apellido));
                    com.Parameters.Add(new SqlParameter("@fecnac", empleadoAModificar.FechaNacimiento));
                    com.Parameters.Add(new SqlParameter("@tel", empleadoAModificar.Telefono));
                    com.Parameters.Add(new SqlParameter("@est", empleadoAModificar.Estado));
                    com.Parameters.Add(new SqlParameter("@usu", empleadoAModificar.Usuario));
                    com.Parameters.Add(new SqlParameter("@clave", empleadoAModificar.Clave));
                    com.ExecuteNonQuery();
                }
            }
            empleadoModificado = Obtener(empleadoAModificar.Codigo);
            return empleadoModificado;
        }
        public void Eliminar(Empleado empleadoAEliminar)
        {
            string sql = "DELETE FROM tb_empleado WHERE codEmpleado=@cod";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    com.Parameters.Add(new SqlParameter("@cod", empleadoAEliminar.Codigo));
                    com.ExecuteNonQuery();
                }
            }
        }
        public List ListarTodos()
        {
            List empleadoExistentes = new List();
            Empleado empleadoExiste = null;
            string sql = "SELECT * FROM tb_empleado";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    using (SqlDataReader resultado = com.ExecuteReader())
                    {
                        while (resultado.Read())
                        {
                            empleadoExiste = new Empleado()
                            {
                                Codigo = (int)resultado["codEmpleado"],
                                DNI = (int)resultado["dni"],
                                Nombre = (string)resultado["nombres"],
                                Apellido = (string)resultado["apellidos"],
                                FechaNacimiento = (string)resultado["fechaNacimiento"],
                                Telefono = (string)resultado["telefono"],
                                Estado = (int)resultado["estado"],
                                Usuario = (string)resultado["usuario"],
                                Clave = (string)resultado["clave"]
                            };
                            empleadoExistentes.Add(empleadoExiste);
                        }
                    }
                }
            }
            return empleadoExistentes;
        }
        
        public int ObtenerIdCorrelativo()
        {
            int idMax = 0;
            string sql = "SELECT isNull(max(codEmpleado),0)+1 as Id FROM tb_empleado ";
            using (SqlConnection con = new SqlConnection(ConexionUtil.Cadena))
            {
                con.Open();
                using (SqlCommand com = new SqlCommand(sql, con))
                {
                    using (SqlDataReader resultado = com.ExecuteReader())
                    {
                        if (resultado.Read())
                        {
                            idMax = (int)resultado["Id"];
                        }
                    }
                }
            }
            return (idMax);
        }
    }
}

Crearemos un servicio web "Empleados.svc"

Editaremos el archivo "IEmpleados.cs" y agregamos los siguientes métodos:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using RESTServices.Dominio;

namespace RESTServices
{    
    [ServiceContract]
    public interface IEmpleados
    {
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "Empleados", ResponseFormat = WebMessageFormat.Json)]
        Empleado CrearEmpleado(Empleado empleadoACrear);

        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "Empleados/{codigo}", ResponseFormat = WebMessageFormat.Json)]
        Empleado ObtenerEmpleado(string codigo);

        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "Empleados?dni={dni}", ResponseFormat = WebMessageFormat.Json)]
        Empleado ObtenerEmpleadoDNI(string dni);

        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "Usuarios?usuario={usuario}", ResponseFormat = WebMessageFormat.Json)]
        Empleado ObtenerEmpleadoUsuario(string usuario);

        [OperationContract]
        [WebInvoke(Method = "PUT", UriTemplate = "Empleados", ResponseFormat = WebMessageFormat.Json)]
        Empleado ModificarEmpleado(Empleado empleadoAModificar);

        [OperationContract]
        [WebInvoke(Method = "DELETE", UriTemplate = "Empleados", ResponseFormat = WebMessageFormat.Json)]
        void EliminarEmpleado(string codigo);

        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "Empleados", ResponseFormat = WebMessageFormat.Json)]
        List ListarEmpleados();
    }
}

Editaremos el archivo "IEmpleados.svc.cs" e implementaremos los métodos creados:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using RESTServices.Persistencia;
using System.Data.SqlClient;
using RESTServices.Dominio;
using System.ServiceModel.Web;
using System.Net;

namespace RESTServices
{    
    public class Empleados : IEmpleados
    {
        EmpleadoDAO dao = new EmpleadoDAO();
        
        public Dominio.Empleado CrearEmpleado(Dominio.Empleado empleadoACrear)
        {
            string dni =Convert.ToString(empleadoACrear.DNI);
            Empleado existe =ObtenerEmpleadoDNI(dni);
            if (existe != null)
                throw new WebFaultException(
                    new MensajeError()
                    {
                        Codigo = "E01",
                        Mensaje = "El empleado ya se encuentra registrado"
                    },
                    HttpStatusCode.InternalServerError);
            return dao.Crear(empleadoACrear);
        }

        public Dominio.Empleado ObtenerEmpleado(string codigo)
        {
            int x = int.Parse(codigo);
            return dao.Obtener(x);
        }

        public Dominio.Empleado ObtenerEmpleadoDNI(string dni)
        {
            int x = int.Parse(dni);
            return dao.ObtenerDNI(x);
        }

        public Empleado ObtenerEmpleadoUsuario(string usuario)
        {
            return dao.ObtenerUsuario(usuario);
        }

        public Dominio.Empleado ModificarEmpleado(Empleado empleadoAModificar)
        {
            return dao.Modificar(empleadoAModificar);
        }

        public void EliminarEmpleado(string codigo)
        {
            int x = int.Parse(codigo);
            dao.Eliminar(dao.Obtener(x));
        }

        public List ListarEmpleados()
        {
            return dao.ListarTodos().ToList();
        }
    }
}

Añadimos WebServiceHostFactory que es una clase introducida en WCF para hacer servicios WCF Restful. 

Para testear instalamos un complemento del Firefox "REST Client"
 
Por último, probamos nuestros servicios REST.

Web Services SOAP (Simple Object Access Protocol)

  • Este tipo de servicios, implica el intercambio de mensajes XML, codificados según el protocolo SOAP.
  • Estos mensajes en formato SOAP son movidos de un sistema a otro, utilizando HTTP.
  • El sistema recibe el mensaje, hace lo que tiene que hacer, y devuelve una respuesta también en formato SOAP.
  • Es un sistema simple, que no tiene en cuenta aspectos importantes del desarrollo de soluciones empresariales, pero que son tenidas en cuenta a través de extensiones a los estándares.
Web Services SOAP desde .NET
Primero crearemos un nuevo Proyecto en Visual Studio 2010 como aparece en la figura.
Seleccionaremos como tipo de proyecto WCF, y el Template que utilizaremos será Aplicación de ServiciosWCF, para efectos del ejemplo manejaremos como nombre de la solución SOAPServices.
 Agregaremos un nuevo elemento y nos saldrá un cuadro en el cual seleccionaremos Servicio WCF como podemos ver en la pantalla siguiente, la cual nos permitirá adentrarnos en SOAP. 
 Crearemos tres funciones básicas dentro de este servicio Ejemplos las cuales serán las siguientes:
Hello : Recibirá un string y retornará un string.
Suma : Recibirá dos enteros y regresará un entero.
Ejecutar: Recibirá un Boleano y regresará un objeto compuesto por un string y un boleano.
Para diseñar estas funciones utilizaremos este codigo:
 Para ejecutar, seleccionamos el servicio Ejemplos y presionando F5, se abrirá una ventana de Cliente de Pruea WCF en el cual veremos los métodos creados y ejecutarlos.

sábado, 21 de febrero de 2015

WCF (La respuesta de Microsoft a SOA)

Introducción a WCF
WCF es la implementación de Microsoft de un set de estándares de la industria, que definen entre otras cosas, interacción entre servicios, conversión de tipos, marshalling, unmarshalling, protocolos, etc.

La idea fundamental de WCF es la de permitir a las empresas desarrollar aplicaciones distribuidas basadas en la arquitectura orientada a servicios (SOA), donde éstas se puedan ejecutar, desde una máquina local hasta Internet, de manera simple y segura.

Componentes básicos de WCF 
  • En primer lugar, el desarrollo con WCF se basa en servicios. 
  • Un servicio es un programa que expone una colección de Endpoints (puntos de acceso). 
  • Cada Endpoint, es una puerta hacia el mundo exterior mediante una determinada tecnología de transporte. 
  • Un Cliente es un programa que intercambia mensajes con uno o más Endpoints. Y un Cliente puede exponer también un Endpoints para recibir mensajes de un Servicio. 
  • Un Endpoint de un Servicio está compuesto por una Address (Dirección), un Binding (Enlace) y un Contract (Contrato)
  • La dirección de un Endpoint es una dirección de red donde reside dicho Endpoint. 
  • El Binding específica cómo se comunica dicho Endpoint con el resto del mundo, incluyendo aspectos como el protocolo de transporte (TCP, http, etc.), tipo de codificación (texto, binario), y requerimientos de seguridad (SSL, seguridad basada en mensajes SOAP, etc.).
  • Por último el contrato especifica qué comunica dicho Endpoint y básicamente está compuesto por una colección de mensajes organizados internamente en operaciones que tienen un patrón de intercambio de mensajes (Message Exchange Patterns ó MEPs), como one-way (un sentido), dúplex y request/reply (petición/respuesta).

Arquitectura Orientada a Servicios (SOA): La era de la integración

Introducción a una Arquitectura Orientada a Servicios (SOA)
  SOA es un estilo arquitectónico de software, no una tecnología determinada. Como estilo arquitectónico, define a los servicios como unidades de partición para dar respuesta a los requerimientos del negocio dentro de una organización. 

  SOA proporciona una metodología y un marco de trabajo para mapear procesos de negocio a componentes de software en forma de servicios. Las aplicaciones ya no son más elementos aislados sino parte integrante del negocio. 
Tecnológicamente, estos servicios tienen la particularidad de ser:
  • Encapsulados
  • De bajo acoplamiento
  • Reutilizables
  • Sin información de estado (stateless)
  • Localizables
  • Independientes de una plataforma o lenguaje
  • Basados en estándares y tecnologías ya utilizadas (SOAP, UDDI, WSDL, http, entre otros).
Todo esto es posible gracias a un bus (ESB) donde se montan dichos componentes. Dicho bus brinda soporte a los servicios mediante manejo de transacciones, seguridad, orquestación, etc.

   Un Enterprise Service Bus (ESB) es una plataforma de integración basada en estándares que combina mensajería, web services, transformación de datos y ruteo inteligente para conectar y coordinar de forma confiable la interacción de un gran número de aplicaciones diversas a través de empresas extendidas (empresas + socios de negocios) con integridad transaccional. 


Beneficios de una Arquitectura Orientada a Servicios (SOA)
   Existen cinco factores importantes que aumentan el interés del equipo ejecutivo y sobre todo, de los responsables de desarrollo, por la arquitectura SOA:
  1. La arquitectura SOA ayuda a mejorar la agilidad y flexibilidad de las organizaciones.
  2. La arquitectura SOA permite una “personalización masiva” de las tecnologías de la información.
  3. La arquitectura SOA permite la simplificación del desarrollo de soluciones mediante la utilización de estándares de la industria y capacidades comunes de industrialización.
  4. La arquitectura SOA permite aislar los sistemas frente a cambios generados por otras partes de la organización (protección  e las inversiones realizadas)
  5. La arquitectura SOA permite alinear y acercar las áreas de tecnología y negocio.