Sie sind auf Seite 1von 34

Developing ASP.

NET MVC 4 Web Applications


Presented by Nataniel Marcial

Introduccion
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!

Training Outline
Mi primer proyecto Creando un CRUD, trabajando con verbos HTTP Consumiendo el servicio Implementando Knockoutjs.

Mi primer proyecto
Lo primero es crear una nueva aplicacin de tipo ASP.NET Web Application.

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. 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.

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) { } }

Creando un CRUD, trabajando con verbos HTTP


Implementar fcilmente un CRUD (create, read, update y delete

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 using using using

System; System.Collections.Generic; System.Linq; 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 using using using using System; System.Collections.Generic; System.Data.Entity; System.Linq; 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 using using using using using MvcApplication1.Models; System; System.Collections.Generic; System.Data.Entity; System.Linq; System.Web;

namespace MvcApplication1.App_Start { public class PersonDBInitializer : DropCreateDatabaseAlways<PersonDBContext> { protected override void Seed(PersonDBContext context) { var persons = new List<Person> { 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# <add name="PersonDBContext connectionString="Data Source=.;Initial Catalog=test;Integrated Security=True" providerName="System.Data.SqlClient" />

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:
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.

Accin GetPerson GetPerson (Int32 id) PutPerson (Int32 id, Person person) PostPerson(Person person) DeletePerson(Int32 id)

Verbo Http Get Get Put Post Delete

Funcionalidad Obtener todos los elementos Obtener un elemento por id Actualizar elemento por su id Insetar un nuevo elemento Eliminar elemento

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:

<label>Id:</label>

<input type="text" id="txtIdSearch" /> <input type="button" id="btnSearch" value="Search" /> </li> <li> <div id="body"> <label>Name:</label> <section class="content-wrapper main-content clear-fix"> <input type="text" id="txtName" /> <div class="hero-unit"> </li> <h2>Get All</h2> <li> <div> <label>Last name:</label> <table id="tblList" class="table table-bordered table<input type="text" id="txtLastName" /> hover"> </li> <thead> <li> <tr> <label>Twitter:</label> <th>Name</th> <input type="text" id="txtTwitter" /> <th>Last Name</th> </li> <th>Twitter</th> <li> </tr> <input type="button" id="btnDelete" value="Delete" /> </thead> <input type="button" id="btnUpdate" value="Update" /> <tbody></tbody> </li> </table> </ul> </div> </div> <h2>Get one</h2> </div> <div> @section scripts <ul> { <li> <script type="text/javascript" src="@Url.Content("/Scripts/app/person.js")"></script> } </section> </div>

Listo, ya tenemos el HTML listo, ahora a implementar cada funcionalidad: Obtener todos
$(document).on("ready", function () { GetAll(); }) //Get all persons function GetAll() { var item = ""; $('#tblList tbody').html(''); $.getJSON('/api/person', function (data) { $.each(data, function (key, value) { item += "<tr><td>" + value.Name + "</td><td>" + value.LastName + "</td><td>" + value.Twitter + "</td></tr>"; }); $('#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 id function 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(); }); };

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 form function ClearForm() { $('#txtIdSearch').val(''); $('#txtName').val(''); $('#txtLastName').val(''); $('#txtTwitter').val(''); }

Y al botn de buscar un manejador para el evento clic:


$(document).on("ready", function () { $('#btnSearch').on('click', function () { GetPersonById($('#txtIdSearch').val()); }) GetAll(); })

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 id function 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 person function 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 person function 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'); } } }); }

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. 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)); })

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 /// <reference path="../knockout-2.3.0.debug.js" /> Luego definimos el modelo: 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(); }
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 () { self.createPerson = function () { var url = '/api/person/' + self.id(); var url = '/api/person/'; $.ajax({ $.ajax({ url: url, url: url, type: 'PUT', type: 'POST', data: ko.toJSON(self), data: ko.toJSON(self), contentType: "application/json;chartset=utf-8", contentType: "application/json;chartset=utf-8", statusCode: { statusCode: { 200: function () { 201: function () { self.getAll(); self.getAll(); self.clearForm(); self.clearForm(); alert('Person with id= ' + self.id() + ' alert('Person was created'); was updated'); }, }, 400: function () { 404: function () { self.clearForm(); self.clearForm(); alert('Error'); alert('Person with id= ' + self.id() + ' } was not found'); } }, }); } 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 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: $(document).on("ready", function () { var personvm = new PersonViewModel(); ko.applyBindings(personvm); personvm.getAll(); })

Paso 2: Definir los bindings en el HTML


<table id="" class="table table-bordered table-hover"> <thead> <tr> <th>Name</th> <th>Last Name</th> <th>Twitter</th> </tr> </thead> <tbody data-bind="foreach: personList"> <tr> <td data-bind="text: Name"></td> <td data-bind="text: LastName"></td> <td data-bind="text: Twitter"></td> </tr> </tbody> </table>

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.

<ul> <li> <label>Id:</label> <input type="text" id="" data-bind="value: id" /> <input type="button" id="" value="Search" data-bind="click: </li> <li> <label>Name:</label> <input type="text" id="" data-bind="value: name" /> </li> <li> <label>Last name:</label> <input type="text" id="" data-bind="value: lastname" /> </li> <li> <label>Twitter:</label> <input type="text" id="" data-bind="value: twitter" /> </li> <li> <input type="button" id="" value="Create" data-bind="click: <input type="button" id="" value="Delete" data-bind="click: <input type="button" id="" value="Update" data-bind="click: </li> </ul>

getPersonById" />

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.

createPerson" /> deletePersonById" /> updatePerson" />

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

Das könnte Ihnen auch gefallen