sábado, 6 de diciembre de 2014

Principios REST

Principios REST 
Este estilo de arquitectura en Internet, se apoya es la siguiente serie de simples principios que te permitirán explotar la arquitectura de la Web al máximo: 
  • Dale un ID a cada recurso: Esto es más simple de lo que parece, porque en Internet, cada recurso que pongamos disponible tendrá un URI asociado. Los URIs forman un espacio de nombres global que te permitirán identificar los recursos con un ID global. Ahora bien, el diseño de estas URIs tampoco es trivial, ya que sin un espacio de nombres consistente estaremos entorpeciendo la comunicación entre máquinas e, incluso, el futuro desarrollo de la aplicación. 
  • Enlaza las cosas juntas: Siempre que se pueda, conviene, al devolver información sobre algo, adjuntar enlaces a los recursos que puedan adjuntar más información. Además, este enfoque permite enlazar recursos proporcionados por diversas máquinas de una forma transparente y simple. 
  • Utiliza métodos estándares: Todos los recursos tienen una interfaz común marcada por el protocolo HTTP. Estos métodos son GET, POST, PUT, DELETE, HEAD y OPTIONS y nos permiten una forma estándar de acceder y manejar los diferentes recursos que necesitemos.
  • Recursos con múltiples representaciones: ¿Cómo puede un cliente manejar los datos que le devuelve una petición GET o POST? Para esto, HTTP proporciona separación entre el manejo de los datos y la invocación a las operaciones. Si un cliente solo es capaz de manejar un determinado formato de datos, deberá especificarlo en la petición (añadiendo este tipo de formato en el accept, p.e: Accept: text/x-vcard) . De esta manera, la aplicación podrá responderle en un formato que sea capaz de manejar.  
  • Comunícate sin estados: Este último principio se refiere a que se debe tratar de evitar que la comunicación con el servidor cambie el estado del mismo. REST prefiere que los cambios de estado se manejen como estados de recursos o bien se manejen en el cliente. De esta manera, como el servidor no tiene que gestionar y almacenar el estado con respecto a cada cliente, la escalabilidad se simplifica. Por otra parte, abstrae al cliente de lo que pase en el servidor o del servidor concreto con el que esté trabajando, pudiendo cambiarse sin que el cliente tenga que notar nada. 
Ejemplo de diseño basado en REST 
La Web evidentemente es un ejemplo clave de diseño basado en REST, ya que muchos principios son la base de REST. Aquí un ejemplo aplicado a Servicios Web.  
La Web consiste del protocolo HTTP, de tipos de contenido, incluyendo HTML y otras tecnologías tales como el Domain Name System (DNS).
Por otra parte, HTML puede incluir javascript y applets, los cuales dan soporte al code-on-demand, y además tiene implícitamente soporte a los vínculos. HTTP posee un interfaz uniforme para acceso a los recursos, el cual consiste de URIs, métodos, códigos de estado, cabeceras y un contenido guiado por tipos MIME.
Los métodos HTTP más importantes son PUT, GET, POST y DELETE. Ellos suelen ser comparados con las operaciones asociadas a la tecnología de base de datos, operaciones CRUD: CREATE, READ, UPDATE, DELETE. Otras analogías pueden también ser hechas como con el concepto de copiar-y-pegar (Copy&Paste). Todas las analogías se representan en la siguiente tabla: 
Create
PUT
Insert
Pegar
>
Read
GET
Select
Copiar
<
Update
POST
Update
Pegar después
>>
Delete
DELETE
Delete
Cortar
Del/rm
El protocolo HTTP separa las nociones de un servidor y un navegador. Esto permite a la implementación cada uno variar uno del otro, basándose en el concepto cliente/servidor. Cuando utilizamos REST, HTTP no tiene estado. Cada mensaje contiene toda la información necesaria para comprender la petición cuando se combina el estado en el recurso. Como resultado, ni el cliente ni el servidor necesita mantener ningún estado en la comunicación. Cualquier estado mantenido por el servidor debe ser modelado como un recurso.  
La restricción de no mantener el estado puede ser violada mediante cookies que mantienen las sesiones. Fielding advierte del riesgo a la privacidad y seguridad que frecuentemente surge del uso de cookies, así como la confusión y errores que pueden resultar de las interacciones entre cookies y el uso del boton “Go back” del navegador.
HTTP proporciona mecanismos para el control del caching y permite que ocurra una conversación entre el navegador y la caché del mismo modo que se hace entre navegador y el servidor Web. 

viernes, 5 de diciembre de 2014

Creación de Servicio Web SOAP

Explicaremos cómo crear un servicio SOAP en .NET utilizando Hibernate para conectar a una base de datos SQL Server.


Primeramente se va crear un nuevo proyecto, luego buscar la opción Visual C#, seleccionar WCF y  escoger la opción “Aplicación de servicios WCF” y colocar un nombre.

Cambiar de nombre al servicio “Service1.svc” que se crea por defecto. Para este ejemplo colocaremos el nombre “Clientes.svc”. De igual manera cambiaremos“IService1.cs” por “IClientes.cs”.

Agregar al proyecto las carpetas “Dominio” y “Persistencia”. Adicionar a la solución la carpeta “Librerias” la cual contendrá los archivos “Iesi.Collections.dll” y“NHibernate.dll”. Usar el explorador de Windows para ir a la carpeta donde se encuentra nuestro proyecto y crear una carpeta llamada "Librerias" que contenga los archivos que incluiremos en la librería, luego arrastrarlos hacia la carpeta “Librerias” que se encuentra en nuestra solución.

El siguiente paso dentro de nuestro proyecto es dar clic derecho sobre la opción “References” y escoger la opción “Agregar Referencia”. Escoger la pestaña “Examinar” y seleccionar los archivos que colocamos en la carpeta “Librerias”.



Ahora crearemos la clase “Conexión.cs” dentro de la carpeta “Persistencia”. Con el siguiente código:

  public class ConexionUtil
    {
        public static string ObtenerCadena()
        {
            return "Data Source=(local);Initial Catalog=BD_ALQUILER_VEHICULOS;Integrated Security=SSPI;";
        }
    }

Asimismo,  la clase “NHibernateHelper.cs” con el siguiente código

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;
using NHibernate.Cfg;

namespace TransaccionesServices.Persistencia
{
    public class NHibernateHelper
    {
        private static ISessionFactory _Fabrica;

        private static ISessionFactory Fabrica
        {
            get
            {
                if (_Fabrica == null)
                {
                    var _Conf = new Configuration();
                    _Conf.SetProperty("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
                    _Conf.SetProperty("connection.driver_class", "NHibernate.Driver.SqlClientDriver");
                    _Conf.SetProperty("connection.connection_string", ConexionUtil.ObtenerCadena());
                    _Conf.SetProperty("adonet.batch_size", "10");
                    _Conf.SetProperty("show_sql", "true");
                    _Conf.SetProperty("dialect", "NHibernate.Dialect.MsSql2000Dialect");
                    _Conf.SetProperty("command_timeout", "60");
                    _Conf.SetProperty("query.substitutions", "true 1, false 0, yes 'Y', no 'N'");
                    _Conf.AddAssembly(typeof(NHibernateHelper).Assembly);
                    _Fabrica = _Conf.BuildSessionFactory();
                }
                return _Fabrica;
            }
        }
        public static ISession ObtenerSesion()
        {
            return Fabrica.OpenSession();
        }
        public static void CerrarFabrica()
        {
            _Fabrica = null;
        }
    }
}

Luego crear la clase “BaseDAO” con el siguiente código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;

namespace TransaccionesServices.Persistencia
{
    public class BaseDAO<Entidad, Id>
    {
        public Entidad Crear(Entidad entidad)
        {
            using (ISession sesion = NHibernateHelper.ObtenerSesion())
            {
                sesion.Save(entidad);
                sesion.Flush();
            }
            return entidad;
        }
        public Entidad Obtener(Id id)
        {
            using (ISession sesion = NHibernateHelper.ObtenerSesion())
            {
                return sesion.Get<Entidad>(id);
            }
        }
        public Entidad Modificar(Entidad entidad)
        {
            using (ISession sesion = NHibernateHelper.ObtenerSesion())
            {
                sesion.Update(entidad);
                sesion.Flush();
            }
            return entidad;
        }
        public void Eliminar(Entidad entidad)
        {
            using (ISession sesion = NHibernateHelper.ObtenerSesion())
            {
                sesion.Delete(entidad);
                sesion.Flush();
            }
        }
        public ICollection<Entidad> ListarTodos()
        {
            using (ISession sesion = NHibernateHelper.ObtenerSesion())
            {
                ICriteria busqueda = sesion.CreateCriteria(typeof(Entidad));
                return busqueda.List<Entidad>();
            }
        }
    }
}

Luego se procede a crear la clase Cliente con el siguiente código:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using GestionServices.Dominio;
using GestionServices.Persistencia;

namespace GestionServices
{
    public class Clientes : IClientes
    {
        private ClienteDAO clienteDAO = null;
        private ClienteDAO ClienteDAO
        {
            get
            {
                if (clienteDAO == null)
                    clienteDAO = new ClienteDAO();
                return clienteDAO;
            }
        }

        UsuariosWS.UsuariosClient proxyUsuarios = new UsuariosWS.UsuariosClient();

        public Mensaje CrearCliente(string nombre, string dni, DateTime fecha_nacimiento, string direccion, string distrito, string email, string clave, string brevete)
        {

            Mensaje mensajeRetorno = new Mensaje();

            UsuariosWS.Mensaje mensajeUsuario = proxyUsuarios.CrearUsuario(nombre, clave, "Cliente");

            if (mensajeUsuario.codigoMensaje == "E")
            {
                mensajeRetorno.codigoMensaje = mensajeUsuario.codigoMensaje;
                mensajeRetorno.codigoElemento = mensajeUsuario.codigoElemento;
                mensajeRetorno.textMensaje = mensajeUsuario.textMensaje;

                return mensajeRetorno;
            }

           UsuariosWS.Usuario usuarioCreado = proxyUsuarios.ObtenerUsuario(mensajeUsuario.codigoElemento);

            Perfil perfilUsuario = new Perfil()
            {
                Codigo = usuarioCreado.Perfil.Codigo,
                Descripcion = usuarioCreado.Perfil.Descripcion
            };

            Usuario usuarioNuevo = new Usuario()
            {
                Codigo = usuarioCreado.Codigo,
                Clave = usuarioCreado.Clave,
                Nombre = usuarioCreado.Nombre,
                Estado = usuarioCreado.Estado,
                Perfil = perfilUsuario
            };

            Cliente clienteACrear = new Cliente()
            {
                Nombre = nombre,
                NroDNI = dni,
                FechaNacimiento = fecha_nacimiento,
                Direccion = direccion,
                Distrito = distrito,
                Email = email,
                Brevete = brevete,
                Usuario = usuarioNuevo
            };

            Mensaje mensajeRequisitos = ValidarRequisitos(clienteACrear);

            if (mensajeRequisitos.codigoMensaje == "E")
            {
                UsuariosWS.Mensaje mensajeDummy = proxyUsuarios.EliminarUsuario(usuarioNuevo.Codigo);
                return mensajeRequisitos;
            }
            else if (ClienteDAO.Crear(clienteACrear) != null)
            {
                mensajeRetorno.codigoMensaje = "S";
                mensajeRetorno.textMensaje = "Cliente " + nombre + " creado exitosamente";
            }
            else
            {
                UsuariosWS.Mensaje mensajeDummy = proxyUsuarios.EliminarUsuario(usuarioNuevo.Codigo);
                mensajeRetorno.codigoMensaje = "E";
                mensajeRetorno.textMensaje = "No se pudo crear el cliente " + nombre;
            }

            return mensajeRetorno;
        }

        public Cliente ObtenerCliente(int codigo)
        {
            return ClienteDAO.Obtener(codigo);
        }

        public Mensaje ModificarCliente(int codigo, string nombre, string dni, DateTime fecha_nacimiento, string direccion, string distrito, string email, string clave, string brevete)
        {

            Mensaje mensajeRetorno = new Mensaje();

            Cliente clienteAModificar = ClienteDAO.Obtener(codigo);

            Usuario usuarioBkp = clienteAModificar.Usuario;

            UsuariosWS.Mensaje mensajeUsuario = proxyUsuarios.ModificarUsuario(clienteAModificar.Usuario.Codigo,
                                                                               email,
                                                                               clave,
                                                                               clienteAModificar.Usuario.Perfil.Descripcion,
                                                                               clienteAModificar.Usuario.Estado);

            if (mensajeUsuario.codigoMensaje == "E")
            {
                mensajeRetorno.codigoMensaje = mensajeUsuario.codigoMensaje;
                mensajeRetorno.codigoElemento = mensajeUsuario.codigoElemento;
                mensajeRetorno.textMensaje = mensajeUsuario.textMensaje;

                return mensajeRetorno;
            }

            UsuariosWS.Usuario usuarioModificado = proxyUsuarios.ObtenerUsuario(clienteAModificar.Usuario.Codigo);

            Perfil perfilUsuario = new Perfil()
            {
                Codigo = usuarioModificado.Perfil.Codigo,
                Descripcion = usuarioModificado.Perfil.Descripcion
            };

            Usuario usuarioNuevo = new Usuario()
            {
                Codigo = usuarioModificado.Codigo,
                Clave = usuarioModificado.Clave,
                Nombre = usuarioModificado.Nombre,
                Estado = usuarioModificado.Estado,
                Perfil = perfilUsuario
            };

            clienteAModificar.Codigo = codigo;
            clienteAModificar.Nombre = nombre;
            clienteAModificar.NroDNI = dni;
            clienteAModificar.FechaNacimiento = fecha_nacimiento;
            clienteAModificar.Direccion = direccion;
            clienteAModificar.Distrito = distrito;
            clienteAModificar.Email = email;
            clienteAModificar.Brevete = brevete;
            clienteAModificar.Usuario = usuarioNuevo;

            Mensaje mensajeRequisitos = ValidarRequisitos(clienteAModificar);

            if (mensajeRequisitos.codigoMensaje == "E")
            {
                UsuariosWS.Mensaje mensajeDummy = proxyUsuarios.ModificarUsuario(usuarioBkp.Codigo,
                                                                                 usuarioBkp.Nombre,
                                                                                 usuarioBkp.Clave,
                                                                                 usuarioBkp.Perfil.Descripcion,
                                                                                 usuarioBkp.Estado);
                return mensajeRequisitos;
            }

            if (ClienteDAO.Modificar(clienteAModificar) != null)
            {
                mensajeRetorno.codigoMensaje = "S";
                mensajeRetorno.textMensaje = "Cliente " + nombre + " modificado exitosamente";
            }
            else
            {
                UsuariosWS.Mensaje mensajeDummy = proxyUsuarios.ModificarUsuario(usuarioBkp.Codigo,
                                                                                 usuarioBkp.Nombre,
                                                                                 usuarioBkp.Clave,
                                                                                 usuarioBkp.Perfil.Descripcion,
                                                                                 usuarioBkp.Estado);
                mensajeRetorno.codigoMensaje = "E";
                mensajeRetorno.textMensaje = "No se pudo modificar el cliente " + nombre;
            }

            return mensajeRetorno;
        }

        public Mensaje EliminarCliente(int codigo)
        {
            Mensaje mensajeRetorno = new Mensaje();

            Cliente clienteAEliminar = ClienteDAO.Obtener(codigo);

            UsuariosWS.Mensaje mensajeUsuario = proxyUsuarios.DesactivarUsuario(clienteAEliminar.Usuario.Codigo);

            if (mensajeUsuario.codigoMensaje == "E")
            {
                mensajeRetorno.codigoMensaje = mensajeUsuario.codigoMensaje;
                mensajeRetorno.codigoElemento = mensajeUsuario.codigoElemento;
                mensajeRetorno.textMensaje = mensajeUsuario.textMensaje;

                return mensajeRetorno;
            }

            ClienteDAO.Eliminar(clienteAEliminar);

            if (ClienteDAO.Obtener(codigo) == null)
            {
                mensajeRetorno.codigoMensaje = "S";
                mensajeRetorno.textMensaje = "Cliente " + clienteAEliminar.Nombre + " eliminado exitosamente";
            }
            else
            {
                mensajeRetorno.codigoMensaje = "E";
                mensajeRetorno.textMensaje = "No se pudo eliminar el cliente " + clienteAEliminar.Nombre;
            }

            return mensajeRetorno;
        }

        public List<Cliente> ListarClientes()
        {
            return ClienteDAO.ListarTodos().ToList();
        }

        public Cliente ObtenerClienteXEmail(string email)
        {
            return ClienteDAO.ObtenerXEmail(email);
        }

        public Cliente ObtenerClienteXDNI(string dni)
        {
            return ClienteDAO.ObtenerXDNI(dni);
        }

        public Mensaje ValidarRequisitos(Cliente cliente)
        {
            Mensaje mensajeRetorno = new Mensaje();

            // Debe ser mayor de edad
            DateTime fecNac = new DateTime(cliente.FechaNacimiento.Year, cliente.FechaNacimiento.Month, cliente.FechaNacimiento.Day);
            DateTime fecHoy = DateTime.Now;

            TimeSpan ts = fecHoy - fecNac;

            int diferenciaDias = ts.Days;

            if (diferenciaDias / 365 <= 18)
            {
                mensajeRetorno.codigoMensaje = "E";
                mensajeRetorno.textMensaje = "El cliente es menor de edad";
                return mensajeRetorno;
            }

            // Licencia de conducir válida
            if (("Q" + cliente.NroDNI) != cliente.Brevete)
            {
                mensajeRetorno.codigoMensaje = "E";
                mensajeRetorno.textMensaje = "El número de licencia es inválido";
                return mensajeRetorno;
            }

            // Único E-mail
            Cliente clienteDummy = ClienteDAO.ObtenerXEmail(cliente.Email);
            if (clienteDummy != null)
            {
                if (clienteDummy.Codigo != cliente.Codigo)
                {
                    mensajeRetorno.codigoMensaje = "E";
                    mensajeRetorno.textMensaje = "Ya existe un cliente registrado con este correo";
                    return mensajeRetorno;
                }
            }

            // único Número de DNI
            clienteDummy = ClienteDAO.ObtenerXDNI(cliente.NroDNI);
            if (clienteDummy != null)
            {
                if (clienteDummy.Codigo != cliente.Codigo)
                {
                    mensajeRetorno.codigoMensaje = "E";
                    mensajeRetorno.textMensaje = "Ya existe un cliente registrado con este número de DNI";
                    return mensajeRetorno;
                }
            }

            mensajeRetorno.codigoMensaje = "S";
            mensajeRetorno.textMensaje = "Requisitos validados correctamente";

            return mensajeRetorno;
        }
    }
}
Luego editar el archivo “IClientes.cs” con el siguiente código:

namespace GestionServices
{
    [ServiceContract]
    public interface IClientes
    {
        [OperationContract]
        Mensaje CrearCliente(string nombre, string dni, DateTime fecha_nacimiento, string direccion, string distrito, string email, string clave, string brevete);
        [OperationContract]
        Cliente ObtenerCliente(int codigo);
        [OperationContract]
        Mensaje ModificarCliente(int codigo, string nombre, string dni, DateTime fecha_nacimiento, string direccion, string distrito, string email, string clave, string brevete);
        [OperationContract]
        Mensaje EliminarCliente(int codigo);
        [OperationContract]
        List<Cliente> ListarClientes();
        [OperationContract]
        Cliente ObtenerClienteXDNI(string dni);
        [OperationContract]
        Cliente ObtenerClienteXEmail(string email);
        [OperationContract]
        Mensaje ValidarRequisitos(Cliente cliente);
    }
}

Como punto final crearemos los archivos XML en la carpeta “Dominio”
A continuación el archivo “Cliente.hbm.xml”:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="GestionServices"
                   namespace="GestionServices.Dominio"
                   default-lazy="false">
  <class name="Cliente" table="t_clientes">
    <id name="Codigo" column="codigo">
      <generator class="increment" />
    </id>
    <property name="Nombre" column="nombre" />
    <property name="NroDNI" column="nro_dni" />
    <property name="FechaNacimiento" column="fecha_nacimiento" />
    <property name="Direccion" column="direccion" />
    <property name="Distrito" column="distrito" />
    <property name="Email" column="email" />
    <property name="Brevete" column="brevete" />
    <many-to-one name="Usuario" column="codigo_usuario" />
  </class>
</hibernate-mapping>