30 de noviembre de 2018

Consumir Web Api desde MVC(HTTPClient)

Se utilizaran estas tablas creadas en una base de datos utilizando SQL Server

el ejemplo se basara en la tabla empleado, ahora crear un nuevo proyecto vacío y seleccionar Web Api, luego crear el modelo de la base de datos utilizando Entity Framework, se guardará la conexión en el Web.config con el nombre RIAcnx

una vez creado el modelo de la base de datos se debe crear un controlador para la entidad empleado, seleccionando la opción que se muestra en la imagen

y en la capeta Models se crean dos clases, la primera se utilizará para mostrar todos los registros de la tabla empleados o bien un registro especifico.
public class EmpleadoModelApi
 {
  public int id { get; set; }
  public string Nombres { get; set; }
  public string Dpto { get; set; }
  public string Cargo { get; set; }
 }
esta clase se utilizará para crear un nuevo registro en la tabla empleados o bien para actualizar un registro existente.
public class CrearEmpleadoApi
 {
  public int id { get; set; }
  public string Nombres { get; set; }
  public int cargo { get; set; }
  public int Dpto { get; set; }
 }
la solución del proyecto Web Api queda según la imagen

antes de continuar se debe habilitar el CORS(Croos-Origin Request), para esto descargar desde NuGet la dll Microsoft.AspNet.WebApi.Cors y especificar en el WebApiConfig

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
   config.MapHttpAttributeRoutes();
   config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
    );
    config.EnableCors(new EnableCorsAttribute("*", "*", "GET,PUT,POST,DELETE"));
    var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
    config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
  }
}

se utilizará Postman para las pruebas de la Web Api, descargarlo desde la chrome web store, en caso no quieras utilizar Postman puedes utilizar Swagger explicado aqui

ahora el código para el método GET que recuperará todos los registros de la tabla empleados con sus cargo y departamento desde la tablas Cargo y Dpto respectivamente, la consulta utiliza la relación entre estas, igualmente la imagen inferior (click para agrandar)muestra la prueba en Postman con el status code 200 (The request was fulfilled).
private RIAcnx db = new RIAcnx();

[Route("api/Empleados")]
[ResponseType(typeof(List))]
public List Getempleadoes()
{
var Empleados = (from dato in db.empleadoes
                 select new EmpleadoModelApi()
                 {
                  id = dato.id,
                  Nombres = dato.nombre,
                  Cargo = dato.Cargo.Cargo1,
                  Dpto = dato.Dpto.Dpto1
                  }).ToList();
     return Empleados;
}

el código para el método GET que recupera un registro especifico según el id con su respectiva prueba en Postman(click en la imagén)
[Route("api/Empleado/{id}")]
[ResponseType(typeof(empleado))]
public IHttpActionResult Getempleado(int id)
{
 var employee = (from dato in db.empleadoes
                .Where(s => s.id == id)
                 select new EmpleadoModelApi()
                 {
                 id = dato.id,
                 Nombres = dato.nombre,
                 Cargo = dato.Cargo.Cargo1,
                 Dpto = dato.Dpto.Dpto1
                 }).FirstOrDefault();

  if (employee == null)
  {
  return NotFound();
  }
 return Ok(employee);
}

el método PUT para actualizar un empleado se muestra a contiuación  igualmente la imagen inferior (click para agrandar)muestra la prueba en Postman con el status code 200 (The request was fulfilled).  Notar que se especifica el Body en raw y JSON.
[Route("api/PutEmpleado")]
[ResponseType(typeof(EmpleadoModelApi))]
public IHttpActionResult Putempleado(EmpleadoModelApi empleado)
  {
   if (!ModelState.IsValid)
   {
   return BadRequest(ModelState);
   }

   if (empleado.id < 0)
   {
   return BadRequest(ModelState);
   }

   try
   {
   empleado clase = new empleado();
   clase.nombre = empleado.Nombres;
   clase.id = empleado.id;
   clase.IdDpto = Convert.ToInt32(empleado.Dpto);
   clase.IdCargo = Convert.ToInt32(empleado.Cargo);
   db.Entry(clase).State = EntityState.Modified;
   db.SaveChanges();
   }
   catch (DbUpdateConcurrencyException)
   {
   if (!empleadoExists(empleado.id))
    {
    return NotFound();
    }
   else
    {
    throw;
    }
   }
return Ok("Empleado modificado");
}

el método POST para ingresar un nuevo registro en la tabla empleados se muestra a continuación  igualmente la imagen inferior (click para agrandar)muestra la prueba en Postman con el status code 200 (The request was fulfilled).
[Route("api/PostEmpleado")]
[ResponseType(typeof(empleado))]
public IHttpActionResult Postempleado(CrearEmpleadoApi empleado)
{
  if (!ModelState.IsValid)
  {
  return BadRequest("el modelo enviado no es válido");
  }
  try
  {
  empleado clase = new empleado();
  clase.id = Convert.ToInt32(empleado.id);
  clase.nombre = empleado.Nombres.ToString();
  clase.IdCargo = Convert.ToInt32(empleado.cargo);
  clase.IdDpto = Convert.ToInt32(empleado.Dpto);
  db.empleadoes.Add(clase);
  db.SaveChanges();
  return Ok(empleado);
  }
  catch (DbUpdateException)
  {
   if (empleadoExists(empleado.id))
   {
   return Conflict();
   }
   else
   {
   throw;
   }
  }
}

El método DELETE para eliminar un registro especifico de la tabla empleados  igualmente la imagen inferior (click para agrandar)muestra la prueba en Postman con el status code 200 (The request was fulfilled).

[Route("api/DeleteEmpleado/{id}")]
[ResponseType(typeof(empleado))]
public IHttpActionResult Deleteempleado(int id)
{
 if (id <= 0)
 return BadRequest("no es un código válido");

 Int32 codigo = Convert.ToInt32(id);
 empleado empleado = db.empleadoes.Find(id);
  if (empleado == null)
  {
   return NotFound();
  }

  try
  {
  db.empleadoes.Remove(empleado);
  db.SaveChanges();
  }

  catch (DbUpdateConcurrencyException)
  {
  return NotFound();
  }
 return Ok("empleado eliminado");
}

CONSUMIR DESDE MVC UTILIZANDO HTTPCLIENT
Se debe crear un nuevo proyecto en una solución distinta de la anterior, utilizando MVC, luego descargar desde NuGet las líbrerias System.Net.Http y Microsoft ASP.NET Web API 2.2 Client Library



se crearán tres clases en la carpeta Models de la aplicación MVC, esta clase se utilizará para enviar los datos del nuevo empleado que ingresará como nuevo registro en la tabla empleados.
public class CrearEmpleado
 {
  [Required (ErrorMessage="debe especificar nombre de empleado")]
  public string Nombres { get; set; }
  [Required (ErrorMessage="especifique código del cargo")]
  public int cargo { get; set; }
  [Required (ErrorMessage="especifique código del departamento")]
  public int Dpto { get; set; }
  [Required(ErrorMessage = "especifique código del empleado")]
  public int id { get; set; }
 }

esta clase se utilizará para mostrar todos los registros de la tabla empleado o bien para mostrar un registro especifico
public class EmpleadoModelMVC
    {
        public int id { get; set; }
        public string Nombres { get; set; }
        public string Dpto { get; set; }
        public string Cargo { get; set; }
    }

esta clase se utilizará para obtener el id del registro en la tabla empleado que se desea eliminar, puede obviarse esta clase, utilizar un textbox de razor y validar del lado del cliente antes de realizar la llamada al Web Api.
public class EliminarMVC
 {
  [Required (ErrorMessage="Especificar numero entero")]
  public int codigo { get; set; }
 }
esta es la llamada desde MVC para obtener todos los registros de la tabla empleado.
[HttpGet]
public ActionResult Empleados()
{
 IList empleados = null;
 using (var client = new HttpClient())
 {
 try
  {
   client.BaseAddress = new Uri("http://localhost:55987/api/");
   client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
   var responseTask = client.GetAsync("Empleados");
   responseTask.Wait();
   var result = responseTask.Result;
   if (result.IsSuccessStatusCode)
   {
    var readTask = result.Content.ReadAsAsync>();
    readTask.Wait();
    empleados = readTask.Result;
   }
   else
   {
    empleados = null;
    ModelState.AddModelError(string.Empty, "Server error !!!");
   }
  }
  catch (Exception ex)
  {
   throw new ArgumentException(ex.Message.ToString());
  }
 }
 return View(empleados);
}

esta es la llamada desde MVC para obtener un registro especifico de la tabla empleado, se utiliza la clase EliminarMVC.cs pues solamente se necesita el código del registro a eliminar.
[HttpGet]
public ActionResult BuscarEmpleado()
{
 return View();
}

[HttpPost]
public ActionResult BuscarEmpleado(EliminarMVC dato)
{
 if (!ModelState.IsValid)
 {
 ModelState.AddModelError("", "Error en el modelo, verificar !!!");
 }

 try
 {
 EmpleadoModelMVC empleados = null;
 Int32 codigo = Convert.ToInt32(dato.codigo);

 using (var client = new HttpClient())
 {
  client.BaseAddress = new Uri("http://localhost:55987/api/");
  client.DefaultRequestHeaders.Accept.Clear();
  client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  var GetTask = client.GetAsync("Empleado/" + codigo.ToString());
  GetTask.Wait();

  var result = GetTask.Result;
  if (result.IsSuccessStatusCode)
  {    
   var readTask = result.Content.ReadAsAsync();
   readTask.Wait();
   empleados = readTask.Result;
   return View("ResultadoEmpleado",empleados);
  }
  else
  {
   empleados = null;
   ModelState.AddModelError(string.Empty, "Server error !!!");
  }
 }
 }
 catch (Exception)
 {
 throw;
 }
 return View(dato);
}

esta es la llamada desde MVC para agregar un nuevo registro a la tabla empleado.
[HttpGet]
public ActionResult CrearEmpleado()
{
 return View();
}

[HttpPost]
public ActionResult CrearEmpleado(CrearEmpleado empleado)
{
 string excepcion = string.Empty;
 try
 {
 using (var client = new HttpClient())
 {
  client.BaseAddress = new Uri("http://localhost:55987/");
  client.DefaultRequestHeaders.Accept.Clear();
  client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  var postTask = client.PostAsJsonAsync("api/PostEmpleado", empleado);
  postTask.Wait();
  var result = postTask.Result;
  if (result.IsSuccessStatusCode)
  {
   return RedirectToAction("Empleados");
  }
 }
 }
 catch (Exception ex)
 {
 excepcion = ex.Message.ToString();
 }
 ModelState.AddModelError(excepcion, "Server Error. Please contact administrator.");
 return View(empleado);
}

esta es la llamada desde MVC para actualizarun registro especifico de la tabla empleado.
[HttpGet]
public ActionResult ActualizarEmpleado()
{
 return View();
}

[HttpPost]
public ActionResult ActualizarEmpleado(CrearEmpleado Empleado)
{
 string excepcion = string.Empty;
 try
 {
 using (var client = new HttpClient())
 {
  client.BaseAddress = new Uri("http://localhost:55987/");
  var postTask = client.PutAsJsonAsync("api/PutEmpleado", Empleado);
  client.DefaultRequestHeaders.Accept.Clear();
  client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  postTask.Wait();
  var result = postTask.Result;
  if (result.IsSuccessStatusCode)
  {
   return RedirectToAction("Empleados");
  }
  }
 }
 catch (Exception ex)
 {
 excepcion = ex.Message.ToString();
 }

 ModelState.AddModelError(excepcion, "Server Error. Please contact administrator.");
 return View(Empleado);
}

esta es la llamada desde MVC para eliminar un registro especifico de la tabla empleado.
[HttpGet]
public ActionResult EliminarEmpleado()
{
 return View();
}

[HttpPost]
public ActionResult EliminarEmpleado(EliminarMVC dato)
{
 if (!ModelState.IsValid)
 {
  ModelState.AddModelError("", "Error en el módelo, verificar !!!");
 }

 try
 {
 Int32 codigo = Convert.ToInt32(dato.codigo);
 using (var client = new HttpClient())
  {
   client.BaseAddress = new Uri("http://localhost:55987/api/");
   client.DefaultRequestHeaders.Accept.Clear();
   client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
   var deleteTask = client.DeleteAsync("DeleteEmpleado/" + codigo.ToString());
   deleteTask.Wait();
   var result = deleteTask.Result;
   if (result.IsSuccessStatusCode)
   {
   return RedirectToAction("Empleados");
   }
  }
 }
 catch (Exception)
 {
  throw;
 }
 return View();
}