Developing ASP.net MVC 4 Web Applications
-
Upload
nataniel-marcial-chavez -
Category
Documents
-
view
136 -
download
6
description
Transcript of Developing ASP.net MVC 4 Web Applications
-
Presented by
Nataniel Marcial
Developing ASP.NET MVC 4 Web Applications
-
Web API es una opcin que tenemos disponible en el mundo .Net para el desarrollo de servicios REST
Bsicamente trabajan sobre el protocolo HTTP, permitiendo hacer uso de los diferentes verbos disponibles como Get, Put, Post, Delete, entre otros.
Web API NO es ASP.NET MVC!
Introduccion
-
Mi primer proyecto
Creando un CRUD, trabajando con verbos HTTP
Consumiendo el servicio
Implementando Knockoutjs.
Training Outline
-
Lo primero es crear una nueva aplicacin de tipo ASP.NET Web Application.
Mi primer proyecto
-
Luego seleccionamos la plantilla Web API:
-
Una vez finaliza la creacin del proyecto, ya tenemos toda la estructura necesaria para trabajar con servicios REST con Web API.
-
Todos los controladores en Web API deben heredar de la clase
ApiController, disponible en el namespace System.Web.Http.
Los nombres de los controladores deben finalizar con el texto
Controller, as entonces si creamos un controlador llamado Test,
su nombre real ser TestController.
C#
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
Si revisamos la carpeta Controllers, podemos ver que la plantilla
nos ha creado dos controladores, un HomeController de
ASP.NET MVC y un ValuesControles de Web API, y dndole
una mirada a ValuesController tenemos:
Dicho controlador tiene ya varias acciones definidas, y en
especial dos mtodos Get para obtener datos, as que probemos
esos dos mtodos, para ello ejecutemos la aplicacin y en la
barra de direcciones adicionamos:
/api/Values el cual llama el mtodo Get que retorna toda la
coleccin de objetos y con /api/Values/id llama el mtodo Get
que recibe un id como parmetro.
-
Implementar fcilmente un CRUD (create, read, update y delete
Creando un CRUD, trabajando con verbos HTTP
-
Lo primero que necesitamos es una clase (modelo) sobre la cual implementar el CRUD, la clase es sencilla pero de utilidad
para el ejemplo:
-
using System;using System.Collections.Generic;using System.Linq;using System.Web;
namespace MvcApplication1.Models{
public class Person{
public int Id { get; set; }public string Name { get; set; }public string LastName { get; set; }public string Twitter { get; set; }
}
}
-
Ahora, crearemos la clase que ser el contexto de nuestra base de datos para lo cual usaremos Entity Framework:
using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Web;
namespace MvcApplication1.Models{
public class PersonDBContext : DbContext{
public DbSet Person { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder){
base.OnModelCreating(modelBuilder);}
}
}
-
Ya que tenemos el contexto y nuestro modelo, es momento de definir como se inicializara nuestra base de datos, as entonces
en la carpeta App_Start adicionamos una nueva clase llamada PersonDBInitializer:
using MvcApplication1.Models;using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Web;
namespace MvcApplication1.App_Start{
public class PersonDBInitializer : DropCreateDatabaseAlways{
protected override void Seed(PersonDBContext context){
var persons = new List {new Person { Name = "Julio", LastName = "Avellaneda", Twitter = "@julitogtu"},new Person { Name = "Juan", LastName = "Ruiz", Twitter = "@juankruiz"},new Person { Name = "Roberto", LastName = "Alvarado", Twitter = "@ralvaradot"},new Person { Name = "Nicolas", LastName = "Herrera", Twitter = "@nicolocodev"},new Person { Name = "Jorge", LastName = "Ramirez", Twitter = "@jramirezdev"},new Person { Name = "Nelson", LastName = "Venegas", Twitter = "@nvenegar"}
};persons.ForEach(c => context. People.Add(c));context.SaveChanges();
}}
}
-
Ahora en el Application_Start() del Global.asax lo definimos:
C#
protected void Application_Start()
{
...
Database.SetInitializer(new PersonDBInitializer());
}
Y para finalizar con el tema asociado definimos la cadena de conexin en el web.config:
C#
-
Ahora volviendo al tema de Web API, es hora de crear el controlador, y para ello Web API nos ayuda bastante; damos
clic derecho en la carpeta Controllers, luego Add -> Controller:
-
Luego seleccionamos Web API 5 with read/write actions, using Entity Framework, y en la ventana que se abre definimos
el nombre del contralor, el modelo y el contexto de base de datos:
-
Una vez finaliza la creacin del controlador, el asistente nos ha creado el controlador con todas las acciones CRUD:
Accin Verbo Http Funcionalidad
GetPerson Get Obtener todos los elementos
GetPerson (Int32 id) Get Obtener un elemento por id
PutPerson (Int32 id, Person person) Put Actualizar elemento por su id
PostPerson(Person person) Post Insetar un nuevo elemento
DeletePerson(Int32 id) Delete Eliminar elemento
Revisando entonces cada una de las acciones, podemos ver que todas las operaciones CRUD ya fueron implementadas, y en este caso el nombre de cada
accin tiene una fuerte relacin con el nombre de los verbos Http:
Ahora ya tenemos todo listo para comenzar a consumir el servicio.
-
Consumiendo el servicio
-
Primero vamos a modificar un poco el HTML de la vista
Index del controlador Home, para el ejemplo todas las
operaciones las vamos a realizar all:
Get All
NameLast NameTwitter
Get one
Id:
Name:
Last name:
Twitter:
@section scripts{
}
-
Listo, ya tenemos el HTML listo, ahora a implementar cada funcionalidad:
Obtener todos
$(document).on("ready",
function () {
GetAll();
})
//Get all personsfunction GetAll() {
var item = "";$('#tblList tbody').html('');$.getJSON('/api/person', function (data) {
$.each(data, function (key, value) {item += "" + value.Name + ""
+ value.LastName + "" + value.Twitter + "";
});$('#tblList tbody').append(item);
});};
Lo primero que hacemos es validar que la pgina se ha cargado
totalmente
Luego realizamos un llamado a la funcin GetAll la cual se
encarga de realizar la peticin a la accin GetPerson() del
controlador que retorna todo el conjunto de resultados, y cmo
lo hace?,
Como estamos usando la funcin getJSON entonces ya la
peticin al verbo Get, y como no le estamos enviando
parmetros entonces responde la accin que no recibe
ningunoGetPeron()
Luego con el $.each recorremos los elementos y llenamos la
tabla.
-
Obtener un elemento
Ahora si queremos obtener 1 solo elemento, debemos pasarle el id que deseamos buscar, ya que en la accin en el
controlador lo recibe GetPerson(Int32 id), entonces aadimos la siguiente funcin
//Get person by idfunction GetPersonById(idPerson) {
var url = '/api/person/' + idPerson;$.getJSON(url)
.done(function (data) {$('#txtName').val(data.Name);$('#txtLastName').val(data.LastName);$('#txtTwitter').val(data.Twitter);
}).fail(function (erro) {
ClearForm();});
};
Y al botn de buscar un manejador para el evento clic:
$(document).on("ready", function () {$('#btnSearch').on('click', function () {
GetPersonById($('#txtIdSearch').val());})
GetAll();})
De nuevo usamos $.getJSON,
En este caso cuando la peticin se ejecuta correctamente entra al
done donde asignamos valores a los campos de texto con los
datos de la persona retornada
En caso que se produzca algn error se va la ejecucin por el
fail.
/Clear formfunction ClearForm() {
$('#txtIdSearch').val('');$('#txtName').val('');$('#txtLastName').val('');$('#txtTwitter').val('');
}
-
Eliminar un elemento por su id
Pasamos ahora a la eliminacin, y en este caso vamos a enviarle el id de la persona que deseamos eliminar, por lo que se
usar la accin DeletePerson(Int32 id), como antes lo primero es la funcin que hace el llamado:
//Delete person by idfunction DeletePersonById(idPerson) {
var url = '/api/person/' + idPerson;$.ajax({
url: url,type: 'DELETE',contentType: "application/json;chartset=utf-8",statusCode: {
200: function () {GetAll();ClearForm();alert('Person with id: ' + idPerson + ' was deleted');
},404: function () {
alert('Person with id: ' + idPerson + ' was not found');
}}
});}
Luego el manejador para el botn y el evento click:
$('#btnDelete').on('click', function () {DeletePersonById($('#txtIdSearch').val());
})
En este caso hacemos uso de $.ajax, definimos la url y le
adicionamos el id de la persona a eliminar, definimos el
type (verbo Http a usar) en DELETE, y manejamos
entonces el cdigo Http como respuesta de consumir el
servicio (statusCode), ya que si revisan la accin esta
retorna un HttpResponseMessage, en donde se tiene un
cdigo 200 (HttpStatusCode.OK) cuando la eliminacin
es correcta o un 404 (HttpStatusCode.NotFound) cuando
no se encuentra una persona con el id enviado o la
eliminacin falla.
-
Actualizar un elemento
Solo nos resta la actualizacin, as que primero la funcin:
//Update personfunction UpdatePerson(idPerson, person) {
var url = '/api/person/' + idPerson;$.ajax({
url: url,type: 'PUT',data: person,contentType: "application/json;chartset=utf-8",statusCode: {
200: function () {GetAll();ClearForm();alert('Person with id: ' + idPerson + ' was updated');
},404: function () {
ClearForm();alert('Person with id: ' + idPerson + ' was not
found');},400: function () {
ClearForm();alert('Error');
}}
});}
Luego el manejador para el botn y el evento click:
$('#btnUpdate').on('click', function () {var person = new Object();person.id = $('#txtIdSearch').val();person.name = $('#txtName').val();person.lastname = $('#txtLastName').val();person.twitter = $('#txtTwitter').val();UpdatePerson(person.id, JSON.stringify(person));
})
Al igual que para la eliminacin usamos $.ajax pero en este caso el
type lo definimos con el verbo PUT, en la url le pasamos el id de la
persona y en el parmetro data le enviamos el objeto person y
finalmente de nuevo validamos la respuesta usando los cdigos
Http, 200 (HttpStatusCode.OK), 404 (HttpStatusCode.NotFound) y
400 (HttpStatusCode.BadRequest).
En el llamado a la funcin creamos un nuevo objeto al cual le
definimos los propiedades y sus correspondientes valores (mismos
nombres que las propiedades en la clase C#) y la serializamos con
JSON.stringify.
-
Insertar un nuevo elemento
Como ltima accin a implementar, ahora vamos a crear una nueva persona, primero entonces la funcin que hace el llamado:
//Create a new personfunction CreatePerson(person) {
var url = '/api/person/';$.ajax({
url: url,type: 'POST',data: person,contentType: "application/json;chartset=utf-8",statusCode: {
201: function () {GetAll();ClearForm();alert('Person with id: ' + idPerson + ' was updated');
},400: function () {
ClearForm();alert('Error');
}}
});}
El manejador para el botn y el evento click:
$('#btnCreate').on('click', function () {var person = new Object();person.name = $('#txtName').val();person.lastname = $('#txtLastName').val();person.twitter = $('#txtTwitter').val();CreatePerson(JSON.stringify(person));
})
Y de nuevo aparece en escena $.ajax en esta
ocasin con el type POST, y manejamos la
respuesta de nuevo con cdigos Http, el 201
(HttpStatusCode.Created) que indica que se cre el
elemento y el 400 para el error.
-
Finalmente la sencilla aplicacin se ver como:
-
Implementando Knockoutjs
-
En el tema anterior vimos cmo podemos consumir nuestro servicio REST de Web API utilizando jQuery y AJAX, creamos un archivo JavaScript para mantener separado el contenido (HTML) del comportamiento de la pgina (JavaScript), sin embargo, con solo observar el archivo creado, nos damos cuenta que dicha afirmacin no es del todo cierta, puesto que tenemos una dependencia total a los elementos del DOM, y si en algn momento el HTML llega a cambiar o los ids de los elementos vamos a tener problemas
Para solucionar el problema anterior, una posible solucin es implementar un framework JavaScript como Knockout,
el cual permite trabajar el patrn MVVM (model-view-view model) en el cliente.
Ahora en la clase BundleConfig (en la carpeta App_Start) en el mtodo RegisterBundles aadimos un nuevo bundle
para knockout:
bundles.Add(new ScriptBundle("~/bundles/knockout").Include("~/Scripts/knockout-2.2.0.js")
Luego en el layout (Views/Shared/_Layout.cshtml) del sitio lo referenciamos al final:
@Scripts.Render("~/bundles/knockout")
-
Ahora que ya tenemos listo a Knockout, iniciamos con el refactoring de person.js, la idea es crear un ViewModel que
permita trabajar de manera desconectada del DOM las operaciones CRUD implementadas, lo primero que haremos y para
poder trabajar mejor con Knockout es agregar una referencia a knockout-2.3.0.debug.js en personko.js para tener
intellisense
///
var PersonViewModel = function () {self = this;self.id = ko.observable();self.name = ko.observable();self.lastname = ko.observable();self.twitter = ko.observable();self.personList = ko.observableArray();
}
Luego definimos el modelo:
Y al definir el modelo ya tenemos varios cambios importantes:
Definicin del objeto PersonViewModel
A self le asignamos this para evitar conflictos al acceder a las propiedades
del objeto
Las propiedades se definen como observables, es decir si cambia la
propiedad el objeto HTML asociado tambin lo har, y viceversa.
La propiedad personList es observable y a la vez es un array.
-
Ahora comenzamos a aadir funciones a nuestro viewmodel:
Obtener todos los elementos
self.getAll = function () {$.getJSON('/api/person', function (data) {
self.personList(data);});
}
En este caso de nuevo se realiza la peticin con $.getJSON, la diferencia radica en que la respuesta se la seteamos como
valor al array observable.
-
Obtener un elemento
self.getPersonById = function () {var url = '/api/person/' + self.id();$.getJSON(url)
.done(function (data) {self.name(data.Name);self.lastname(data.LastName);self.twitter(data.Twitter);
}).fail(function (erro) {
self.clearForm();});
}
La funcionalidad bsica permanece casi que igual, sin
embargo los cambios que se observan son: Se utiliza self.id() para obtener el valor de la propiedad
id del objeto en lugar de consultar el DOM
Si la respuesta es correcta, se asignan los valores a las
propiedades del objeto y no directamente a los
elementos del DOM.
self.clearForm = function () {self.id('');self.name('');self.lastname('');self.twitter('');
}
-
Eliminar elemento por id
self.deletePersonById = function () {var url = '/api/person/' + self.id();$.ajax({
url: url,type: 'DELETE',contentType: "application/json;chartset=utf-8",statusCode: {
200: function () {self.getAll();self.clearForm();alert('Person with id= ' + self.id() + '
was deleted');},404: function () {
alert('Person with id= ' + self.id() + ' was not found');
}}
});}
El cambio importante es que para acceder al id de la persona de utiliza self.id() en lugar de acceder al elemento del DOM para leer su valor
-
Actualizar y crear un elemento
self.updatePerson = function () {var url = '/api/person/' + self.id();$.ajax({
url: url,type: 'PUT',data: ko.toJSON(self),contentType: "application/json;chartset=utf-8",statusCode: {
200: function () {self.getAll();self.clearForm();alert('Person with id= ' + self.id() + '
was updated');},404: function () {
self.clearForm();alert('Person with id= ' + self.id() + '
was not found');},400: function () {
self.clearForm();alert('Error');
}}
});}
self.createPerson = function () {var url = '/api/person/';$.ajax({
url: url,type: 'POST',data: ko.toJSON(self),contentType: "application/json;chartset=utf-8",statusCode: {
201: function () {self.getAll();self.clearForm();alert('Person was created');
},400: function () {
self.clearForm();alert('Error');
}}
});}
-
En la actualizacin y creacin de un elemento se comparten los cambios, las dos acciones en el lado del servidor
reciben un objeto de tipo Person, lo cual anteriormente hacamos creando un nuevo objeto, asignndoles
propiedades y finalmente serializndolo, sin embargo Knockout ofrece una forma ms sencilla de realizar este
proceso, simplemente con ko.toJSON(modelo) se realiza la serializacin del objeto.
Y como relacionamos ese modelo con nuestro HTML dicho proceso tiene dos pasos:
Paso 1: Llamar el viewmodel y enlazarlo
$(document).on("ready", function () {var personvm = new PersonViewModel();ko.applyBindings(personvm);personvm.getAll();
})
En este caso, una vez la pgina est cargada, creamos un nuevo objeto de tipo PersonViewModel, luego con
ko.applyBindings(modelo) aplicamos los bindgins y finalmente hacemos el llamado a la funcin que obtiene todos los
elementos:
-
Paso 2: Definir los bindings en el HTML
NameLast NameTwitter
El primer cambio se da en la definicin del cuerpo de
la tabla, en este caso haciendo uso de la propiedad
data-bind le estamos asignamos la propiedad
personList, y como usamos la funcin foreach
entonces Knockout itera sobre cada elemento del
array, luego en cada elemento td usando nuevamente
la propiedad data-bind a la propiedad text le
relacionamos la propiedad de la cual va a mostrar su
valor.
-
Id:
Name:
Last name:
Twitter:
Para los input, en el data-bind a la
propiedad value le asignamos alguna de las
propiedades del ViewModel, para los
botones igualmente con data-bind al evento
clic le relacionamos una funcin del
ViewModel.
El cambio ms importante en esta sencilla implementacin de Knockout, es que si revisamos de nuevo el archivo person.js NO se tiene ninguna dependencia ni referencia al DOM, lo cual ofrece una mejor estructura de nuestra aplicacin y la puede hacer ms mantenible y extensible