Servicii Rest Pentru Aplicatii Mobile
Cuprins
TOC \o 2-3 \t "Heading, 4"
CAP. 1 – FUNDAMENTAREA TEORETICA PAGEREF _Toc \h 3
Introducere PAGEREF _Toc1 \h 3
Modelul de maturitate REST al lui Richardson PAGEREF _Toc2 \h 5
ASP.NET MVC 4 si WebApi PAGEREF _Toc3 \h 7
Interoperabilitatea intre JSON, XML si REST PAGEREF _Toc4 \h 10
CAP. 2 – SPECIFICATII SI ARHITECTURA PAGEREF _Toc5 \h 14
Descrierea aplicației PAGEREF _Toc6 \h 14
2.2 funcțiile sistemului PAGEREF _Toc7 \h 14
2.1 schema bloc a sistemului PAGEREF _Toc8 \h 15
2.3 arhitectura generală PAGEREF _Toc9 \h 17
CAP. 2b – Proiectarea Serviciului REST PAGEREF _Toc10 \h 19
2.4 Structura serviciului PAGEREF _Toc11 \h 19
NIVEL 0 PAGEREF _Toc12 \h 19
NIVEL 1: URI și resurse PAGEREF _Toc13 \h 20
NIVEL 2: Verbe HTTP PAGEREF _Toc14 \h 20
NIVEL3: HATEOAS PAGEREF _Toc15 \h 22
2.5 Modelarea tabelelor de resurse PAGEREF _Toc16 \h 23
Linkuri Hypermedia PAGEREF _Toc17 \h 24
3.1.3 Urmărirea modelului RMM PAGEREF _Toc18 \h 24
OData PAGEREF _Toc19 \h 25
2.6 interfața cu utilizatorul (doar pe aplicatii mobile) PAGEREF _Toc20 \h 28
Securizarea serviciului PAGEREF _Toc21 \h 29
Automatic Error Logging PAGEREF _Toc22 \h 29
CAP. 3 IMPLEMENTAREA EFECTIVĂ PAGEREF _Toc23 \h 31
3.1 Controllers, Dependencies, and Managing the Database Unit of Work PAGEREF _Toc24 \h 31
3.5 Alegerea componentelor de arhitectură PAGEREF _Toc25 \h 31
CAP. 4 Testarea aplicației – Utilizarea sistemului și rezultate experimentale PAGEREF _Toc26 \h 35
Using Fiddler PAGEREF _Toc27 \h 35
CAP. 5 Concluzii PAGEREF _Toc28 \h 37
3.6 documentație și coduri sursă -în anexe). PAGEREF _Toc29 \h 38
Anexa 1: Cod sursa (selecții) PAGEREF _Toc30 \h 39
Automatic Error Logging PAGEREF _Toc31 \h 39
Anexa 2: Capturi de ecran aplicații mobile PAGEREF _Toc32 \h 42
Bibliografie PAGEREF _Toc33 \h 43
CAP. 1 – FUNDAMENTAREA TEORETICA
Introducere
Odată cu dezvoltarea internetului, am asistat la o explozie tehnologică în domeniul IT, am fost martori la proliferarea dispozitivelor mobile, la revoluția tabletelor si a telefoanelor inteligente și ne îndreptăm spre IoT (Internet of Things) o lume in care aproape orice dispozitiv va fi conectat la rețeaua globală. În acest context se impune alegerea celor mai potrivite tehnologii software care să ne ajute la întâmpinarea cu succes a provocărilor care bat la ușă.
În cea mai mare parte a timpului, în perioada creșterii internetului din ultimii douăzeci de ani, site-urile și paginile web s-au bazat pe cod pe partea de server pentru orice altceva decât simpla manipulare a limbajului de marcare HTML. Dar, mai recent, diferite unelte și framework-uri pe baza de AJAX — cum ar fi JavaScript, jQuery, HTML5 și câteva manipulări inteligente de cod CSS — au crescut cererea de servicii care să fie mai puțin realizate pentru aplicații complexe în mediul enterprise care să comunice între ele pentru anumite nevoi specifice; acum majoritatea paginilor web au nevoie să primească și să transmită cantități mici de date. În aceste cazuri, soluția la îndemână și evidentă este comunicarea cu un serviciu peste protocolul, din moment ce site-urile web în sine sunt aplicații HTTP. Mai mult, opțiunile de securitate disponibile într-un browser sunt mult mai simple decât cele ale unei aplicații de sine stătătoare, eliminându-se astfel folosirea unor specificațiile complexe și greoaie de securitate ale unui standard cum ar fi SOAP.
Pe lângă protocolul mai simplu de comunicație și nevoile de securitate, paginile web de obicei comunică cu alte aplicații și servicii folosind mesaje bazate pe text în loc de mesaje binare, astfel un serviciu nu trebuie să suporte decât serializarea de tip XML sau JSON.
Pe lângă aplicațiile web, telefoanele inteligente și tabletele au creat o cerere uriașă pentru servicii folosite de aplicațiile care au resurse mai mici decât calculatoarele desktop. Aceste servicii sunt similare cu cele folosite de site-urile web bazate pe AJAX: comunică de obicei prin HTTP, trimit și primesc cantități mici de date bazate pe text, modelele lor de securitate tind să aibă o abordare minimalistă pentru a putea furniza o experiență mai bună pentru utilizatorul final (de exemplu se încearcă realizarea de aplicații care necesită cât mai puține configurări din partea utilizatorului). De asemenea implementarea acestor servicii încurajează refolosirea lor pe diferitele platforme mobile, fără modificări pe partea de server.
În concluzie, există în acest moment cererea pentru framework-uri de servicii, care tocmai prin design-ul lor, să furnizeze exact ce au nevoie acestor servicii simple HTTP bazate pe text.
„In teza sa de doctorat, Architectural Styles and the Design of Network-based Software Architectures, Roy Thomas Fielding, unul dintre principalii autori ai specificațiilor HTPP, a descris REST (Representational State Transfer) ca un principiu cheie al arhitecturii World Wide Web și a primit o atenție foarte mare asupra sa. Acum oamenii privesc REST ca o alternativă la alte specificații cum ar fi SOAP.”. REST a fost realizat în scopul de a beneficia într-o mai mare măsură de standardele și tehnologiile din HTTP decât SOAP. De exemplu, în loc de metode SOAP arbitrare, programatorii de API-uri REST sunt încurajați să folosească doar verbe HTTP:
GET
POST
PUT
DELETE
REST este de asemenea axat pe resurse; API-urile RESTful folosesc verbe HTTP pentru a acționa asupra sau a obține informații despre resurse. Resursele corespund substantivelor din REST (cum ar fi Utilizatori, Clienti și Comenzi în aplicația noastră). Astfel avem verbe care acționează asupra substantivelor, sau altfel spus, avem acțiuni asupra resurselor.
În plus, REST profită de avantajele altor aspecte ale sistemelor HTTP, cum ar fi:
Caching
Securitate
Statelessness
Network layering (cu diferite nivele de firewall-uri, gateway-uri si sisteme de protecție între client și server)
Modelul de maturitate REST al lui Richardson
În 2008, Leonard Richardson a creat un model de maturitate pentru REST, în principiu o hartă pe care programatorii să o folosească în hățișul din ce in ce mai des la creșterii continue a nivelelor de conformitate cerute de o anumită definiție, arhitectură sau metodologie.
Fig. 1 Modelul de maturitate REST al lui Leonard Richardson (MMR)
„Modelul de maturitate REST al lui Leonard Richardson (MMR) le propune dezvoltatorilor de API-uri același tip de plan de evoluție pentru construirea serviciilor web RESTful, la nivelul 0 modelul pornește cu o interfață în stil RPC și progresează încă trei nivele, până ajungem un design al interfeței API care, cel puțin după Roy Fielding, este o precondiție pentru un serviciu RESTful; nu putem pretinde că avem un serviciu RESTful dacă ne oprim la nivelele 0,1 sau 2 ale modelului RMM; pe de o altă parte se poate greși la orice nivel, astfel încât chiar dacă credem că am ajuns la nivelul 3 al modelului, să nu avem un serviciu RESTful.”
Descrierea modelului de maturitate REST al lui Leonard Richardson:
Nivelul 0 – XML-RPC și SOAP: API-ul seamănă cu majoritatea serviciilor SOAP, adică interfața este caracterizată de faptul că avem o singură URI și o singură metodă HTTP sau verb
Nivelul 1: la acest nivel introducem resursele. Acum în loc să facem toate cererile către un singur punct de contact al serviciului, începem să vorbim despre resurse individuale;
Nivelul 2: la acest nivel folosim verbele cât de aproape modul în care se folosește în HTTP;
Nivelul 3: în nivelul final apare ceea ce este denumit deseori sub acronimul HATEOAS (Hypertext As The Engine Of Application State).
În încheiere prezentăm “regulile” lui Roy T. Fielding pentru programatorii de API-uri REST publicate pe blogul său :
„Dezvoltatori de API-uri, vă rog să luați aminte la următoarele reguli înainte să vă denumiți creația un API REST:
Un API REST nu trebuie să fie dependent de nici un protocol de comunicație, deși maparea cu succes pe un protocol dat poate fi necesară în contextul disponibilității meta-datelor, alegerea metodelor, etc. În general, orice element al unui protocol care folosește un URI pentru identificare trebuie să permite folosirea oricărei scheme URI să fie folosită de dragul acelei identificări. [Eșecul aici implică faptul că identificarea nu este separată de interacțiune.]
Un API REST nu ar trebui să conțină nici o schimbare în protocolul de comunicație, în afară de completarea sau reglarea unor părți prea puțin documentate ale protocoalelor de comunicație, cum ar fi metoda PATCH din HTTP sau câmpul Link header. Soluțiile temporare pentru implementări defectuoase (cum ar fi în cazul unor browsere care „cred” ca HTML definește setul de metode al protocolului HTPP) ar trebui definite separat, sau cel puțin în anexe, cu speranța că soluția temporară va deveni în cele din urmă învechită. [Eșecul aici implică faptul că interfețele de resurse sunt specifice obiect, nu generice.]
Un API REST ar trebui să definească foarte bine tipurile de medii folosite pentru reprezentarea resurselor și schimbarea stărilor aplicației și să definească numele relațiilor extinse și/sau marcajelor hypertext pentru tipurile standard de medii. Orice efort consumat pentru descrierea metodelor de folosit pentru anumite URI de interes ar trebui să fie definit în întregime în limitele regulilor de procesare pentru un anumit tip de mediu (și în anumite cazuri, deja definite de tipul existent de mediu). [Eșecul aici implică faptul că informația out-of-band conduce interacțiunea în loc de hypertext]
Un API REST nu trebuie să definească nume de resurse fixe sau ierarhii (o cuplare evidentă client/server). Serverele trebuie să aibă libertatea să își controleze spațiul de nume (namespace). În schimb, permiteți serverelor să trimită instrucțiuni clienților despre modul de construire a unei URI potrivite, așa cum se face în formularele HTML și în șabloanele URI, prin definirea acelor instrucțiuni din tipul de mediu și relațiile între legături. [Eșecul aici implică faptul că un client presupune o anumită structură a resurselor datorită informației out-of-band, cum ar fi un standard specific domeniului, care este echivalentul cuplării funcționale din modelul RPC].
Un API REST ar trebui să poată fi accesat inițial fără o cunoaștere prealabilă dincolo de URI-ul inițial (bookmark) și a setului de tipuri standardizat de medii (presupus cunoscut de orice client care ar putea folosi API-ul). De aici încolo toate tranzițiile de stare ale aplicației trebuie să fie dictate de selecția de către client dintre opțiunile furnizate de server existente în reprezentările primite de la server sau presupus a fi implicite de manipularea de către utilizator a acestor reprezentări. Tranzițiile trebuie să fie determinate (sau limitate de) cunoașterea de către client a tipului de mediu și a mecanismului de comunicare a resurselor, ambele putând fi îmbunătățite „din zbor” (de exemplu prin cod-la-comandă). [Eșecul aici implică faptul că informația out-of-band conduce interacțiunea în loc de hypertext.]
Modelul de maturitate REST și lucrările publicate Roy Fielding – furnizează trei atribute legate de web distincte ale unui API care ne va ajuta să realizăm servicii RESTful cu protocolul HTTP:
Identificatorii uniformi de resurse (URI) unici ai resurselor sunt unici
Folosirea consistentă a verbelor HTTP
HATEOAS (“Hypermedia As The Engine Of Application State” ) –folosirea hypermedia ca și motor de schimbare al stărilor aplicației
ASP.NET MVC 4 si WebApi
În continuare vom analiza implementarea REST cu ajutorul framework-ului Web Api 2 de la Microsoft, care este inclus în ASP.NET MVC 4.
Deși putem folosi WCF pentru a crea servicii de această natura, WCF nu este configurat de la început pentru acest mod de lucru; din păcate posibilitățile, prea extinse și complicate de a configura și extinde WCF, face posibil faptul de a greși în logica aplicației, încă de la faza de design, cu efecte costisitoare de-a lungul realizării serviciului.
Tocmai la acest aspect se impuprin cod-la-comandă). [Eșecul aici implică faptul că informația out-of-band conduce interacțiunea în loc de hypertext.]
Modelul de maturitate REST și lucrările publicate Roy Fielding – furnizează trei atribute legate de web distincte ale unui API care ne va ajuta să realizăm servicii RESTful cu protocolul HTTP:
Identificatorii uniformi de resurse (URI) unici ai resurselor sunt unici
Folosirea consistentă a verbelor HTTP
HATEOAS (“Hypermedia As The Engine Of Application State” ) –folosirea hypermedia ca și motor de schimbare al stărilor aplicației
ASP.NET MVC 4 si WebApi
În continuare vom analiza implementarea REST cu ajutorul framework-ului Web Api 2 de la Microsoft, care este inclus în ASP.NET MVC 4.
Deși putem folosi WCF pentru a crea servicii de această natura, WCF nu este configurat de la început pentru acest mod de lucru; din păcate posibilitățile, prea extinse și complicate de a configura și extinde WCF, face posibil faptul de a greși în logica aplicației, încă de la faza de design, cu efecte costisitoare de-a lungul realizării serviciului.
Tocmai la acest aspect se impune studierea altor framework-ului Web Api .
În anii care au urmat lansării versiunii inițiale a .NET Framework, Microsoft a propus o mare varietate de soluții pentru realizarea aplicațiilor orientate spre servicii. Încă de la prima versiune de .NET Framework, programatorii puteau crea servicii web ASP.NET ASMX bazate pe XML care permiteau conectarea altor clienți .NET sau chiar a altor clienți care nu se bazau pe .NET.
Aceste servicii web implementau diferite versiuni de SOAP, dar erau disponibile doar pentru folosirea peste HTTP.
Pe lângă servicii web, versiunea 1.0 a framework-ului .NET oferea suport pentru Remoting; acest lucru a permis programatorilor să scrie servicii care nu erau neapărat legate de protocolul HTTP. Similar serviciilor web bazate pe ASMX, .NET Remoting în esență punea la dispoziție activarea obiect (object activation) și contextul sesiunii pentru apelurile de metode inițiate de client. Apelantul folosește un obiect proxy ca să invoce metode, iar runtime-ul .NET se ocupă de operațiunile de serializare și marshaling ale datelor între obiectul proxy și obiectul serviciu de pe server.
Spre sfârșitul anului 2006, Microsoft a lansat .NET versiunea 3.0, care includea Windows Communication Foundation (WCF). WCF nu doar a înlocuit serviciile web ASMX și .NET Remoting, dar a făcut un pas uriaș înainte în ceea ce privește flexibilitatea, configurabilitatea, extensibilitatea și suportul pentru standarde mai noi de securitate și SOAP.
De exemplu, cu WCF, un programator poate scrie un serviciu non-HTTP care suportă autentificarea cu tokeni service SAML și să il găzduiască într-un serviciu Windows construit la comandă. Acestea și alte facilități au lărgit considerabil posibilitățile în care .NET poate fi utilizat pentru a construi aplicații orientate spre servicii.
Dacă avem nevoie să realizăm comunicarea între două aplicații, indiferent dacă sunt instalate în același data-center sau la kilometri distanță, atunci cu WCF se poate face acest lucru cu siguranță. Iar dacă nu ne ajung funcțiile standard ale WCF, datorită modelul eficient de extensibilitate se poate realiza aproape orice funcționalitate necesară.
În ciuda existenței WCF, aici ne vom despărți puțin de această cale flexibilă și capabilă a evoluției serviciilor web pentru a studia o soluție mai simplă și dedicată unui set mai mic de scenarii specifice.
Avantajele folosirii ASP.NET Web Api
Odată ce am stabilit că, în anumite cazuri, nu avem nevoie de toate capabilitățile extinse pe care le pune la dispoziție WCF, putem să luăm în considerație folosirea unui framework cum ar fi ASP.NET Web Api, care odată cu versiunea 2 propune și mai multe funcții prin configurația standard, fără să sacrifice din simplitate sau focusul asupra comunicației serviciilor prin HTTP. În continuare vom arunca o privire asupra acestora:
Web Api: Web Api din ASP.NET MVC 4 ajuns la versiunea a doua.
Configurație: La fel ca și în cazul realizării unui web site, nu trebuie făcute multe configurări pentru a porni un serviciu bazat pe MVC. Nu există conceptele de endpoint și nici contractele, în comparație cu un serviciu WCF, fiind destul de simplu. Mai avem nevoie de un URL de tip REST, un set de argumente de intrare și un mesaj de răspuns JSON sau XML.
REST în mod implicit: ASP.NET MVC 4 și Web API ne oferă cam tot ce avem nevoie pentru a scrie servicii REST, cu constrângerile necesare pentru aderarea la model; acest lucru se datorează în mare măsură funcției de rute pusă la dispoziție de framework-ul MVC. Spre deosebire de WCF, unde serviciul este de fapt o adresă către un fișier fizic, adresarea serviciului cu MVC se face cu rute către metodele controller-ului în stilul REST.
Abstractizare cu rute: Întrucâtva similar cu interfețele serviciilor și implementarea lor în WCF, rutele permit programatorilor de servicii MVC să dezvolte un strat de abstracție între ceea ce văd apelanții și implementarea efectivă; cu alte cuvinte, putem mapa orice URL către orice metodă a controllerului. Când semnătura API (URL-UL REST) nu e hard-codată pe o anume interfață, clasă, sau fișier.svc, putem actualiza implementarea noastră a acelei metodă a API-ului, atât timp cât URL-ul pentru acea metodă rămâne valid. Un exemplu clasic al folosirii URL-urilor pentru gestionarea schimbărilor în implementare este cazul diferitelor versiuni ale aceluiași serviciu: prin crearea unei noi rute cu “v2” inclus în URL, putem crea o mapare arbitrară între implementare și o schemă de versionare sau chiar un set de versiuni care vor exista cândva în viitor. Astfel, putem lua un set de controllere (cu metodele lor cu tot) și într-un moment viitor să hotărâm să le facem să aparțină unei versiuni 2 a API-ului nostru..
Activare controller-ului: În toate implementările (ASMX – Servicii Web XML, WCF, sau MVC, conceptul de activare a serviciului este prezent. Deoarece marea majoritate a apelurilor către un serviciu sunt cereri noi, runtime-ul ASP.NET sau WCF activează o nouă instanță a clasei serviciului pentru fiecare cerere nouă, similar cu instanțierea obiectelor în programarea orientată pe obiect. ASP.NET MVC furnizează un mecanism simplu pentru pre-procesare și post-procesare și anume filtre acțiune. Aceste filtre sunt de fapt clase care conțin câteva metode ce permit rularea de cod înainte și după ce metodele controller-ului sunt invocate; filtrele sunt prezentate sub formă de atribute și sunt configurate pe o metodă anume sau la nivel global pentru toate metodele.
Interoperabilitatea intre JSON, XML si REST
REST se bazează doar pe standardele HTTP existente, fiind interoperabil între toate platformele care pot genera cereri HTTP: calculatoare, telefoane inteligente, tablete, sisteme de supraveghere, ceasuri, echipamente electrocasnice; orice dispozitiv care poate genera o cerere HTTP către un URL, poate lucra cu REST.
„Același lucru se aplica si la JSON si la datele pur XML. În comparație cu SOAP, aceste tehnologii au cerințe mici în ceea ce privește formatarea corectă sau înțelegerea specificațiilor mesajului. Din punct de vedere tehnic, SOAP este un protocol bazat pe XML; dar construirea unui mesaj SOAP valid (care include envelope, header și body) este mai complicată decât reprezentarea datelor în XML. Același lucru se poate spune despre parsarea XML sau JSOP față de mesaje complete (și complexe) SOAP, ceea ce face ca dezvoltatorii să aibă nevoie de librării SOAP pentru a construi și parsa mesaje. Această cerință pentru librării limitează posibilitatea folosirii SOAP pe dispozitive mici sau specializate”.
Unul dintre principalele avantaje ale JSON, în afară de formatarea cea mai simplă posibilă, este că, pentru un pachet de date dat, ocupă mai puțin spațiu decât dacă ar fi reprezentat XML/SOAP. Avem un motiv în plus să folosim JSON pentru dispozitive conectate ocazional, a celor cu putere mică, ca și pentru folosirea pentru transmiterea datelor prin rețele celulare. Prin aceasta nu spunem că SOAP nu este o tehnologie bună sau că nu își mai găsește locul în zilele noastre; dimpotrivă, capabilitățile SOAP merg mult mai departe decât cele ale REST și JSON.
Multe dintre aceste capabilități sunt definite de specificațiile WS-* . Acestea se ocupă de alte nevoi, de mesaje mult mai complexe, cum are securitatea mesajelor, tranzacții, descoperirea de servicii, publicarea meta-datelor, rutare sau federații de identitate. Niciuna dintre acestea nu este posibilă cu REST datorită faptul că au nevoie de capabilități în afara protocolului HTTP.
Totuși nici unul dintre aceste aspecte și avantaje ale folosirii ASP.NET MVC discutate până acum nu au de fapt nimic de-a face cu noul MVC4 Web API 2. De fapt, framework-ul MVC Framework în sine, fără Web API pune la dispoziție un framework simplu dar puternic suficient pentru a crea servicii bazate pe REST.
Aceste fiind spuse, noul Web API disponibil în MVC4 are multe de oferit în plus, aduce o întreagă panoplie de funcționalități care fac și mai ușoară dezvoltarea de servicii REST. În continuare vom vedea câteva dintre acestea:
Acțiuni CRUD bazate pe convenții: acțiunile HTTP (cum ar fi GET sau POST) sunt mapate automat pe metodele controller (denumite și acțiuni controller) folosind numele lor. De exemplu pentru un controller cu numele Produse, o cerere GET cum ar fi /api/produse va invoca în mod automat o metoda numita Get a controller-ului. Și mai mult, Web Api potrivește în mod automat numărul de argumente primite în URL cu o metodă controler potrivită. Prin urmare, un URL de forma /api/produse/32 va invoca în mod automat metoda Get(long id). Aceeași „automatizare” se aplică și în cazul apelurilor POST, PUT și DELETE;
Negociere de conținut inclusă: În MVC, metodele controller care returnează JSON or XML trebuie să fie hard-codate pentru a returna exact unul dintre tipurile conținut necesare cu Web Api, metoda controller trebuie să întoarcă doar valoarea neprelucrată, iar această valoare va fi convertită către JSON sau XML, în funcție de cererea apelantului. Apelantul pur și simplu folosește un header HTTP de tip Accept sau Content pentru a specifica tipul de conținut dorit a se returna pentru datele primite și Web Api se asigură că valorile întoarse sunt formatate în mod corespunzător. În loc să returneze în obiect de tipul JsonResult, se va returna obiectul date (de exemplu Produs or IEnumerable<Produs>)
Suport automat pentru OData: Prin folosirea noului atribut [Queryable] in metoda unui controller care întoarce IQueryable, clienții pot folosi metoda pentru a compune interogări OData
Auto-găzduire: cu Web API, nu mai e obligatoriu să folosim IIS pentru a găzdui servicii HTTP. Serviciile REST pot găzduite într-un serviciu Windows, o aplicație consolă sau orice alt tip de găzduire de care avem nevoie sau la care avem acces.
In concluzie, ASP.NET MVC Framework ne oferă o platformă foarte bună pentru a realiza API-uri Web în stil REST. Pentru scenariile care nu au nevoie de puterea si complexitatea oferite de WCF si SOAP, MVC poate fi o alternativă simplă și elegantă. Scenariile posibile includ aplicațiile care au nevoie să funcționeze doar pe HTTP precum și aplicațiile axate în principal pe mesaje text formatate.
Exemple de implementări de servicii REST
Serviciile REST sunt folosite in tot Internetul. Cele mai elocvente exemple sunt prezentate in lista de mai jos:
Amazon: Simple Storage Service (S3) (http://aws.amazon.com/s3)
Servicii care expun protocolul Atom Publishing Protocol (http://www.ietf.org/html.charters/atompub-charter.html)
Majoritatea serviciilor web de la Yahoo (http://developer.yahoo.com/)
del.icio.us : http://del.icio.us/help/api/
3.1 Amazon’s Simple Storage Service (S3)
Amazon folosește atât SOAP cat si REST pentru serviciile web însă un procent de 86% din utilizarea acestora este realizata de către cele de tip REST.
Figura 1: Invocarea unui serviciu web REST de la Amazon.
Yahoo! oferă de asemenea servicii REST. Serviciul Web Search de la Yahoo este de tip RESTful. Serviciul BOSS Search API este limitat la 5000 de interogări pe zi pentru o adresa de IP. Serviciul permite utilizatorilor căutarea de pagini web folosind o arhitectura REST. Câteva reguli prin care se construiesc cereri de tip REST sunt prezentate in figura de mai jos:
În acest capitol am trecut în revistă modelul REST, avantajele folosirii ASP.NET MVC 4, incluzând suportul foarte bun pentru REST, rute URL personalizate și interoperabilitatea dintre serviciile bazate pe REST– și JSON; în încheiere am făcut o mica introducere în noul Web Api din ASP.NET MVC 4 și am explorat câteva dintre noile funcționalități pe care le aduce în lumea serviciilor REST.
În capitolele următoare vom aplica în practică Web Api pentru realizarea unei aplicații care va prezenta un serviciu REST către aplicații de pe dispozitive mobile.
CAP. 2 – SPECIFICATII SI ARHITECTURA
Descrierea aplicației
Vom realiza o aplicație SFA (Sales Force Automation) care să funcționeze pe dispozitive mobile (telefoane inteligente)
Scopul unei aplicații SFA este de a sta la dispoziția agenților de vânzări dintre companiile care se ocupă cu distribuția de produse în cantități mici, dar variate, în general.
Agenții de vânzări au nevoie să preia comenzi de la clienți – pe teren – și să le transmită la o aplicație centrală unde se realizează toată logistica onorării comenzilor; pentru acest lucru vom crea un API începând de la nivelul 0 al modelului REST și vom adăuga în etape toate ingredientele necesare pentru a ajunge la nivelul 3 al modelului.
Până de curând majoritatea aplicațiilor SFA erau realizate pe tehnologii Microsoft și anume SQL Server ca bază de date centrală (la sediul companiei), iar dispozitivele mobile folosite erau PDA-uri cu Windows Mobile mergând până la versiunea 7. Dar odată cu explozia din ultimii anii a utilizării telefoanelor inteligente și declinul utilizării PDA-urilor, a apărut necesitatea migrării acestor aplicații pe tehnologii mai noi, care să funcționeze pe aceleași telefoane inteligente pe care agenții de vânzări le folosesc și pentru convorbiri de tip voce, reenunțându-se la un al doilea dispozitiv cu o tehnologie învechită și care nu mai are suport din partea producătorilor.
Aplicația este formată din două părți:
un API instalat pe un server IIS pe realizat conform modelul REST
aplicații mobile native pentru sistemele de operare iOS 8, Android 4.4 și Windows Phone 8
schema bloc a sistemului
funcțiile sistemului
arhitectura generală
am urmărit modelul REST
in aceasta lucrare vom realiza o aplicație SFA
Vom urma principiile modelul REST al lui, in realizarea aplicației vom urmări realizarea
respectare nivele
UML
2.2 funcțiile sistemului
comenzile de la clienți sunt preluate cu o zi (sau mai multe zile) înainte de către agenții de vânzare care activează pe teren cu ajutorul aplicațiilor native instalate pe telefoane inteligente cu sisteme de operare iOS 8, Android 4 și Windows Phone 8.1
aplicația de pe telefon se conectează la serviciul REST de pe server;
serviciul REST este conectat la o bază de date Microsoft SQL Server care este actualizată în timp real cu baza de date principală a aplicației ERP care gestionează toate activitățile ce au legapturp cu comenzile: verificare stocuri, comenzi la furnizor, livrarea, facturare, retururi conform operațiunilor logistice stabilite de compania care folosește aplicația
2.1 schema bloc a sistemului
Fig. 1 – Schema bloc a aplicației
UML EXECUTARE COMANDĂ
Schema aplicației prezentata in acesta lucrare.
2.3 arhitectura generală
În implementarea aplicației vom urmări modelul REST prezentat în capitolul anterior, folosim framework-ul Web Api inclus în Microsoft ASP.NET
Soft folosit
APLICATIE WEB:
• Server: API pe IIS 8
• Client: iOS iphone, Windows Phone si Android.
Unele de dezvoltare folosite
Visual Studio 2013 Professional folosit pentru:
realizarea serviciului REST pe server (cu .NET Framework 4.5.2, inclusiv ASP.NET 4.5 instalat pe server)
aplicația Windows Phone (împreună cu Windows Phone 8.0 SDK) –limbaj de programare C#
SQL Server 2014
Android Studio și Android SDK pentru dezvoltarea aplicației pentru telefoane cu sistemul de operare Android 4.4 (Kit Kat) – limbaj de programare Java
xCode 6 și SDK iOS 8 pentru realizarea aplicației pentru iPhone (iOS 8) – limbaj de programare Swift
Tehnologii folosite:
ASP.NET MVC 4
Visual C#
Objective-C/Cocoa/Cocoa Touch
SDK: iOS 8 SDK
SDK: Windows Phone 8 SDK
Medii de dezvoltare folosite:
Visual Studio 2013 Pro (MSDNAA)
xCode 6
Configuratie SERVER
Windows Server 2012 R2 sTANDARD Edition
4GB RAM + 200 GB HDD
IIS 8.5
.NET Framework 4.5.2 (ASP.NET 4.5, MVC 4)
Microsoft SQL Server 2012 R2 Standard
Pe partea de server
DB
CAP. 2b – Proiectarea Serviciului REST
Pentru realizarea serviciului nostru vom urma modelul RMM al lui Leonard Richardson, care definește calea de urmat pentru a modifica stilul unei aplicații tradiționale RPC într-o aplicație REST, încercând să urmăm îndeaproape modelul REST. Având în vedere faptul că un serviciu realizat conform arhitecturii REST ar trebui, cel puțin în teorie, să folosească verbe HTTP și să fie axat pe resurse, interfața lui va considerabil diferită de un API în stilul „tradițional” RPC sau SOAP; vom încerca să prezentăm diferențele de metodologii între acestea.
În continuare vom alege componentele software adiționale care se vor adăuga mediului de lucru Visual Studio 2013.
La final vom realiza o metodologie de testare a aplicației și vom configura un sistem de logare a evenimentelor și erorilor din aplicație.
2.4 Structura serviciului
În acest capitol vom realiza tabelele cu tipurile de resurse cu acțiunile HTTP și URI-urile asociate.
NIVEL 0
Dacă API-ul nostru ar fi un serviciu SOAP de nivel 0 am crea un serviciu WCF cum ar fi ComenziServiciu; peste acest serviciu am avea o metoda CreareComanda(). Această metodă ar putea primi o cerere care să includă numele comenzii, clientul sau alte date; răspunsul metodei ar fi un număr generat automat de sistem.
Am putea avea și o metodă care să aducă de pe server detaliile unei comenzi. GetComanda(). Această nouă metodă ar trebui să primească ca input un ID și să întoarcă un obiect comandă – serializat ca XML.
Alte metode posibile sunt prezentate în tabelul următor:
Tabel 3.1. Serviciul la nivelul 0 al MMR
Toate operațiile sau metodele arată la fel dacă ne uităm la ele din punctul de vedere al internetului, iar serviciul nu prea arată a Web. De exemplu, dacă preluăm comanda 132 sau 1234, URI-ul este același, fiind de fapt același folosit pentru a crea o comanda, a o actualiza sau pentru finalizarea ei. Nu am folosit verbele HTTP așa cum ne-am propus, fiecare acțiune disponibilă în API este creată în mod special; pentru a fi RESTful pe HTTP, va trebui să evităm să avem acțiuni care sunt consistente cu HTTP (adică trebuie să folosim verbe cum ar fi GET, PUT, POST și DELETE.
Clienții trebuie să știe dinainte totul despre acțiunile disponibile adică există o legătură implicită între client și server, în sensul că apelantul este dependent de un contract și de un set dat de acțiuni din partea serviciului.
De asemenea nu trebuie să ținem minte toate câmpurile care trebuie completate pe un formular înainte de a trimite o cerere (în cazul nostru plasarea unei comenzi). Serverul dictează toate relațiile, toate URI-urile și toate formulare fără să ceară cunoașterea lor prealabilă. Acest lucru se va întâmpla deoarece, clienții cunosc implicit web site-urile care ghidează clientul prin resursele disponibile și vor furniza toate informațiile de care avem nevoie pentru a face orice schimbare sau cereri.
NIVEL 1: URI și resurse
Scopul nostru este realizarea unui API centrat pe resurse. The actions available to those resources are constrained by the use of HTTP. This is why you must map the available HTTP verbs into the API; you don’t have the freedom to create other actions or verbs. Acest concept este baza unui design REST.
Am ajuns la nivelul 1 al modelului de maturitate al lui Richardson
În tabelul 3.2 putem vedea cum fiecare resursa individuala este adresabilă de un URI unic (Uniform Resource Identifier).
Tabel 3.2. Serviciul la nivelul 1 al modelului MMR
Dar încă suntem forțați să ne bazăm pe mesaje specifice pentru operații: apelantul nu poate diferenția două operații disponibile cu un URI ca /api/comenzi decât dacă apelantul deja are contractul. Folosim doar verbul POST, așa că acțiunea dorită este dictată de mesajul cererii.
NIVEL 2: Verbe HTTP
Trebuie să identificăm verbele HTTP de care avem nevoie. Deoarece nu exista un verb CreateComanda, nici măcar un verb Create trebuie să alegem dintre verbele disponibile în protocolul folosit și anume:
GET
PUT
POST
DELETE
Deoarece avem nevoie să generăm comenzi noi, putem elimina GET și DELETE pentru acțiunea CreateComanda. Dintre cele rămase, PUT se folosește pentru a crea sau înlocui o resursă cu identificator cunoscut (un URI unic cunoscut); folosim POST când sistemul generează identificatorul noii resurse generate.
Tabel 3.3. Folosirea verbelor HTTP cu resursa Comenzi
Semnificația fiecărui verb este dependentă de URI; avem patru verbe, dar opt acțiuni diferite, în funcție de obiectul referinței (colecție sau element unic).
La crearea unei instanțe noi a resursei, PUT se folosește cu un URI unic în cazul în care apelantul generează identificatorul noii resurse înainte de a trimite cererea către server. În tabelul 3.3, acțiunea PUT este folosită cu un element URI unic pentru a crea o nouă comandă cu un identificator specificat, 1138. Dacă în schimb sistemul ar genera identificatorul, apelantul ar folosi acțiunea POST și o colecție URI.
Aceste aspecte sunt legate de conceptul de idempotență:
Metodele PUT și DELETE sunt idempotente; apelarea lor repetată va produce același rezultat fără alte efecte colaterale
Acțiunea GET se numește sigură . Aceasta nu este idempotentă în sine. Sigur înseamnă că nimic în sistem nu se schimbă, ceea ce este potrivit pentru apeluri HTTP care trebuie doar să interogheze sistemul fără să schimbe nimic.
POST nu este considerat idempotență, deoarece la fiecare invocare a metodei, se creează o nouă resursă de tipul celei invocate.
Trebuie să mapăm fiecare resursă cu un set de acțiuni HTTP, definind care sunt permise și care nu sunt suportate de API-ul nostru.
În tabelul următor am folosit verbele HTTP disponibile, ajungând la nivelul 2 al modelului REST.
Tabel 3.4. Serviciul la nivelul 2 al modelului MMR
În acest moment serviciul folosește URI-uri unice pentru resursele individuale și am trecut la verbe HTTP adică fiecare acțiune PUT și POST va fi reprezentată de o resursă comanda (XML sau JSON).
Totuși clientul tot trebuie să aibă cunoștințe prealabile despre API ca să poată traversa domeniul și pentru a putea executa operații mai complexe decât crearea, actualizarea sau finalizarea unei comenzi. Conform naturii Web-ului clientul ar trebui în schimb să fie ghidat în totalitate, punând la dispoziție toate resursele și acțiunile prin intermediul link-urilor și form-urilor, adică pasul următor HATEOAS “hypermedia ca și motor al stărilor aplicației”.
NIVEL3: HATEOAS
Acest atribut al HATEOAS este cheia ca un serviciu să fie RESTful (REST complet); totuși este deseori neglijat deoarece necesită un schimb de gândire semnificant față stilul clasic de design RPC.
În tabelele 3.3 și 3.4, putem observa că anumite operații GET vor întoarce colecții de resurse. Unul dintre principiile REST cu HTTP este acela că apelanții fac tranzițiile prin stările aplicației doar cu ajutorul hyperlink-urilor puse la dispoziție de către server; astfel dacă apelantul primește o cale rădăcină sau un URI de start, va putea să navigheze colecția de resurse fără a cunoaște în prealabil schema URI. Oricând o resursă este returnată de către serviciu, indiferent dacă într-o colecție sau singură, datele returnate trebuie să includă și URI-ul necesar pentru a se întoarce iar și să execute o altă comandă GET ca să obțină chiar acea resursă.
În mod normal se returnează doar câteva atribute sau porțiuni de date când se răspunde cu o colecție; acum apelantul poate folosi acel URI pentru a obține toate atributele acelei resurse.
În lumea HATEOAS, dorim să ghidăm utilizatorul spre acțiunile disponibile pe o resursă. Când un utilizator vizitează un site, el are nevoie să știe doar adresa rădăcină a site-ului poate a vizita între site-ul; dorim să păstrăm o experiență similară pentru apelanții API-ului nostru.
Acum putem completa tabelul de resurse și operații folosind cele trei concepte învățate din modelul MMR:
URI-uri și resurse
Verbe și HTTP
HATEOAS
În tabelul 2.5 am ajuns la un design REST mai aproape de ideal. Se pot vedea lucrurile pe care le putem face pentru a face serviciul să se auto-descrie. (de exemplu, informațiile legate de operațiile disponibile sunt transmise către apelant prin link-uri conținute în răspunsul serviciului).
Tabelul 2.5. Serviciul la nivelul 3 al modelului MMR
2.5 Modelarea tabelelor de resurse
Până acum, am explorat caracteristicile pe care un API trebuie să le dețină înainte de a putea pretinde că serviciul este RESTful. Am trecut în revistă și modelul de maturitate al lui Richardson pentru servicii REST și am folosit modelul pentru a trece prin nivelele modelului în timpul modelării aplicației noastre.
Trebuie să vedem ce vrem să poată face apelanții API-ului nostru. Din moment ce serviciul nostru se axează pe preluarea de comenzi de produse, majoritatea capabilităților vor fi pentru crearea, vizualizarea și modificarea comenzilor; pentru acest lucru vom modela categorii, parteneri/clienți, starea comenzilor etc.
În primul rând, utilizatorul trebuie să poată crea o nouă comandă și ar trebui să poată face acest doar prin furnizarea unui subiect. Valori ca scadența plății, data_livrarii, prioritate, pot fi actualizate mai târziu dacă nu sunt cunoscute în momentul realizării comenzii. Când se creează o nouă comandă, aplicația va crea un identificator pentru ea. Bineînțeles, apelantul va putea să șteargă sau să actualizeze o comandă existentă (daca se realizează până la închiderea zile de lucru
O comanda trebuie să suporte nici un articol sau mai multe ca făcând parte dintr-o comanda.
În ceea ce privește articolele, agentul de vânzări va trebui să vadă o listă cu toate articolele. Astfel, aplicația client va putea primi o listă cu articolele sau să trimită un șir de căutare.
În sfârșit, pentru a putea clasifica comenzile, vom furniza valori pentru parteneri, sediul sau punctul de lucru al clientului la care se livrează produsele
Trebuie să fim atenți la una dintre regulile principale ale arhitecturii REST și anume evitarea cuplării clientului cu serverul prin partajarea definițiilor de tip; deși vom folosi clase în codul de server pentru reprezenta resursele primite și trimise către apelant, aceste definiții sunt interne, păstrând comunicarea externă a serviciului la ce ne dă voie protocolul HTTP (de exemplu, verbe HTTP, URI-uri pentru acces la resurse și folosirea hypermedia ca motor al stării aplicației).
Linkuri Hypermedia
Clientul care consumă API-ul nostru trebuie ghidat prin serviciul nostru; de fiecare dată când trimitem reprezentări ale resurselor către apelant, trebuie să trimitem și o listă de acțiuni disponibile (schimbări de stare).
Una dintre problemele ce decurg din folosirea linkurilor este că arhitectura REST nu definește nici un standard care ar trebui urmat pentru crearea link-urilor într-un API. Dintre multele abordări disponibile se remarcă link-urile de tip ATOM, care seamănă cu elementul link HTML, dar sunt destinate consumării de către readerele de date agregate.
3.1.3 Urmărirea modelului RMM
Serviciul RESTful trebuie să arate și să se comporte ca un automat finit (state machine), adică trebuie să avem resurse care trec prin stări prin tranziții de stare predefinite. Din definiția REST, serviciul nostru trebuie să specifice tranzițiile permise pentru orice resursă dată pe baza stării curente a acelei resurse. Cu alte cuvinte, link-urile disponibile (stările de tranziție) se vor schimba de la un apel la următorul, în funcție de starea în care suntem (ex starea comenzii și permisiunile utilizatorului curent). De aceea este imperios necesar ca lista de linkuri să fie dinamică.
Un alt motiv important pentru utilizarea unei colecții de legături pentru stările de tranziție este principiul Single Responsibility Principle (SRP), formulat de Robert C. Martin în 2002 și care spune că o clasă ar trebui să aibă doar un singur motiv să se schimbe și implicit ar trebui să fie responsabilă pentru un singur lucru. Daca am include stările de tranziție în tipurile de resurse, am viola principiul SRP, deoarece definiția resursei ar trebui să se schimbe la fiecare schimbare a unei stări de tranziție disponibile.
OData
URI-ul /api/articole în serviciul nostru va furniza capabilități limitate de interogare și filtrare (siruri de căutare ce pot avea și wildcard-uri).
Pentru interogări mai complexe există Open Data Protocol (OData. Acest protocol a fost creat de Microsoft și alte companii pentru a standardiza interogările și actualizările bazate pe web.
Pe site-ul www.odata.org se spun următoarele :
„Protocolul OData înlesnește crearea de servicii de date REST, care permit ca resursele, identificate prin Uniform Resource Identifiers (URI) și definite într-un model de date șă fie publicate și editate de clienți Web folosind mesaje HTTP simple.”
OData este un standard OASIS care definește cele mai bne practici pentru construirea și consumarea API-urilor RESTful.
Acum trebuie să definim URI-urile și verbele d HTTP pentru resursa Comenzi.
Tabellul 2.5 shows the list of operations available for the Task.
Table 2-5. Listă cu operații cu Comenzi
Am folosit pentru prima data PUT și DELETE pe o colecție de resurse. Pentru a specifica produsele incluse în comanda, apelantul folosește colecția Articole pentru a adăuga sau a sterge un anumit produs unul câte unul; am putea chiar șterge toate articolele (din comandă) folosind PUT sau DELETE pe întreaga colecție. Conform protocolului HTTP, acest lucru va înlocui sau șterge toate produsele (articolele) asociate comenzii. The same applies to the categories associated with a given task.
Valorile status și livrare nu sunt colecții, dar trebuie să permitem apelantului să le actualizeze pentru a permite selectarea datei de livrare și confirmarea închiderii comenzii prin plata ulterioară a comenzii.
Reprezentarea modelului bazei de date în proiectul atSFADb inclusă în soluția Visual Studio 2013:
//Comanda.sql
CREATE TABLE [dbo].[Task] (
[ComandaId] BIGINT IDENTITY (1, 1) NOT NULL,
[DetaliiComanda] NVARCHAR (100) NOT NULL,
[Data_Livrare] DATETIME2 (7) NULL,
[DataFinalizare] DATETIME2 (7) NULL,
[ScadentaPlata] DATETIME2 (7) NULL,
[StatusId] BIGINT NOT NULL,
[DataComenzii] DATETIME2 (7) NOT NULL,
[Agent] bigint NOT NULL,
[ts] rowversion NOT NULL,
PRIMARY KEY CLUSTERED ([ComandaId] ASC),
FOREIGN KEY ([StatusId]) REFERENCES [dbo].[Status] ([StatusId]),
FOREIGN KEY ([Agent]) REFERENCES [dbo].[Articol] ([ArticolId])
//Articol.sql
CREATE TABLE [dbo].[Articole](
[IDarticol] [int] NOT NULL,
[ClasaArticol] [tinyint] NULL,
[Articol] [nvarchar](255) NULL,
[UM] [nvarchar](255) NULL,
[PretVinzare] [float] NULL,
[Gestiune] [nvarchar](255) NULL,
[Masa] [float] NULL,
[TVA] [float] NULL,
[TipSerie] [nvarchar](255) NULL,
[SimbolClasaA] [nvarchar](255) NULL,
[SinncronizareID] [uniqueidentifier] NULL,
CONSTRAINT [PK_Articole] PRIMARY KEY CLUSTERED
(
[IDarticol] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Comanda]
(
[ComandaId] bigint NOT NULL,
[ArticolId] bigint not null,
[ts] rowversion not null,
primary key ([ComandaId], [ArticolId]),
foreign key ([ArticolId]) references dbo.[Articol] (ArticolId),
foreign key ([ComandaId]) references dbo.Task ([ComandaId])
)
go
create index ix_ComandaArticol_ArticolId on T Comanda ([ArticolId])
go
//status.sql
CREATE TABLE [dbo].[Status] (
[StatusId] BIGINT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[StareComanda] INT NOT NULL,
[ts] rowversion NOT NULL,
PRIMARY KEY CLUSTERED ([StatusId] ASC)
);
2.6 interfața cu utilizatorul (doar pe aplicatii mobile)
Serviciul în sine nu are interfață cu utilizatorul, se poate comunica cu el prin HTTP/text prin metodele și acțiunile expuse.
Aplicațiile native de pe telefoanele inteligente sunt realizate nativ cu instrumentele de dezvoltare suportate oficial de producătorii platformelor respective:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
CORDOVA TOOLS
Securizarea serviciului
Serviciul REST este publicat pe un server public, dar serverul IIS pe care este instalat acceptă conectarea doar la clienții mobili pre-autorizați prin configurarea unui certificat digital pe fiecare dispozitiv.
Aplicațiile mobile în sine nu sunt securizate în modul obișnuit; deoarece aplicațiile SFA sunt aplicații Enterprise, ele nu sunt instalate printr-un App Store oficial al producătorului SDK-ului (Apple, Microsoft sau Google). Aplicațiile sunt instalate in-house, de către departamentul IT al beneficiarului, cu unelte specializate de deployment specifice (de exemplu în cazul Apple am folosit Apple Configurator cu care se poate genera o instalare cu un certificat digital care identifică unic dispozitivul mobil, nefiind necesară introducerea unui nume de utilizator si a unei parole.
În mod normal autentificarea cu certificate client nu este foarte folositoare pentru web site-uri sau servicii web publice, dar în cazul nostru se mulează foarte bine pe faptul că avem acces la dispozitivele mobile care au dreptul să se conecteze și pot fi configurate ușor cu certificate client.
Serviciul REST autentifică clienții în funcție de aceste chei unice, preluînd comenzi doar de la acestea.
Automatic Error Logging
În final vom prezenta pe scurt partea de monitorizare (logging) a aplicației.
Am urmărit două aspecte în tratarea excepțiilor generate de acțiunile controller-ului:
Logarea erori către modulul log4net.
Întoarcerea unui cod eroare 500 către apelant, incluzând o parte a mesajului de eroare în răspuns. În mod normal nu ar trebui să expunem mesaje de eroare interne ale aplicației către utilizatori, dar poate fi mult mai ușor să identificăm și rezolvăm bug-urile aplicației, dacă avem un mesaj de eroare mai detaliat; în plus câteva mesaje oricum trebuie să ajungă la apelant, de exemplu erorile de validare trebuie afișate pe aplicație mobilă. O implementare mai corectă ar fi să facem această opțiune configurabilă și să returnăm mesajele de eroare complete pentru anumite erori sau în anumite condiții.
CAP. 3 IMPLEMENTAREA EFECTIVĂ
3.1 Controllers, Dependencies, and Managing the Database Unit of Work
3.1.1 Controller Activation
3,1,2 Dependencies
3.1.3 Constructor Injection of Dependencies
3.5 Alegerea componentelor de arhitectură
Am ajuns la punctul în care putem explora opțiunile disponibile în ceea ce privește uneltele și framework-urile disponibile ce se pot utiliza în contextul unui serviciu REST creat ASP.NET MVC 4 Web API.
Componentele software folosite la dezvoltarea serviciului REST:
Acces date. Am folosit NHibernate pentru cea mai mare parte a operațiilor C-R-U-D (Create-Read-Update-Delete) suplimentate cu proceduri stocate unde a fost cazul: de asemenea cu NHibernate se poate separa apelantul de tot ce este orientat SQL Server, astfel se pot suporta și alte baze de date fără a modifica codul substanțial
Container IoC. Pentru injecția dependențelor în aplicație, vom folosi Ninject. Este simplu de folosit, este integrat într-un singur DLL și este configurat pentru o sintaxă fluentă.
Logger. Avem nevoie de un logger care să realizeze următoarele operații (configurabile la runtime sau în timpul deployment-ului): filtrare, log-uri pe nivele, rutare și formatare. Pentru acest scop am ales log4net, care are în plus și o interfață ILog care ne permite să folosim injecția de dependințe pentru a putea furniza instanțe de logger pentru orice clasă a aplicației.
Autentificare și autorizare. Autentificarea și autorizarea se face de către serverul web IIS care comunică cu dispozitive mobile prin certificate digitale client instalate pe dispozitivele mobile
Framework de testare. Am folosit NUnit si ReSharper pentru a rula testele.
Scriptare Build and Deployment Build. În sfârșit, trebuie să ne alegem uneltele pentru compilarea și publicare aplicației noastre. Pentru realizarea unei aplicații fiabile, avem nevoie de un bun process de livrare a versiunilor noi ale aplicației, astfel încât orice bug sau funcționalitate nouă să poată fi livrate în mediul de producție fără a se folosi prea mult procese manuale (și implicit riscante). Vom folosi MSBuild și extensiile MSBuild Extension Pack(acestea din urmă pot fi folosite pentru crearea unui site in IIS, rularea unui script pe o bază de date SQL sau instalarea si pornirea unui serviciu Windows).
Configurarea calculatorele de dezvoltare
Un PC Windows cu suport pentru virtualizare (necesar pentru emulatorul de Windows Phone)
Windows 8 64bit
IIS 8
.NET 4.5 (cu ASP.NET 4.5) instalat
SQL Server 2014
Visual Studio 2013
Windows Phone SDK 8.0
NuGet Package Manager 2.1 (pentru configurarea librăriilor necesare în proiectele)
Un calculator Apple Mac pentru realizarea aplicației pentru iPhone:
xCode 6 – mediu de dezvoltare
SDK iOS 8
Proiecte Visual Studio 2013
Tabel 3-7. Proiectele din soluția Visual Studio 2013
Tabel 3.8. Proiectele de test
Descrierea proiectelor
Tabel 4.3. Descrierea proiectelor folosite
Figura 4-3. Soluția în Visual Studio 2013
*
CEVA AICI
*
CEVA AICI
*
Am adauăgat și utlimele componente, acum serviciul funcționeză, toate dependențele sunt rezolvate și toate modulele comunică între ele.
La momentul rulării serviciul funcționează în modul următor:
Apelantul face o cerere web;.
MVC pornește activarea controller-ului adecvat pe rutelor URL înregistrate la pornirea aplicaței
MVC folosește NinjectDependencyResolver pentru a satisface toate dependințele controller-ului, toate dependințele pe care le cer fiecare dintre aceste dependințe ș.a.m.d;
Dacă orice obiect cere un obiect ISession object, Ninject apelează metoda NinjectConfigurator. CreateSession() pentru a crea instanța ISession.
În continuare vom realiza testarea aplicației, manual și automat (în Visual Studio folosind Resharper).
CAP. 4 Testarea aplicației – Utilizarea sistemului și rezultate experimentale
Using Fiddler
If you don’t already have Fiddler installed on your workstation, download and install it now from www.fiddler2.com/fiddler2/. Once it is installed, fire it up from the Windows Start Menu. Once launched, it will start capturing all of the browser traffic. What you want to do with the tool is to make web requests to the task-management service, similar to what the browser is doing. The difference is that you can create and examine the raw header and body content for request and response messages.
Once you have Fiddler open, go back to your browser and navigate to the categories URL again. Then, back in Fiddler, double-click the 200 response entry in the left-hand panel. Figure 7-1 shows what you should see and double-click.
Figure 7-1. The aricole response entry
In the right-hand panel, you should see the request data at the top and the service’s response at the bottom. Click the Raw buttons to see both the request and the response. The raw request data should like similar to Figure 4,1.
Fig. 4.1. The articole raw HTTP request
You should note two things in the request: the URL at the top that represents the GET request URI and the Authorization header value of “Basic amJvYjpqYm9iMTIzNDU=.” This is the base64-encoded string of the credentials you entered when the browser prompted you for your username and password.
Now look at the raw data for the HTTP response (the bottom-right panel). Note that it includes an HTTP status code of “200 OK” in the header. Also, the body contains the XML representing all of the categories currently in the database. You can also click the other buttons in the request and response panels to look at the data rendered as XML or just a Headers view. Figure 7-3 shows the response panel just described.
Figure 7-3. The categories raw response
To see one of the capabilities of the Web API, click the Composer tab in the top-right request panel. Make sure GET is selected in the dropdown, and then enter the URL to the categories list in the address bar (http://localhost:11000/api/categories). Next, enter the following in the Request Headers box:
Authorization: Basic amJvYjpqYm9iMTIzNDU= Content-Length: 41
Host: localhost:11000
At this point, the Composer tab should like similar to Figure 7-4.
GET http://localhost:11011/api/articole
Request Headers
Authorization: Client certificate
Figure 7-4. The composer tab for the categories query
Go ahead and click the Execute button. If all goes well, you should see a new entry in the left-hand panel. Double-click the new entry. On the right-hand side, you can examine the request and response content for your manually composed HTTP request. The response panel should look very similar to Figure 7-3.
NUnit, Postman, ReSharper
tehnologia folosită
probleme întâmpinate și modul de rezolvare
rezultate experimentale
CAP. 5 Concluzii
Analiza rezultatelor obținute – în concluzii
sublinierea realizărilor obținute,
comparația cu sisteme similare (WCF, SOAP),
În primul capitol am prezentat modelul REST ca o alternativă la serviciile web bazate pe SOAP; am prezentat ASP.NET MVC ca pe un framework foarte bun pentru a realiza servicii RESTful și despre valoarea pe care o aduce Web Api în plus în scopul de construi servicii REST și mai flexibile și mai robuste. Am trecut în revistă principalele caracteristici ale arhitecturii REST și a, studiat modelul de maturitate REST al lui Richardson în comparație cu modelul RPC.
.
În capitolul al doilea am prezentat schema bloc a aplicației, schema de utilizare, am folosit cunoștințele din primul capitol pentru a modela un API pentru un serviciu REST care este la baza unei aplicații SFA (Sales Force Automation)
Am început de la nivelul 0 al modelului MMR și am adăugat elementele necesare ajungerii la nivelul 3 al modelului. Am realizat specificația API-ului public, modelul de date pentru serviciu și am făcut de selecție de componente și unelte de dezvoltare și runtime-uri.
Am urmărit diferențierea între REST și RPC:
REST verbe HTTP și tipuri de resurse. Toate resursele din domeniu (de exemplu în baza de date) au un URL unic. Și mai mult consumatorii API-ului pot modifica starea datelor prin trimiterea de cereri HTTP cum ar fi PUT, POST, și DELETE) către acele URL-uri.
SOAP: mesaje și metode. Toate operațiile sunt cereri POST de mesaje XML către un singur URL
I Apoi am creat soluția cu proiectele incluse în Visual Studio 201. Am configurat librăriile și referințele dintre proiect.
Am finalizat API-ul:
writing some of the basic classes and configuration for the domain model
the API’s resource types,
the database
log4net configuration
the sections in the web.config file.
În acest moment serviciul nu era funcțional, dar am modelat toate tipurile și structurile care vor comunica și păstra datele – atât în cadrul aplicației cât cu apelanții API-ului
Chapter 5 was all about stitching together the various architecture components you decided to use. The modeling you did in Chapter 4 was purely about data. In Chapter 5, however, the application finally started coming alive. For example, you configured
the Ninject dependency-injection container, managed the database unit of work and transactions, and stepped through the exact steps taken by ASP.NET MVC 4 and the Web API whenever a caller submits a request to one of the REST URLs (i.e., the controller methods). So, while you still hadn’t built any controllers yet, it was probably clear by this point how all of these pieces would come together at runtime. Of course, at that point the service was not yet secured, and you still had no way of knowing who was calling the service. A key take-away from Chapter 5 was to remember to always push all of your dependencies up to the class constructor.
Security was tackled in Chapter 6, with an emphasis on keeping it simple.
Direcții de dezvoltare
3.6 documentație și coduri sursă -în anexe).
Anexa 1: Cod sursa (selecții)
Note:
Codul generat de template-ul Web Api ASP.NET MVC din Visual Studio 2013 nu este prezentat aici (de exemplu modelele de view-uri, rute sunt folosite așa cum le furnizează Microsoft doar cu mici configurări și adaptări la sistemele hardware/sofware folosite
Sunt prezentate doar selecții de cod sursă care relevă activitatea de realizare a API-ului conform modelulul REST
}
Automatic Error Logging
The final section of this chapter will briefly cover error logging as performed from the controller action filter you learned about in Chapter 5—when you were looking at managing the database unit of work and transaction. That same action filter/attribute is a perfect place to put error logging because the filter’s OnActionExecuted() method will always execute, even when a controller action generates an exception.
You have two main goals in handling exceptions generated from controller actions:
Log the error to log4net.
Return a status code of 500 to the caller, including part of the error message itself.
The second goal is somewhat debatable, as one could argue that you don’t want to expose internal error messages to the users. However, it can be much easier to troubleshoot and fix bugs if an accurate error message is returned to the caller or user who will be logging bugs. Further, some messages need to make their way back to the
caller. For example, validation errors should certainly be visible to a consumer of the API. A fair approach might be to make this option configurable, and only return the full error messages for certain types of errors or only in certain environments.
You can satisfy both of the goals by using the following code within the
LoggingNHibernateSessionAttribute action filter:
private void LogException(HttpActionExecutedContext filterContext)
{
var exception = filterContext.Exception; if (exception == null) return;
var container = GetContainer();
var logger = container.Get <ILog> (); logger.Error("Exception occured:", exception);
var reasonPhrase = GetExceptionMessage(exception);
if (reasonPhrase.Length > MaxStatusDescriptionLength)
{
reasonPhrase = reasonPhrase.Substring(0, MaxStatusDescriptionLength);
}
reasonPhrase = reasonPhrase.Replace(Environment.NewLine, " ");
filterContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
ReasonPhrase = reasonPhrase
};
}
private string GetExceptionMessage(Exception ex)
{
var message = ex.Message;
var innerException = ex.InnerException; while (innerException != null)
{
message += " – >" + innerException.Message; innerException = innerException.InnerException;
}
return message;
}
First, you check to see if there even is an exception; if there isn’t, there is no need to continue. Next, provided you have an exception to handle, you get the logger from the container and log the exception as an error.
The next step is to convert the exception stack to a string—traversing the InnerException tree until you hit bottom. This is implemented in the
GetExceptionMessage() method. Next, take that string and make sure it’s not too long (anything longer than 512 characters will cause an unhandled exception). Also,
remove any end-of-line characters from the string (as that, too, will cause an unhandled exception).
The last step is to set the response to a new HttpResponseMessage object, setting the
return code to “500 Internal Server Error.” You also set the response’s ReasonPhrase to the cleaned-up exception message. Once the MVC has finished executing the action filter/ attribute, it will return that specific HttpResponseMessage object to the caller.
All of this is called from within the action filter’s OnActionExecuted() method:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
EndTransaction(actionExecutedContext); CloseSession(); LogException(actionExecutedContext);
LogAction(actionExecutedContext.ActionContext.ActionDescriptor, "EXITING ");
}
Anexa 2: Capturi de ecran aplicații mobile
Bibliografie
Mihail Cherciu – Curs tehnologii web, Universitatea din Bucuresti
Jamie Kurtz – ASP.NET MVC 4 and the Web Api, ISBN13: 978-1-4302-4977-1, 2013, Apress Media LLC., New York, Statele Unite ale Americii
http://www.asp.net/web-api, site-ul oficial al companiei Microsoft pentru Web Api
http://www.asp.net/mvc/mvc4 , site-ul oficial al companiei Microsoft pentru ASP.NET MVC 4
www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. Specificatii HTTP status codes
Microsoft Developer Network, http://msdn.microsoft.com
www.odata.org
Roy Thomas Fielding – Teza de doctorat Architectural Styles and the Design of Network-based Software Architectures,
https://github.com/jagregory/fluent-nhibernate/wiki.
http://www.xml.com/pub/a/2004/06/16/dive.html ATOM Links
http://martinfowler.com/articles/injection.html
Single Responsibility Principle (SRP), formulat de Robert C. Martin în 2002
http://en.wikipedia.org/wiki/Single_responsibility_principle
Bibliografie
Mihail Cherciu – Curs tehnologii web, Universitatea din Bucuresti
Jamie Kurtz – ASP.NET MVC 4 and the Web Api, ISBN13: 978-1-4302-4977-1, 2013, Apress Media LLC., New York, Statele Unite ale Americii
http://www.asp.net/web-api, site-ul oficial al companiei Microsoft pentru Web Api
http://www.asp.net/mvc/mvc4 , site-ul oficial al companiei Microsoft pentru ASP.NET MVC 4
www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. Specificatii HTTP status codes
Microsoft Developer Network, http://msdn.microsoft.com
www.odata.org
Roy Thomas Fielding – Teza de doctorat Architectural Styles and the Design of Network-based Software Architectures,
https://github.com/jagregory/fluent-nhibernate/wiki.
http://www.xml.com/pub/a/2004/06/16/dive.html ATOM Links
http://martinfowler.com/articles/injection.html
Single Responsibility Principle (SRP), formulat de Robert C. Martin în 2002
http://en.wikipedia.org/wiki/Single_responsibility_principle
Anexa 1: Cod sursa (selecții)
Note:
Codul generat de template-ul Web Api ASP.NET MVC din Visual Studio 2013 nu este prezentat aici (de exemplu modelele de view-uri, rute sunt folosite așa cum le furnizează Microsoft doar cu mici configurări și adaptări la sistemele hardware/sofware folosite
Sunt prezentate doar selecții de cod sursă care relevă activitatea de realizare a API-ului conform modelulul REST
}
Automatic Error Logging
The final section of this chapter will briefly cover error logging as performed from the controller action filter you learned about in Chapter 5—when you were looking at managing the database unit of work and transaction. That same action filter/attribute is a perfect place to put error logging because the filter’s OnActionExecuted() method will always execute, even when a controller action generates an exception.
You have two main goals in handling exceptions generated from controller actions:
Log the error to log4net.
Return a status code of 500 to the caller, including part of the error message itself.
The second goal is somewhat debatable, as one could argue that you don’t want to expose internal error messages to the users. However, it can be much easier to troubleshoot and fix bugs if an accurate error message is returned to the caller or user who will be logging bugs. Further, some messages need to make their way back to the
caller. For example, validation errors should certainly be visible to a consumer of the API. A fair approach might be to make this option configurable, and only return the full error messages for certain types of errors or only in certain environments.
You can satisfy both of the goals by using the following code within the
LoggingNHibernateSessionAttribute action filter:
private void LogException(HttpActionExecutedContext filterContext)
{
var exception = filterContext.Exception; if (exception == null) return;
var container = GetContainer();
var logger = container.Get <ILog> (); logger.Error("Exception occured:", exception);
var reasonPhrase = GetExceptionMessage(exception);
if (reasonPhrase.Length > MaxStatusDescriptionLength)
{
reasonPhrase = reasonPhrase.Substring(0, MaxStatusDescriptionLength);
}
reasonPhrase = reasonPhrase.Replace(Environment.NewLine, " ");
filterContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
ReasonPhrase = reasonPhrase
};
}
private string GetExceptionMessage(Exception ex)
{
var message = ex.Message;
var innerException = ex.InnerException; while (innerException != null)
{
message += " – >" + innerException.Message; innerException = innerException.InnerException;
}
return message;
}
First, you check to see if there even is an exception; if there isn’t, there is no need to continue. Next, provided you have an exception to handle, you get the logger from the container and log the exception as an error.
The next step is to convert the exception stack to a string—traversing the InnerException tree until you hit bottom. This is implemented in the
GetExceptionMessage() method. Next, take that string and make sure it’s not too long (anything longer than 512 characters will cause an unhandled exception). Also,
remove any end-of-line characters from the string (as that, too, will cause an unhandled exception).
The last step is to set the response to a new HttpResponseMessage object, setting the
return code to “500 Internal Server Error.” You also set the response’s ReasonPhrase to the cleaned-up exception message. Once the MVC has finished executing the action filter/ attribute, it will return that specific HttpResponseMessage object to the caller.
All of this is called from within the action filter’s OnActionExecuted() method:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
EndTransaction(actionExecutedContext); CloseSession(); LogException(actionExecutedContext);
LogAction(actionExecutedContext.ActionContext.ActionDescriptor, "EXITING ");
}
Anexa 2: Capturi de ecran aplicații mobile
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Servicii Rest Pentru Aplicatii Mobile (ID: 123852)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
