Webes alkalmazások fejlesztése 9. előadás. Webszolgáltatások felhasználása (ASP.NET WebAPI)

Hasonló dokumentumok
Webes alkalmazások fejlesztése 9. előadás. Webszolgáltatások felhasználása (ASP.NET Core &.NET Framework)

Webes alkalmazások fejlesztése 8. előadás. Webszolgáltatások megvalósítása (ASP.NET WebAPI)

Webes alkalmazások fejlesztése 14. fejezet. Szolgáltatások adatkezelése (WCF) Giachetta Roberto. Eötvös Loránd Tudományegyetem Informatikai Kar

Webes alkalmazások fejlesztése 7. előadás. Autentikáció és autorizáció (ASP.NET Core) Cserép Máté

Webes alkalmazások fejlesztése 7. előadás. Autentikáció és autorizáció (ASP.NET)

Webes alkalmazások fejlesztése 8. előadás. Webszolgáltatások megvalósítása (ASP.NET WebAPI)

Webes alkalmazások fejlesztése 4. előadás. Megjelenítés és tartalomkezelés (ASP.NET Core) Cserép Máté

Webes alkalmazások fejlesztése 4. előadás. Megjelenítés és tartalomkezelés (ASP.NET)

Webes alkalmazások fejlesztése 10. előadás. Webszolgáltatások tesztelése (ASP.NET Core) Cserép Máté

Webes alkalmazások fejlesztése 4. előadás. Megjelenítés és tartalomkezelés (ASP.NET) Cserép Máté.

Eseményvezérelt alkalmazások fejlesztése II 12. előadás. Objektumrelációs adatkezelés (ADO.NET) Giachetta Roberto

Webes alkalmazások fejlesztése 12. fejezet. Szolgáltatás alapú kommunikáció (WCF) Giachetta Roberto. Eötvös Loránd Tudományegyetem Informatikai Kar

Eseményvezérelt alkalmazások fejlesztése II 8. előadás. Összetett WPF alkalmazások. Giachetta Roberto. Eötvös Loránd Tudományegyetem Informatikai Kar

API tervezése mobil környezetbe. gyakorlat

Szerializáció. Tóth Zsolt. Miskolci Egyetem. Tóth Zsolt (Miskolci Egyetem) Szerializáció / 22

Webes alkalmazások fejlesztése 10. előadás. Szolgáltatás alapú rendszerek megvalósítása (ASP.NET WebAPI) Cserép Máté

Webes alkalmazások fejlesztése 3. előadás. Objektumrelációs adatkezelés (ASP.NET)

Webes alkalmazások fejlesztése 6. előadás. Állapotfenntartás (ASP.NET) 2015 Giachetta Roberto

WCF, Entity Framework, ASP.NET, WPF 1. WCF service-t (adatbázissal Entity Framework) 2. ASP.NET kliens 3. WPF kliens

Webes alkalmazások fejlesztése Bevezetés. Célkitűzés, tematika, követelmények. A.NET Core keretrendszer

2. Beadandó feladat dokumentáció

Webes alkalmazások fejlesztése Bevezetés. Célkitűzés, tematika, követelmények. A.NET Core keretrendszer

CREATE TABLE student ( id int NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name varchar(100) NOT NULL, address varchar(100) NOT NULL )

2. Beadandó feladat dokumentáció

Eseményvezérelt alkalmazások fejlesztése II 5. előadás. Windows Forms alkalmazások párhuzamosítása. Giachetta Roberto

Symfony kurzus 2014/2015 I. félév. Security: authentication, authorization, user provider, role-ok, access control, FOS user bundle

1. beadandó feladat dokumentáció

3. Beadandó feladat dokumentáció

Java Programozás 11. Ea: MVC modell

Models are not right or wrong; they are more or less useful.

Webes alkalmazások fejlesztése 1. előadás. Webes alkalmazások és biztonságuk

C# nyelv alapjai. Krizsán Zoltán 1. Objektumorientált programozás C# alapokon tananyag. Általános Informatikai Tanszék Miskolci Egyetem

Adatbázisok webalkalmazásokban

OOP és UML Áttekintés

Webes alkalmazások fejlesztése 3. előadás. Objektumrelációs adatkezelés (Entity Framework) Cserép Máté

3. Beadandó feladat dokumentáció

Adabáziselérés ODBC-n keresztül utasításokkal C#-ban

Webes alkalmazások fejlesztése 6. előadás. Állapotfenntartás (ASP.NET) Állapotfenntartás. Állapotfenntartás. Állapotfenntartás.

Webes alkalmazások fejlesztése 6. előadás. Állapotfenntartás (ASP.NET Core) Cserép Máté

Java. Perzisztencia. ANTAL Margit. Java Persistence API. Object Relational Mapping. Perzisztencia. Entity components. ANTAL Margit.

Java Programozás 4. Gy: Java GUI. Tipper, MVC kalkulátor

C# Nyelvi Elemei. Tóth Zsolt. Miskolci Egyetem. Tóth Zsolt (Miskolci Egyetem) C# Nyelvi Elemei / 18

Mobil Telefonon Keresztüli Felügyelet Felhasználói Kézikönyv

1. ábra Fájl feltöltése 2. ábra Megtekintés

Webes alkalmazások fejlesztése 6. előadás. Állapotfenntartás (ASP.NET) Cserép Máté.

Webes alkalmazások fejlesztése 6. előadás. Állapotfenntartás (ASP.NET) 2015 Giachetta Roberto

Webes alkalmazások fejlesztése

Access adatbázis elérése OLE DB-n keresztül

Webes alkalmazások fejlesztése 2. előadás. Webfejlesztés MVC architektúrában (ASP.NET) Webfejlesztés MVC architektúrában Fejlesztés ASP.

Eseményvezérelt alkalmazások fejlesztése II 4. előadás. Windows Forms alkalmazások architektúrája és tesztelése

Objektum Orientált Programozás. 11. Kivételkezelés 44/1B IT MAN

Bevezető. Servlet alapgondolatok

Bánsághi Anna 2015 Bánsághi Anna 1 of 31

Webszolgáltatások (WS)

Szoftvertechnológia 8. előadás. Szoftverrendszerek tervezése. Giachetta Roberto. Eötvös Loránd Tudományegyetem Informatikai Kar

Eseményvezérelt alkalmazások fejlesztése I 11. előadás. Szoftverek tesztelése

OOP #14 (referencia-elv)

Webes alkalmazások fejlesztése. Bevezetés az ASP.NET MVC 5 keretrendszerbe

Objektumorientált programozás C# nyelven

Objektumorientált programozás C# nyelven

MVC. Model View Controller

Előszó A Windows alkalmazásfejlesztés rövid története A Windows életútja A Windows 8 paradigmaváltása... 16

Webes alkalmazások fejlesztése 2. előadás. Webfejlesztés MVC architektúrában (ASP.NET Core) Cserép Máté

Models are not right or wrong; they are more or less useful.

Tartalomjegyzék 2. RENDSZER FELÉPÍTÉSE... 3

C#, OOP. Osztályok tervezése C#-ban

KROMESCH SÁNDOR APP FELHŐ. API-k és Webszolgáltatások a Cloudban. Magyarországi Web Konferencia November 8.

Programozás II. labor

WEBFEJLESZTÉS 2. ADATBÁZIS-KEZELÉS, OSZTÁLYOK

Tartalom DCOM. Történeti áttekintés. Történeti áttekintés. Történeti áttekintés. Történeti áttekintés

OOP: Java 8.Gy: Abstract osztályok, interfészek

Eseményvezérelt alkalmazások fejlesztése II 10. előadás. Objektumrelációs adatkezelés (Entity Framework) Cserép Máté

Programozás BMEKOKAA146. Dr. Bécsi Tamás 8. előadás

Sorosítás (szerializáció) és helyreállítás. 1. Bináris sorosítás és helyreállítás Szükséges névterek Attribútumok. 1.3.

Webes alkalmazások fejlesztése 3. előadás. Objektumrelációs adatkezelés (Entity Framework) Cserép Máté.

ANDROID ALKALMAZÁSFEJLESZTÉS

A Java EE 5 plattform

QBE Édes Otthon lakásbiztosítás tarifáló webservice. Fejlesztői dokumentáció 1.0.2

Programozás II. ATM példa Dr. Iványi Péter

Overview. Service. Application Activity Activity 2 Activity 3. Fragment. Fragment. Fragment. Frag ment. Fragment. Broadcast Receiver

Szoftvertechnológia alapjai Java előadások

Hálózatkezelés. Tóth Zsolt. Miskolci Egyetem. Tóth Zsolt (Miskolci Egyetem) Hálózatkezelés / 20

SZÁMÍTÓGÉPES ADATBÁZIS-KEZELÉS. A MySQL adatbáziskezelő PHP folytatás JDBC, ODBC

Java VI. Egy kis kitérő: az UML. Osztály diagram. Általános Informatikai Tanszék Utolsó módosítás:

Grafikus keretrendszer komponensalapú webalkalmazások fejlesztéséhez

Programozási nyelvek Java

JUnit. JUnit használata. IDE támogatás. Parancssori használat. Teszt készítése. Teszt készítése

webalkalmazások fejlesztése elosztott alapon

Webes alkalmazások fejlesztése 2. előadás. Webfejlesztés MVC architektúrában (ASP.NET Core) Cserép Máté

Informatika terméktervezőknek

Programozás I. 3. gyakorlat. Szegedi Tudományegyetem Természettudományi és Informatikai Kar

A gyakorlat során az alábbi ábrán látható négy entitáshoz kapcsolódó adatbevitelt fogjuk megoldani.

JNDI - alapok. Java Naming and Directory Interface

Java. Java Message Service. ANTAL Margit. JMS API technológia. ANTAL Margit. Sapientia - EMTE

Johanyák Zsolt Csaba: Képnézegető program oktatási segédlet

Modellező eszközök, kódgenerálás

Vizuális és eseményvezérelt programozás , II. félév BMF NIK

MŰSZAKI DOKUMENTÁCIÓ. Aleph WebOPAC elérhetővé tétele okostelefonon. Eötvös József Főiskola 6500 Baja, Szegedi út 2.

Bevezetés Működési elv AJAX keretrendszerek AJAX

Eseményvezérelt alkalmazások fejlesztése II 5. előadás. Windows Forms alkalmazások párhuzamosítása. Cserép Máté

Átírás:

Eötvös Loránd Tudományegyetem Informatikai Kar Webes alkalmazások fejlesztése 9. előadás Webszolgáltatások felhasználása (ASP.NET WebAPI) 2016 Giachetta Roberto groberto@inf.elte.hu http://people.inf.elte.hu/groberto

A webszolgáltatás A webszolgáltatások lehetővé teszik az alkalmazások közötti platformfüggetlen adatcserét a legelterjedtebb modell a REST (Representational State Transfer), amely HTTP protokoll segítségével biztosítja a kommunikációt a szolgáltató megvalósítható ASP.NET WebAPI alapon, a kliens tetszőleges alkalmazás lehet a műveletek nem csak primitív típusokat, de összetett, adatátviteli objektumokat (Data Transfer Object, DTO) is közölhetnek az objektumelvű adatok továbbítására legelterjedtebb a JSON (Javascript Object Notation) formátum ELTE IK, Webes alkalmazások fejlesztése 9:2

A kliens Az ASP.NET alapú webszolgáltatásokhoz fogyasztóként az ASP.NET WebAPI Client csomag segítségével férhetünk hozzá A HttpClient típus biztosítja a kapcsolatot HTTP alapú szolgáltatásokhoz mivel a hálózati kommunikáció időigényes, aszinkron függvények segítségével biztosítja a HTTP utasítások futtatását (GetAsync, PutAsync, ) az utasítások eredménye tartalmazza a választ (HttpResponseMessage) amennyiben a művelet sikeres (IsSuccessStatusCode), akkor feldolgozhatjuk a tartalmat (Content) ELTE IK, Webes alkalmazások fejlesztése 9:3

A kliens Pl.: using (HttpClient client = new HttpClient()) // kliens példányosítása { HttpResponseMessage response = await client.getasync("http:// "); // kérés aszinkron végrehajtása if (response.issuccessstatuscode) { HttpContent content = response.content; // tartalom feldolgozása } } // kliens megsemmisítése ELTE IK, Webes alkalmazások fejlesztése 9:4

A kliens adatkezelése A tartalom kezelése objektumorientált módon történik, az adattovábbítás formátumát a rendszer kezeli (ahogy az szolgáltató esetén is) az adatátviteli objektum átalakításának (szérializáció) és visszaalításának (deszérializáció) módja a HTTP fejlécinformációk szerint történik HttpClient GetAsync application/ json ApiController Get Deserialize { } Serialize ELTE IK, Webes alkalmazások fejlesztése 9:5

A kliens adatkezelése ehhez szükséges, hogy az adatátviteli objektum típusa a kliens és szerver oldalon is megegyezzen (pl. egyazon osztálykönyvtárból vannak meghivatkozva) olvasás esetén csak az adat típusát kell megadnunk, pl.: if (response.issuccessstatuscode) { Product myproduct = await response.content.readasasync<product>(); // tartalom feldolgozása } ugyanakkor lehetőségünk van a tartalmat szöveges (ReadAsStringAsync), vagy bináris formátumban (ReadAsByteArrayAsync), illetve adatfolyamként (ReadAsStreamAsync) kezelni ELTE IK, Webes alkalmazások fejlesztése 9:6

A kliens adatkezelése a szérializációt végző típus (MediaTypeFormatter) specializálható, így egyedi üzenetformátumok is kialakíthatóak amennyiben tartalmat is küldünk (pl. POST, DELETE), megadhatjuk annak formátumát, pl.: client.postasync("http:// ", product, new JsonMediaTypeFormatter()); // az adatot JSON formátumra szérializálja megadhatjuk annak formátumát, pl.: vagy közvetlenül a megfelelő formátumú adatküldést is hívhatjuk, pl.: client.postasjsonasync("http:// ", product); // az adatot JSON formátumra szérializálja ELTE IK, Webes alkalmazások fejlesztése 9:7

A kliens konfigurációja A kliensben konfigurálható a címek előtagja (BaseAddress), a kommunikáció időkorlátja (Timeout), az elküldött üzenetek fejlécének tulajdonságai (DefaultRequestHeaders), és azon belül a tartalom formátuma (DefaultRequestHeaders.Accept), pl.: client.defaultrequestheaders.accept.clear(); client.defaultrequestheaders.accept.add( new MediaTypeWithQualityHeaderValue( "application/json")); // a kliens csak a JSON formátumot fogadja el ELTE IK, Webes alkalmazások fejlesztése 9:8

Alapvető adatkezelési műveletek A szolgáltatás sok esetben alapvető adatkezelési műveleteket biztosít, ezek a CRUD műveletek létrehozás (Create), olvasás (Read), módosítás (Update), törlés (Delete) a műveleteknek adott a HTTP megfelelője (létrehozás: POST, olvasás: GET, módosítás: PUT, törlés: DELETE) a válasz kódja létrehozás esetén CREATED (201), többi művelet esetén OK (200), vagy NO CONTENT (204) amennyiben a művelet nem azonnal hajtódik végre, ACCEPTED (202) állapotot jelezhetünk egy RESTful szolgáltatásban a műveleteknek ehhez a sémához kell alkalmazkodnia ELTE IK, Webes alkalmazások fejlesztése 9:9

Kliens oldali adatkezelés A kliens oldali adatkezelést kétféleképpen valósíthatjuk meg: szinkron módon: a kliens és a szerver állapota mindig megegyezik aszinkron módon: a kliens és a szerver állapota eltér, és manuálisan szinkronizálható (mentés, betöltés, frissítés) Az aszinkron adatkezelés előnyös, ha a változtatásainkat nem egyenként, hanem csoportosan szeretnénk elmenteni ehhez kliens oldalon követnünk kell a változásokat állapotjelzőkkel (flag), és megjelölnünk, milyen változtatásokat történtek az adatokon (új, módosított, törölt) ELTE IK, Webes alkalmazások fejlesztése 9:10

Példa Feladat: Valósítsuk meg az utazási ügynökség épületeit karbantartó asztali alkalmazást. a kliens egy WPF alkalmazás lesz (TravelAgency.Admin), amely egy WebAPI szolgáltatáshoz (TravelAgency.Service) fog csatlakozni a kliens alkalmazást MVVM architektúrában készítjük el, ahol a perzisztencia (TravelAgencyServicePersistence) biztosítja a hálózati kommunikációt az adatátvitelhez külön típust hozunk létre (BuiltingDTO), és egy külön osztálykönyvtárba helyezzük el (TravelAgency.Data), amely megosztásra kerül mindkét projekt számára ELTE IK, Webes alkalmazások fejlesztése 9:11

Példa Tervezés (architektúra): «WPF application» Admin «WebAPI application» Service «Class Library» Data ELTE IK, Webes alkalmazások fejlesztése 9:12

Példa Tervezés (szolgáltatás): a szolgáltatásban egy vezérlő (BuildingsController) biztosítja a CRUD műveleteket hozzáadásnál visszaküldjük a hozzáadott épületet módosításnál és törlésnél ellenőrizzük a kapott azonosítót Data::BuildingDTO «property» + CityId() :Int32 + Comment() :String + Features() :Int32? + Id() :Int32 + LocationX() :Double + LocationY() :Double + Name() :String + SeaDistance() :Int32 + ShoreId() :Int32? ApiController Controllers::BuildingsController - _entities :ITravelAgencyEntities + BuildingsController() + BuildingsController(ITravelAgencyEntities) - ~BuildingsController() + DeleteBuilding(Int32) :IHttpActionResult # Dispose(Boolean) :void + GetBuildingForCity(Int32) :IHttpActionResult + GetBuildings() :IHttpActionResult + PostBuilding(BuildingDTO) :IHttpActionResult + PutBuilding(BuildingDTO) :IHttpActionResult -_entities IDisposable «interface» Models:: ITravelAgencyEntities DbContext Models:: TravelAgencyEntities ELTE IK, Webes alkalmazások fejlesztése 9:13

Példa Tervezés (kliens): a kliens aszinkron adatkezelést biztosít, a modell (ITravelAgencyModel) felügyeli a kliensbeli állapotot állapotjelzőkkel (DataFlag), ez alapján tudjuk mentéskor a megfelelő műveletet elvégezni a perzisztencia (ITravelAgencyPersistence) feladata az adatok betöltése, mentése és konvertálása aszinkron műveletekkel az új épületeknek létrehozunk egy ideiglenes azonosítót (a megkülönböztetés végett), amely helyett a szerver visszaad egy végleges azonosítót ELTE IK, Webes alkalmazások fejlesztése 9:14

Példa Tervezés (kliens): «interface» Model::ITravelAgencyModel + CreateBuilding(BuildingDTO) :void + DeleteBuilding(BuildingDTO) :void + LoadAsync() :Task + SaveAsync() :Task + UpdateBuilding(BuildingDTO) :void «property» + Buildings() :IReadOnlyList<BuildingDTO> Exception PersistenceUnavailableException + PersistenceUnavailableException(String) + PersistenceUnavailableException(Exception) «interface» ITravelAgencyPersistence + CreateBuildingAsync(BuildingDTO) :Task<Boolean> + DeleteBuildingAsync(BuildingDTO) :Task<Boolean> + ReadBuildingsAsync() :Task<IEnumerable<BuildingDTO>> + UpdateBuildingAsync(BuildingDTO) :Task<Boolean> TravelAgencyModel TravelAgencyServicePersistence - _client :HttpClient ELTE IK, Webes alkalmazások fejlesztése 9:15

Példa Megvalósítás (TravelAgencyModel.cs): public async Task SaveAsync() { // az állapotjelzőnek megfelelő műveletet // végezzük el switch (_buildingflags[building]) { case DataFlag.Create: result = await _persistence.createbuildingasync(building); break; case DataFlag.Delete: } ELTE IK, Webes alkalmazások fejlesztése 9:16

Példa Megvalósítás (TravelAgencyPersistence.cs): public async Task<Boolean> CreateBuildingAsync( ){ HttpResponseMessage response = await _client.postasjsonasync("api/buildings/", building); // az értékeket azonnal JSON formátumra // alakítjuk building.id = (await response.content.readasasync<buildingdto>()).id; // a válaszüzenetben megkapjuk a végleges // azonosítót } ELTE IK, Webes alkalmazások fejlesztése 9:17

Adatkonverzió Az adatkötés során lehetőségünk van átalakítani (konvertálni) az adatot a megjelenítés és a kötött tartalom között vannak alapértelmezett átalakítások (pl. szöveg/szám) alkalmazhatunk egyedi konverziót (az IValueConverter interfész megvalósításával) cél (címke) függőségi tulajdonság (felirat) adatkötés forrás (szövegdoboz) tulajdonság (szöveg) konverzió ELTE IK, Webes alkalmazások fejlesztése 9:18

Adatkonverzió Az IValueConverter interfész biztosítja a Convert és ConvertBack műveleteket, amelyek elvégzik a transzformációt az átalakítás paraméterezhető (ConverterParameter) figyelembe veszi a nyelvi környezetet (ConverterCulture) cél Convert ConvertBack forrás A konverziót a kötésnél adjuk meg, általában erőforrásból betöltve: {Binding Path=, Converter=, ConverterParameter=, ConverterCulture= } ELTE IK, Webes alkalmazások fejlesztése 9:19

Adatkonverzió Pl.: class StringToIntConverter : IValueConverter // egyszerű szám-szöveg átalakító { public object Convert(object value, ){ return value.tostring(); } // átalakítás szöveggé } public object ConvertBack(object value, ){ return Convert.ToInt32(value); } // átalakítás számmá ELTE IK, Webes alkalmazások fejlesztése 9:20

Adatkonverzió Pl.: <Window xmlns:local="clr-namespace:myapp"> <Window.Resources> <local:stringtointconverter x:key="converter" /> <! az átalakító, mint erőforrás --> </Window.Resources> <TextBox Text="{Binding Path=, Converter={StaticResource converter} }" /> <!-- szövegdoboz, amely az adatkötéshez felhasználja az átalakítót --> ELTE IK, Webes alkalmazások fejlesztése 9:21

Adatkonverzió hibakezelése Az átalakítás során hiba léphet fel (pl. a megadott szöveg nem konvertálható számmá), amelyet megfelelően kell kezelnünk a konvertáláskor nem keletkezhet kivétel amennyiben a cél értékét nem tudjuk létrehozni (a Convert műveletben), akkor jelezzük, hogy nem kell végrehajtani a kötést (Binding.DoNothing) amennyiben a forrás tulajdonságot nem tudjuk beállítani (a ConvertBack műveletben), akkor visszaadjuk a beállítatlan függőségi értéket (DependencyProperty.UnsetValue) a beállítási hiba azonnal jelentkezik a felületen is (alapértelmezetten piros keretben) ELTE IK, Webes alkalmazások fejlesztése 9:22

Adatkonverzió hibakezelése Pl.: class StringToIntConverter : IValueConverter // egyszerű szám-szöveg átalakító { public object ConvertBack(object value, ){ try { return Convert.ToInt32(value); } catch { // elfogjuk a kivételt return DependencyProperty.UnsetValue; } // jelezzük a sikertelen beállítást } // átalakítás számmá } ELTE IK, Webes alkalmazások fejlesztése 9:23

Ellenőrzések adatkonverzióval A hibakezeléssel egybekötött átalakító használható ellenőrzések végrehajtására is nem is szükséges konvertálnia a tartalmat, csupán ellenőrzi az adat meglétét, formátumát Pl.: class EmailCheckConverter : IValueConverter // e-mail formátum ellenőrző átalakító { public object Convert (object value, ){ return value; } // nem végzünk semmilyen átalakítást ELTE IK, Webes alkalmazások fejlesztése 9:24

Ellenőrzések adatkonverzióval } public object ConvertBack(object value, ){ if (value == null!regex.ismatch(value.tostring(), @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA- Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA- Z]\.)+[a-zA-Z]{2,9})$")){ // ha nem egyezik az e-mail formátum // reguláris kifejezésével return DependecyObject.UnsetValue; // akkor jelezzük a hibát } return value; // különben nem csinálunk semmit } ELTE IK, Webes alkalmazások fejlesztése 9:25

Többszörös kötés és konverzió Lehetőségünk van egy függőségi tulajdonságra több tulajdonságot is kötni (MultiBinding) több egyszerű kötés (Binding) gyűjteménye csak megfelelő konverzióval (IMultiValueConverter) jeleníthetőek meg az adatok tömbként fogadja (a kötés sorrendjében) az adatokat, és ugyanebben a sorrendben kell visszaadnia függőségi tulajdonság többszörös adatkötés konverzió tulajdonság tulajdonság ELTE IK, Eseményvezérelt alkalmazások fejlesztése II 9:26

Többszörös kötés és konverzió Pl.: <TextBlock> <TextBlock.Text> <!-- szöveg összetett megadása --> <MultiBinding Converter=" "> <!-- többszörös kötés átalakítóval --> <Binding Path=" " /> <Binding Path=" " /> <!-- tetszőleges sok kötést adunk meg --> </MultiBinding> </TextBlock.Text> </TextBlock> ELTE IK, Eseményvezérelt alkalmazások fejlesztése II 9:27

Többszörös kötés és konverzió Pl.: class MyMultiConverter : IMultiValueConverter { public object Convert(object[] values, ){ // egy tömbben kapjuk meg az értékeket, a // megadott kötések sorrendjében } public object[] ConvertBack(object value, ){ // egy tömbben szolgáltatjuk vissza az // eredményt, ismét a megadott sorrendben } } ELTE IK, Eseményvezérelt alkalmazások fejlesztése II 9:28

Példa Feladat: Valósítsuk meg az utazási ügynökség épületeit karbantartó asztali alkalmazást. a jobb megjelenítés érdekében használjunk adatkonverziót a kliens oldalán, szükség lesz: a tengerpart távolság átalakítására (SeaDistanceConverter) a tengerpart típus átalakítására (ShorteTypeConverter) a jellemzők átalakítására (FeatureConverter, FeatureDisplayConverter) módosítjuk az adatátviteli típust (BuildingDTO) is, hogy az kifejezőbb legyen a megjelenítés számára, és felveszünk két további segédtípust (CityDTO, FeatureDTO) ELTE IK, Webes alkalmazások fejlesztése 9:29

Példa Tervezés (adatátvitel): BuildingDTO + BuildingDTO() + Equals(Object) :Boolean «property» + Id() :Int32 + Name() :String + City() :CityDTO + SeaDistance() :Int32 + ShoreId() :Int32? + Features() :FeatureDTO[] + LocationX() :Double + LocationY() :Double + Comment() :String CityDTO + Equals(Object) :Boolean + ToString() :String «property» + Id() :Int32 + Name() :String FeatureDTO + Convert(Int32?) :FeatureDTO[] + Convert(FeatureDTO[]) :Int32? «property» + Id() :Int32 + IsAvailable() :Boolean ELTE IK, Webes alkalmazások fejlesztése 9:30

Példa Tervezés (kliens): IValueConverter ViewModel::ShoreTypeConverter IValueConverter ViewModel::FeatureDisplayConverter IValueConverter ViewModel::SeaDistanceConverter IValueConverter ViewModel::FeatureConverter - _model :ITravelAgencyModel - _view :MainWindow - _viewmodel :MainViewModel App Application + App() - App_Startup(object, StartupEventArgs) :void - ViewModel_ExitApplication(object, System.EventArgs) :void - ViewModel_MessageApplication(object, MessageEventArgs) :void -_model «interface» Model::ITravelAgencyModel Window View::MainWindow -_view -_model -_viewmodel ViewModel::MainViewModel - _buildings :ObservableCollection<BuildingDTO> - _cities :ObservableCollection<CityDTO> - _currentbuilding :BuildingDTO - _isloaded :Boolean - _model :ITravelAgencyModel - _selectedindex :Int32 ViewModelBase + MainViewModel(ITravelAgencyModel) - OnExitApplication() :void - OnMessageApplication(String) :void «property» + Buildings() :ObservableCollection<BuildingDTO> + Cities() :ObservableCollection<CityDTO> + CreateBuildingCommand() :DelegateCommand + CurrentBuilding() :BuildingDTO + DeleteBuildingCommand() :DelegateCommand + ExitCommand() :DelegateCommand + IsLoaded() :Boolean + LoadCommand() :DelegateCommand + SaveCommand() :DelegateCommand + SelectedIndex() :Int32 + UpdateBuildingCommand() :DelegateCommand «event» + ExitApplication() :EventHandler + MessageApplication() :EventHandler<MessageEventArgs> ELTE IK, Webes alkalmazások fejlesztése 9:31

Példa Megvalósítás (ShoreTypeConverter.cs): public Object Convert(Object value, ) { // ellenőrizzük az értéket // ellenőrizzük a paramétert List<String> shorenames = (parameter as IEnumerable<String>).ToList(); Int32 index = (Int32)value; if (index < 0 index >= shorenames.count) return Binding.DoNothing; } return shorenames[index]; ELTE IK, Webes alkalmazások fejlesztése 9:32

Példa Megvalósítás (MainWindow.xaml): <x:array x:key="shoretypearray"> <system:string>homokos</system:string> </x:array> <viewmodel:shoretypeconverter x:key="shoretypeconverter" /> <DataGridTextColumn Header="Tengerpart" Binding="{Binding ShoreId, Converter={StaticResource shoretypeconverter}, ConverterParameter={StaticResource shoretypearray}}" /> ELTE IK, Webes alkalmazások fejlesztése 9:33

Adatok titkosítása memóriában A teljes biztonsághoz a memóriában lévő kényes tartalmat is titkosítani kell, mivel az is potenciális támadási felület lehetőség szerint csak a feldolgozás időtartamára szerepeljen titkosítatlan információ a memóriában, egyébként kódolva tároljuk Szövegek titkosított kezelésére szolgál a SecureString típus, amely alapvetően titkosítva tárolja a jelszót, és csak lekéréskor (ToString) dekódolja a grafikus felületen a jelszavak titkosított bekérését a PasswordBox biztosítja, a Password tulajdonság feloldja a titkosítást (amely nem függőségi tulajdonság, így nem köthető) ELTE IK, Webes alkalmazások fejlesztése 9:34

Adatok titkosítása memóriában Pl.: <Button Content="Bejelentkezés" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=passwordBox}" /> <!-- magát a jelszóbekérőt adjuk át --> LoginCommand = new DelegateCommand(param => { _model.login(username, (param as PasswordBox).Password); // kiolvassuk a titkosított jelszót } ELTE IK, Webes alkalmazások fejlesztése 9:35

Adatok betöltése az adatbázisba A szolgáltatás adatbázis struktúrája és adatait létrehozhatónak kód segítségével (Entity Framework Code First) adatok betöltéséhez engedélyeznünk kell adatmigrációt a NuGet csomagkezelő konzolban (enable-migrations), ezzel automatikusan létrejön egy betöltő függvény (Configuration.Seed), amely a paraméterben megadott adatbázisba (context) feltölti az adatokat az ASP.NET Identity (EF) adatbázis is kód alapú, így a felhasználók és csoportok létrehozhatóak ezzel a módszerrel mivel a migrációs eszköz osztályokra keres, mindenképpen szükséges az IdentityContext származtatása ELTE IK, Webes alkalmazások fejlesztése 9:36

Adatok betöltése az adatbázisba Pl.: internal sealed class Configuration : { protected override void Seed(MyDbContext context) { // adatbázis feltöltése adatokkal context.customer.add(new Customer { Name = "John Doe" }); context.savechanges(); } ELTE IK, Webes alkalmazások fejlesztése 9:37

Példa Feladat: Valósítsuk meg az utazási ügynökség épületeit karbantartó asztali alkalmazást. adjunk lehetőséget képek megtekintésére, hozzáadására, törlésére a képet fájlból töltjük be, majd átméretezzük (kis és nagy méretben, PNG formátumban) a képeket egyedi azonosítóval látjuk el, valamint az épület azonosítójával a biztonság növelésére az adatkezelést authentikációhoz kötjük (ASP.NET Identity segítségével), így a felhasználónak előbb be kell jelentkezniük az alkalmazásba ELTE IK, Webes alkalmazások fejlesztése 9:38

Példa Tervezés: létrehozunk egy vezérlőt (BuildingImageController), valamint egy adatátviteli típust (ImageDTO) a képkezeléshez a képeket alapvetően byte tömbként kezeljük, a szolgáltatás nem is ismeri azok képi tartalmát a képbetöltést egy segédtípusban (ImageHandler) végezzük a képek megjelenítéséhez átalakítást végzünk (BuildingImageConverter), ami BitmapImage típusra alakítja a tömböt, ezeket Image vezérlővel jelenítjük meg külön nézetbe szervezzük az épület adatainak megadását (BuldingEditorWindow) ELTE IK, Webes alkalmazások fejlesztése 9:39

Példa Tervezés: létrehozunk egy vezérlőt a felhasználó-kezeléshez (AccountController), ebben lehetőséget adunk bejelentkezésre (Login) és kijelentkezésre (Logout) a szolgáltatásban attribútum (Authorize) segítségével korlátozzuk az akciófüggvényekhez való hozzáférést (csak a rendszergazda csoportban lévő felhasználókra) kliens oldalon megjelenik a két új művelet a modellben (LoginAsync, LogoutAsync) a bejelentkezéshez egy külön nézetet (LoginWindow), valamint nézetmodellt (LoginViewModel) hozunk létre ELTE IK, Webes alkalmazások fejlesztése 9:40

Példa Tervezés (szolgáltatás): IDisposable «interface» Models::ITravelAgencyEntities -_entities ApiController BuildingsController ApiController CitiesController AccountController ApiController - _usermanager :UserManager<IdentityUser> - _rolemanager :RoleManager<IdentityRole> + AccountController() - ~AccountController() + Login(String, String) :IHttpActionResult + Logout() :IHttpActionResult # Dispose(Boolean) :void ApiController BuildingImagesController - _entities :ITravelAgencyEntities + BuildingImagesController() + BuildingImagesController(ITravelAgencyEntities) - ~BuildingImagesController() + GetImages(Int32) :IHttpActionResult + GetImage(Int32) :IHttpActionResult + PostImage(ImageDTO) :IHttpActionResult + DeleteImage(Int32) :IHttpActionResult # Dispose(Boolean) :void ELTE IK, Webes alkalmazások fejlesztése 9:41

Példa Tervezés (kliens): ViewModelBase ViewModel::MainViewModel - _buildings :ObservableCollection<BuildingDTO> - _cities :ObservableCollection<CityDTO> - _isloaded :Boolean - _model :ITravelAgencyModel - _selectedbuilding :BuildingDTO - CancelChanges() :void - DeleteBuilding(BuildingDTO) :void - DeleteImage(ImageDTO) :void - LoadAsync() :void + MainViewModel(ITravelAgencyModel) - Model_BuildingChanged(object, BuildingEventArgs) :void - OnBuildingEditingFinished() :void - OnBuildingEditingStarted() :void - OnExitApplication() :void - OnImageEditingStarted(Int32) :void - SaveAsync() :void - SaveChanges() :void - UpdateBuilding(BuildingDTO) :void «event» + BuildingEditingFinished() :EventHandler + BuildingEditingStarted() :EventHandler + ExitApplication() :EventHandler + ImageEditingStarted() :EventHandler<BuildingEventArgs> «property» + Buildings() :ObservableCollection<BuildingDTO> + CancelChangesCommand() :DelegateCommand + Cities() :ObservableCollection<CityDTO> + CreateBuildingCommand() :DelegateCommand + CreateImageCommand() :DelegateCommand + DeleteBuildingCommand() :DelegateCommand + DeleteImageCommand() :DelegateCommand + EditedBuilding() :BuildingDTO + ExitCommand() :DelegateCommand + IsLoaded() :Boolean + LoadCommand() :DelegateCommand + SaveChangesCommand() :DelegateCommand + SaveCommand() :DelegateCommand + SelectedBuilding() :BuildingDTO + UpdateBuildingCommand() :DelegateCommand -_mainviewmodel App - _editorview :BuildingEditorWindow - _loginview :LoginWindow - _loginviewmodel :LoginViewModel - _mainview :MainWindow - _mainviewmodel :MainViewModel - _model :ITravelAgencyModel ViewModel::ImageHandler + OpenAndResize(String, Int32) :Byte[] Application + App() + App_Exit(object, ExitEventArgs) :void - App_Startup(object, StartupEventArgs) :void - MainViewModel_BuildingEditingFinished(object, EventArgs) :void - MainViewModel_BuildingEditingStarted(object, EventArgs) :void - MainViewModel_ImageEditingStarted(object, BuildingEventArgs) :void - ViewModel_ExitApplication(object, System.EventArgs) :void - ViewModel_LoginFailed(object, EventArgs) :void - ViewModel_LoginSuccess(object, EventArgs) :void - ViewModel_MessageApplication(object, MessageEventArgs) :void -_loginview -_loginviewmodel Window View::LoginWindow ViewModelBase ViewModel::LoginViewModel - _model :ITravelAgencyModel - LoginAsync(PasswordBox) :void + LoginViewModel(ITravelAgencyModel) - OnExitApplication() :void - OnLoginFailed() :void - OnLoginSuccess() :void «event» + ExitApplication() :EventHandler + LoginFailed() :EventHandler + LoginSuccess() :EventHandler «property» + ExitCommand() :DelegateCommand + LoginCommand() :DelegateCommand + UserName() :String ELTE IK, Webes alkalmazások fejlesztése 9:42

Példa Tervezés (kliens): Model::TravelAgencyModel - _buildingflags :Dictionary<BuildingDTO, DataFlag> - _buildings :List<BuildingDTO> - _cities :List<CityDTO> - _imageflags :Dictionary<ImageDTO, DataFlag> - _persistence :ITravelAgencyPersistence + CreateBuilding(BuildingDTO) :void + CreateImage(Int32, Byte[], Byte[]) :void + DeleteBuilding(BuildingDTO) :void + DeleteImage(ImageDTO) :void + LoadAsync() :Task + LoginAsync(String, String) :Task<Boolean> + LogoutAsync() :Task<Boolean> - OnBuildingChanged(Int32) :void + SaveAsync() :Task + TravelAgencyModel(ITravelAgencyPersistence) + UpdateBuilding(BuildingDTO) :void «event» + BuildingChanged() :EventHandler<BuildingEventArgs> «property» + Buildings() :IReadOnlyList<BuildingDTO> + Cities() :IReadOnlyList<CityDTO> + IsUserLoggedIn() :Boolean -_persistence «interface» Persistence::ITravelAgencyPersistence Persistence::TravelAgencyServicePersistence - _client :HttpClient + CreateBuildingAsync(BuildingDTO) :Task<Boolean> + CreateBuildingImageAsync(ImageDTO) :Task<Boolean> + DeleteBuildingAsync(BuildingDTO) :Task<Boolean> + DeleteBuildingImageAsync(ImageDTO) :Task<Boolean> + LoginAsync(String, String) :Task<Boolean> + LogoutAsync() :Task<Boolean> + ReadBuildingsAsync() :Task<IEnumerable<BuildingDTO>> + ReadCitiesAsync() :Task<IEnumerable<CityDTO>> + TravelAgencyServicePersistence(String) + UpdateBuildingAsync(BuildingDTO) :Task<Boolean> ELTE IK, Webes alkalmazások fejlesztése 9:43

Példa Megvalósítás (BuildingImagesController.cs): [Authorize(Roles = "administrator")] // csak bejelentkezett adminisztrátoroknak public IHttpActionResult PostImage([FromBody] ImageDTO image) { _entities.savechanges(); return Created(Request.RequestUri + image.id.tostring(), image.id); // csak az azonosítót küldjük vissza } ELTE IK, Webes alkalmazások fejlesztése 9:44

Példa Megvalósítás (ImageHandler.cs): public static Byte[] OpenAndResize(String path, Int32 height) { BitmapImage image = new BitmapImage(); // kép betöltése image.begininit(); image.urisource = new Uri(path); image.decodepixelheight = height; // megadott méretre image.endinit(); ELTE IK, Webes alkalmazások fejlesztése 9:45

Példa Megvalósítás (ImageHandler.cs): PngBitmapEncoder encoder = new PngBitmapEncoder(); // átalakítás PNG formátumra encoder.frames.add(bitmapframe.create(image)); } using (MemoryStream stream = new MemoryStream()) // átalakítás byte-tömbre { encoder.save(stream); return stream.toarray(); } ELTE IK, Webes alkalmazások fejlesztése 9:46