Developing ASP.net MVC 4 Web Applications

34
Presented by Nataniel Marcial Developing ASP.NET MVC 4 Web Applications

description

primeros pasos para crear una aplicacion web utilizando ajax mvc4 jscript y knockout.js

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