domingo, 23 de octubre de 2016

CRUD Kendo Grid ASP.NET MVC, con Entity Framework a SQL Server - Part 2

En es post continuaremos desarrollando nuestro proyecto Visual Studio 2015 para administrar tablas mediante operaciones CRUD (ver primera parte) con ASP.NET MVC 5 WebAPI 2 RESTful , jQuery y Kendo UI Grid.

Ahora construiremos una API para gestionar los datos de nuestras tablas de Empleados y Puestos. Para esto aprovecharemos las ventajas que nos proporciona la Web API 2 para crear de manera muy sencilla tablas de rutas de links mediante etiquetas en nuestros métodos así cumpliendo la metodología RESTful de manera completa, con lo cual aprovecharemos los verbos HTTP PUT, DELETE, POST y GET para redirigir las acciones a los métodos que realizan las acciones de crear, eliminar, actualizar y obtener datos respectivamente. Existen otros verbos pero por ahora utilizaremos solo estos.

Lo primero que haremos es crear una nueva carpeta en nuestro proyecto Administrador.Data llamada Proxy

A continuación agregaremos las siguientes dos clases, que principalmente nos proporciona los métodos necesarios para realizar las operaciones CRUD con Entity Framework:

Código de la clase Empleados en la carpeta Proxy:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Administrador.Data.Proxy
{
    public class Empleados
    {
        public static List<Models.Empleados> ObtenerTodo()
        {
            var resultado = new List<Models.Empleados>();

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Empleados.ToList();
            }
   
            return resultado;
        }

        public static List<Models.Empleados> Obtener(int cantidad, int pagina)
        {
            var resultado = new List<Models.Empleados>();

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Empleados.OrderBy(e=>e.Nombre).Skip((pagina - 1) * cantidad).Take(cantidad).ToList();
            }

            return resultado;
        }

        public static int Cantidad()
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Empleados.OrderBy(e => e.Nombre).Count();
            }

            return resultado;
        }

        public static Models.Empleados Obtener(Guid Id)
        {
            var resultado = new Models.Empleados();

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Empleados.FirstOrDefault(e=>e.Id == Id);
            }

            return resultado;
        }

        public static int Crear(Models.Empleados empleado)
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                var auxEmpleado = new Models.Empleados
                {
                    Apellido = empleado.Apellido,
                    Descripcion = empleado.Descripcion,
                    Edad = empleado.Edad,
                    frk_Puesto = empleado.frk_Puesto,
                    Id = Guid.NewGuid(),
                    Nombre = empleado.Nombre,
                    Puestos = empleado.Puestos,
                    Salario = empleado.Salario
                };

                _db.Entry(auxEmpleado).State = System.Data.Entity.EntityState.Added;

                resultado = _db.SaveChanges();
            }

            return resultado;
        }

        public static int Actualizar(Models.Empleados empleado)
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                var auxEmpleado = _db.Empleados.FirstOrDefault(e => e.Id == empleado.Id);
                if (auxEmpleado != null)
                {
                    auxEmpleado.Apellido = empleado.Apellido;
                    auxEmpleado.Descripcion = empleado.Descripcion;
                    auxEmpleado.Edad = empleado.Edad;
                    auxEmpleado.frk_Puesto = empleado.frk_Puesto;
                    auxEmpleado.Nombre = empleado.Nombre;
                    auxEmpleado.Puestos = empleado.Puestos;
                    auxEmpleado.Salario = empleado.Salario;

                    _db.Entry(auxEmpleado).State = System.Data.Entity.EntityState.Modified;

                    resultado = _db.SaveChanges();
                }
            }

            return resultado;
        }

        public static int Eliminar(Guid Id)
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                var auxEmpleado = _db.Empleados.FirstOrDefault(e => e.Id == Id);

                _db.Entry(auxEmpleado).State = System.Data.Entity.EntityState.Deleted;

                resultado = _db.SaveChanges();
            }

            return resultado;
        }
    }
}

Código de la clase Puestos en la carpeta Proxy:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Administrador.Data.Proxy
{
    public class Puestos
    {
        public static List<Models.Puestos> ObtenerTodo()
        {
            var resultado = new List<Models.Puestos>();

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Puestos.ToList();
            }

            return resultado;
        }

        public static List<Models.Puestos> Obtener(int cantidad, int pagina)
        {
            var resultado = new List<Models.Puestos>();

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Puestos.OrderBy(e => e.Nombre).Skip((pagina - 1) * cantidad < 0 ? 0 : (pagina - 1) * cantidad).Take(cantidad).ToList();
            }

            return resultado;
        }

        public static int Cantidad()
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Puestos.OrderBy(e => e.Nombre).Count();
            }

            return resultado;
        }

        public static Models.Puestos Obtener(Guid Id)
        {
            var resultado = new Models.Puestos();

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                resultado = _db.Puestos.FirstOrDefault(e => e.Id == Id);
            }

            return resultado;
        }

        public static int Crear(Models.Puestos puesto)
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                var auxPuesto = new Models.Puestos
                {
                    Id = Guid.NewGuid(),
                    Nombre = puesto.Nombre,
                    Descripcion = puesto.Descripcion
                };

                _db.Entry(auxPuesto).State = System.Data.Entity.EntityState.Added;
                resultado = _db.SaveChanges();
            }

            return resultado;
        }

        public static int Actualizar(Models.Puestos puesto)
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                var auxPuesto = _db.Puestos.FirstOrDefault(e => e.Id == puesto.Id);

                if (auxPuesto != null)
                {
                    auxPuesto.Descripcion = puesto.Descripcion;
                    auxPuesto.Nombre = puesto.Nombre;

                    _db.Entry(auxPuesto).State = System.Data.Entity.EntityState.Modified;
                    resultado = _db.SaveChanges();
                }
            }

            return resultado;
        }

        public static int Eliminar(Guid Id)
        {
            var resultado = 0;

            using (var _db = new Models.dbGrillaKendoEntities())
            {
                var auxPuesto = _db.Puestos.FirstOrDefault(e => e.Id == Id);

                if (auxPuesto != null)
                {
                    _db.Entry(auxPuesto).State = System.Data.Entity.EntityState.Deleted;
                    resultado = _db.SaveChanges();
                }
            }

            return resultado;
        }
    }
}
Utilizamos la instrucción using para administrar la instancia de Entity Framework ya que nos facilita liberar los recursos una vez finalizada la consulta a la base de datos.

Ahora nos vamos de lleno al proyecto Administrador.WebApi para crear nuestra Web API RESTful.

Lo primero que haremos es configurar el proyecto para que nuestra API RESTful retorne de manera segura datos en formato JSON. Para esto agregaremos el siguiente código que esta en verde en el archivo WebApiConfig.cs que esta en la carpeta App_Start:

public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

Ahora agregaremos la clase Empleado a nuestro modelo de vistas. Para esto crearemos un nuevo archivo llamado Empleado.cs en la carpeta Models/Views y pegar el siguiente código:

Código de la clase Empleado:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;

namespace Administrador.WebApp.Models.Views
{
    public class Empleado
    {
        public System.Guid Id { get; set; }
        public string Nombre { get; set; }
        public string Apellido { get; set; }
        public Nullable<int> Edad { get; set; }
        public Nullable<decimal> Salario { get; set; }
        [DisplayName("Descripción")]
        public string Descripcion { get; set; }
        public Nullable<System.Guid> frk_Puesto { get; set; }
    }
}

Para ir finalizando y sacando conclusiones añadiremos solo dos clases más, que vendrían a ser nuestro punto de entrada a la API REST.

Creamos una nueva carpeta en nuestro proyecto Administrador.WebApi llamada APIRest.

Ahora en esta carpeta creamos el archivo EmpleadosController.cs y reemplazamos con el siguiente código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace Administrador.WebApp.APIRest
{
    [RoutePrefix("APIEmpleados")]
    public class EmpleadosController : ApiController
    {
        [HttpGet]
        [Route("{cantidad?}/{pagina?}")]
        public object Obtener([FromUri] int cantidad = 10, [FromUri] int pagina = 1)
        {
            var resultado = new List<Models.Views.Empleado>();
            foreach (var item in Administrador.Data.Proxy.Empleados.Obtener(cantidad, pagina))
            {
                resultado.Add(new Models.Views.Empleado
                {
                    Apellido = item.Apellido,
                    Descripcion = item.Descripcion,
                    Edad = item.Edad,
                    frk_Puesto = item.frk_Puesto,
                    Id = item.Id,
                    Nombre = item.Nombre,
                    Salario = item.Salario
                });
            }

            return new
            {
                datos = resultado,
                total = Administrador.Data.Proxy.Empleados.Cantidad()
            };
        }

        [HttpGet]
        [Route("")]
        public object ObtenerTodo()
        {
            var resultado = new List<Models.Views.Empleado>();
            foreach (var item in Administrador.Data.Proxy.Empleados.ObtenerTodo())
            {
                resultado.Add(new Models.Views.Empleado
                {
                    Descripcion = item.Descripcion,
                    Id = item.Id,
                    Nombre = item.Apellido = item.Apellido,
                    Edad = item.Edad,
                    frk_Puesto = item.frk_Puesto,
                    Salario = item.Salario,
                    Apellido = item.Apellido
                });
            }

            return new
            {
                datos = resultado,
                total = Administrador.Data.Proxy.Empleados.Cantidad()
            };
        }

        [HttpGet]
        [Route("{id:guid}")]
        public object Obtener([FromUri] Guid id)
        {
            var resultado = new Models.Views.Empleado();

            var auxEmpleado = Administrador.Data.Proxy.Empleados.Obtener(id);

            resultado.Apellido = auxEmpleado.Apellido;
            resultado.Descripcion = auxEmpleado.Descripcion;
            resultado.Edad = auxEmpleado.Edad;
            resultado.frk_Puesto = auxEmpleado.frk_Puesto;
            resultado.Id = auxEmpleado.Id;
            resultado.Nombre = auxEmpleado.Nombre;
            resultado.Salario = auxEmpleado.Salario;

            return new { datos = resultado };
        }

        [HttpPut]
        [Route("")]
        public object Crear([FromBody] Models.Views.Empleado empleado)
        {
            var resultado = Administrador.Data.Proxy.Empleados.Crear(new Data.Models.Empleados
            {
                Apellido = empleado.Apellido,
                Descripcion = empleado.Descripcion,
                Edad = empleado.Edad,
                frk_Puesto = empleado.frk_Puesto,
                Id = Guid.NewGuid(),
                Nombre = empleado.Nombre,
                Salario = empleado.Salario
            });

            return new { datos = resultado };
        }

        [HttpPost]
        [Route("")]
        public object Actualizar([FromBody] Models.Views.Empleado empleado)
        {
            var resultado = Administrador.Data.Proxy.Empleados.Actualizar(new Data.Models.Empleados
            {
                Apellido = empleado.Apellido,
                Descripcion = empleado.Descripcion,
                Edad = empleado.Edad,
                frk_Puesto = empleado.frk_Puesto,
                Id = empleado.Id,
                Nombre = empleado.Nombre,
                Salario = empleado.Salario
            });

            return new { datos = resultado };
        }

        [HttpDelete]
        [Route("{id:guid}")]
        public object Eliminar([FromUri] Guid id)
        {
            var resultado = Administrador.Data.Proxy.Empleados.Eliminar(id);

            return new { datos = resultado };
        }
    }
}


Por último creamos el archivo PuestosController.cs en esta misma carpeta y reemplazamos con el siguiente código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace Administrador.WebApp.APIRest
{
    [RoutePrefix("APIPuestos")]
    public class PuestosController : ApiController
    {
        [HttpGet]
        [Route("{cantidad?}/{pagina?}")]
        public object Obtener([FromUri] int cantidad = 10, [FromUri] int pagina = 1)
        {
            var resultado = new List<Models.Views.Puesto>();
            foreach (var item in Administrador.Data.Proxy.Puestos.Obtener(cantidad, pagina))
            {
                resultado.Add(new Models.Views.Puesto
                {
                    Descripcion = item.Descripcion,
                    Id = item.Id,
                    Nombre = item.Nombre
                });
            }

            return new {
                datos = resultado,
                total = Administrador.Data.Proxy.Puestos.Cantidad()
            };
        }

        [HttpGet]
        [Route("")]
        public object ObtenerTodo()
        {
            var resultado = new List<Models.Views.Puesto>();
            foreach(var item in Administrador.Data.Proxy.Puestos.ObtenerTodo())
            {
                resultado.Add(new Models.Views.Puesto
                {
                    Descripcion = item.Descripcion,
                    Id = item.Id,
                    Nombre = item.Nombre
                });
            }

            return new
            {
                datos = resultado,
                total = Administrador.Data.Proxy.Puestos.Cantidad()
            };
        }

        [HttpGet]
        [Route("{id:guid}")]
        public object Obtener([FromUri] Guid id)
        {
            var resultado = new Models.Views.Puesto();

            var auxPuesto = Administrador.Data.Proxy.Puestos.Obtener(id);

            resultado.Descripcion = auxPuesto.Descripcion;
            resultado.Id = auxPuesto.Id;
            resultado.Nombre = auxPuesto.Nombre;

            return new { datos = resultado };
        }

        [HttpPut]
        [Route("")]
        public object Crear([FromBody] Models.Views.Puesto puesto)
        {
            var resultado = Administrador.Data.Proxy.Puestos.Crear(new Data.Models.Puestos
            {
                Descripcion = puesto.Descripcion,
                Empleados = null,
                Id = Guid.NewGuid(),
                Nombre = puesto.Nombre
            });

            return new { datos = resultado };
        }

        [HttpPost]
        [Route("")]
        public object Actualizar([FromBody] Models.Views.Puesto puesto)
        {
            var resultado = Administrador.Data.Proxy.Puestos.Actualizar(new Data.Models.Puestos
            {
                Descripcion = puesto.Descripcion,
                Empleados = null,
                Id = puesto.Id,
                Nombre = puesto.Nombre
            });

            return new { datos = resultado };
        }

        [HttpDelete]
        [Route("{id:guid}")]
        public object Eliminar([FromUri] Guid id)
        {
            var resultado = Administrador.Data.Proxy.Puestos.Eliminar(id);

            return new { datos = resultado };
        }
    }
}


Para probar esta API REST podemos utilizar Fiddler, ya que nos permite ejecutar llamadas utilizando los verbos HTTP.

Para el caso de la API de los datos de Puestos los URL para llamar son utilizando el prefijo APIPuestos, y para empleados APIEmpleados.

Por ejemplo :



Como conclusión se puede destacar la etiqueta Route y RoutePrefix que nos permiten configurar nuestras URLs de manera muy sencilla.