Tales from under the Mountain

ASP.NET MVC Framework i REST - GET implementacija

Metodi kontrolera

Dakle, kako što smo rekli, MVC framework radi na principu jedne klase koja predstavlja kontroler, i metoda te klase koji predstavljaju akcije kontrolera. Naravno, nije svaki metod automatski akcija, samo metodi koji imaju public nivi pristupa (ovo vam omogućava da imate private metode za delove koda koje često koristite, itd.) U poslednjih nekoliko revizija framework-a, tim je dodavao dosta atributa koji nam daju veću kontrolu nad izvršavanjem tih akcija. Jedan od tih koji ćemo danas koristiti je AcceptVerbs atribut koji kao parametzra prima enumeraciju HttpVerbs ili običan string sa vrednošću nekog HTTP metoda. Kao što mu samo ime kaže, on služi da se odredi koji će se HTTP zahtev rutirati do akcije. Ako imamo HttpVerbs.Get vrednost prosleđenu kao parametar AcceptVerb atributu, akcija sa tim atributom će se izvršiti samo na GET HTTP zahtev, ali ne i na POST. Ukoliko nemamo ovaj atribut, onda će se akcija izvršiti na bilo koji HTTP zahtev.

Naravno, postojanje ovog atributa nam izuzetno pomaže kod pravljenja REST servisa sa MVC framework-om.

GET metod

U ovom postu ću pokazati jedan metod, GetCharacters() koji vraća kolekciju likova iiz anše baze Star Trek likova. Oba metoda će odgovarati samo na GET poziv. Jedan će vratiti XML reprezentaciju resursa (kolekcije), dok će drugi vratiti JSON reprezentaciju resursa.

Dakle, kod za sada izgleda veoma prosto:

   1: [AcceptVerbs(HttpVerbs.Get)]
   2: public ActionResult GetCharacters() {
   3:     var r = from c in _db.Characters
   4:             select c;
   5:     return View(r);
   6: }

Razlike

Osnovna razlika između rada sa WCF-om za REST servise i MVC framework-om postaje jasna odmah. WCF ima mehanizme za automatsku serijalizaciju tipova u XML i JSON, dok MVC ima samo JSON pomoću JsonResult tipa koji može da se vrati umesto ActionResult ili ViewResult tipa iz akcije/metoda. Za XML serijalizaciju ćemo morati sami da se "pomučimo".

Druga stvar su ULR-ovi. MVC framework je doneo ideju routing-a, kao što sam objasnio u prethodnom postu, što znači da putanje stavljamo u global.asax fajl, a ne definišemo za svaki metod ponaosob putanu kroz UriTemplate atribute kao kod WCF-a.

Reprezentacije

Kao što smo već rekli, imaćemo dve osnovne reprezentacije resursa. Prva je XML, i koristićemo format podataka koji je identičan onom koji smo već koristili za WCF servis. Ono što je potrebno da uradimo ručno, jeste serijalizacija naših obojekata u XML format. Drugi format reprezentacije će  biti JSON, JavaScript Serialized Object Notation. Ovaj format je idealan za konzumaciju putem AJAX klijenata.

Kao što se može primetiti iz gornjeg kratkog code snippet-a, svaki metod vraca po default-u tip ActionResult koji je uveden radi lakšeg testiranja. Postoji nekoliko vrsta result tipova, zavisno od toga šta želimo da uradimo u metodu. Samim tim, postoji nekoliko načina da prikažemo, odnosno vratimo podatke iz našeg kontrolera/metoda do klijenta.

Postoji nekoliko načina da se vrati rezultat. Prvi je da se vrati na uobičajen način view, ali da view ne bude aspx strana, već XML fajl u kojem ćemo generisati podatke kroz iteraciju nad našom LINQ kolekcijom. Drugi način je da vratimo samo XmlDocument ili XElement tip sa pravilno podešenim Content-Type header-om; MVC framework će automatski obaviti ovaj tip u ContentResult koji služi da se vrati ili čisti tekst ili bilo šta drugo što ne spada u ostale tipove rezultata. Više o rezultatima i njihovim tipovima možete da nađete na http://www.asp.net/learn/mvc/tutorial-03-cs.aspx. Treća opcija, koja je i "najčistija", je da nasledimo ActionResult klasu i da u našoj implementaciji obavimo serijalizaciju. Treći način možete da vidite podrobnije opisan na blogu Omara Al Zabira.

Nasleđivanje ActionResult klase je i jedini način da napravite samo jedan metod koji će na osnovu HTTP header-a da vraća određenu reprezentaciju. Omar koristi “Content-Type” header u svojoj result klasi da bi odlučio koju reprezentaciju da vrati (što baš i nije najbolji način, pravilnije je koristiti “Accept” header putem kojeg klijent obaveštava server koje sve MIME tipove može da obradi). Pošto me ovde interesuje samo da pokažem LO-REST scenarije uz korišćenje MVC framework-a, onda ću koristiti nekoliko metoda i, naravno, LINQ to XML.

 Reprezentacija – JSON

Prvo ćemo napraviti JSON reprezentaciju, pošto je lakša i jednostavnija. Gore dat metod ćemo preraditi na sledeći način:

 

   1: [AcceptVerbs(HttpVerbs.Get)]
   2: [ActionName("Characters")]
   3: public JsonResult GetCharacters() {
   4:     CharactersDataContext db = new CharactersDataContext();
   5:     var r = db.Characters.Select(c => new { c.ID, c.Name, c.Rank, c.Service }).ToList();
   6:     return Json(r);
   7: }

Dakle, kao što vidimo, umesto ActionResult vraćamo JsonResult. Pošto nam dati JSON serilizaer pravi problema sa “circular reference detected” exception-om, uradićemo malu projekciju u anonimni tip koji ima sve što nam je potrebno, i sve ćemo to zapakovati u listu. Potom ćemo istu proslediti Json() metodu. I kao jednu ispomoć, iskoristićemo atribut “ActionName”, da bismo dali bolje ime našoj metodi.

Ono što ćemo dobiti nazad je JSON objekat koji u sebi ima listu sa našim anonimnim tipom. Šta ćemo dalje raditi sa ovim ostaje mašti korisnika, kako bih rekao. jQuery ima veoma koristan .ajax() metod koji možete da koristite da biste pozvali ovaj metod, ili pak da to radite ručno preko eval() f-je u JavaScript-u. Kako god da se odlučite, ovo je način da vratite JSON reprezentaciju.

Reprezentacija – XML

Kako bi metod izgledao sa XML reprezentacijom?

   1: [AcceptVerbs(HttpVerbs.Get)]
   2: [ActionName("CharactersXml")]
   3: public XElement GetCharactersXml(){
   4:     CharactersDataContext db = new CharactersDataContext();
   5:     XElement r = new XElement("characters",
   6:                 from c in db.Characters
   7:                 select new XElement("character",new XElement("ID",c.ID),new XElement("Name",c.Name),
   8:                     new XElement("Rank",c.Rank),new XElement("Service",c.Service)));
   9:     this.ControllerContext.HttpContext.Response.ContentType = "application/xml";
  10:     return r;
  11: }

Nekoliko stvari se promenilo. Prvo, metod vraća XElement tip, koji predstavlja našu reprezentaciju. Drugo, kod za kreiranje reprezentacije je malo komplikovaniji jer koristimo kobimaciju LINQ to SQL i LINQ to XML API-ja. Poslednja promena je linija 9 u gornjem kodu, koja koristi, kao što i liči, HttpContext u kome se izvršava trenutni kontroler da bi postavila Content-Type. Ovo sam uradio samo da bih mogao da vidim XML kod lepo sređen u IE-u i FF-u, a ne kao tekst.

Dobijamo ovaj rezultat:

image

 

 Kratak zaključak

MVC framework nam omogućava da veoma lako i brzo napravimo LO-REST servise. Ideja URL Routing-a nam omogućava da dobijemo “čiste”  URL-ove koji pokazuju na naše resurse, dok nam ideja Action Result klasa daje mogućnost da vratimo različite reprezentacije.

U sledećem nastavku ćemo pogledati i ostale metode koji su nam potrebni (ako mi vreme provedeno sa REST starter kit-om ne bude oduzelo previše vremena i pameti, pa počnem o tome da pišem :)).

Out.

B.D.

Posted: Oct 22 2008, 12:06 AM by blackdwarf | with 4 comment(s)
Filed under: , ,

Comments

Marko said:

upravo ono sto mi treba, hvala :)

imas li ideju kako bi se vrsila autorizacija zahteva?

pozdrav

# April 25, 2009 9:12 AM

blackdwarf said:

U "regularnom" MVC-u preko Authorize atributa koji i ovde moze da pomogne. Posto se isti kaci na Membership API iz ASP.NET-a 2.0. Doduse, ako se pravi REST servis, bilo bi potrebno malo "hakovanja" AccountsController-a da vraca HTTP kodove umesto da redirektuje na login form, ali to nije preterano tesko.

Alternativno, bilo bi moguce proveravati HTTP zahtev u svakom metodu i tu videti da li je browser poslao kredencijale i zatim vrsiti autorizaciju.

# April 26, 2009 7:53 AM

Marko said:

tako sam i mislio, hvala puno

inace, kombinacija jquery.ajax metode i mvc-a koji vraca json rezultate radi kao sat, obavezno probati :)

pozdrav svima

# April 27, 2009 1:38 PM

blackdwarf said:

Ooo, da, veoma mocna stvar. Takodje je jako dobro probati i Ajax helper-e, ima nekih korisnih stvari za koje je inace potrebno "rucno" pisati kod u jQuery. "Rucno" kazem, jer mi se nekako cini toliko lakim bilo sta to radim u toj bilbioteci da to zaista skoro da postaje samo slaganje kockica. :))

# April 27, 2009 9:38 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Are you a human?