Upload
barna-trajber
View
137
Download
2
Embed Size (px)
Citation preview
Budapesti Műszaki és Gazdaságtudományi Egyetem 1117 Budapest, Magyar tudósok körútja 2. Q épület, B szárny, II. em. 207.
Villamosmérnöki és Informatikai Kar Telefon: +36/1/463-2870, +36/1/463-3716 Fax: +36/1/463-2871
Automatizálási és Alkalmazott Informatikai Tanszék http:/www.aut.bme.hu, H-1521 Budapest
SZAKDOLGOZAT FELADAT
Trajber Barna Viktor
szigorló mérnökinformatikus hallgató részére
Költségnyilvántartó keretrendszer .NET alapon
Amikor egy háztartás, vagy kisvállalat költségvetését szeretnénk nyilvántartani,
kézenfekvő, hogy elektronikusan tároljuk a kiadásokat és bevételeket, a
számlabefizetéseket. Ez lehetővé teszi az egyszerű, biztonságos tárolást, a könnyű
adatbevitelt, különböző szűrések és rendezések eredményeinek megtekintését.
A szakdolgozat célja egy kiadás nyilvántartó alkalmazáscsalád fejlesztése, melyet
a költségkategóriák testreszabásával akár otthoni, illetve kisvállalati környezetben is
használhatunk. Az elkészült keretrendszernek tartalmaznia kell egy szerver oldali
alkalmazást, melynek elsődleges feladata, hogy kommunikáljon a különböző
platformokon megvalósított kliens alkalmazásokkal.
A hallgató feladatának a következőkre kell kiterjednie:
Tervezze meg a keretrendszer felépítését és adatbázis sémáját!
Készítsen egy szerveralkalmazást, amely WCF szolgáltatást nyújt a kliensek felé!
Készítsen egy mobil kliens alkalmazást Windows Phone 8 platformra!
Készítsen egy vékony kliens alkalmazást ASP.NET MVC keretrendszer
segítségével!
Tanszéki konzulens: Dr. Asztalos Márk
Budapest, 2013. október 10.
Dr. Vajk István
egyetemi tanár
tanszékvezető
2
Budapesti Műszaki és Gazdaságtudományi Egyetem
Villamosmérnöki és Informatikai Kar
Automatizálási és Alkalmazott Informatikai Tanszék
Trajber Barna Viktor
KÖLTSÉGNYILVÁNTARTÓ
KERETRENDSZER .NET ALAPON
KONZULENS
Dr. Asztalos Márk
BUDAPEST, 2014
Tartalomjegyzék
Összefoglaló ..................................................................................................................... 6
Abstract ............................................................................................................................ 7
1 Bevezetés ....................................................................................................................... 8
2 Technológiai ismertető .............................................................................................. 10
2.1 ASP.NET MVC 4 ................................................................................................. 10
2.1.1 ASP.NET architektúra ................................................................................... 10
2.1.2 MVC architektúra .......................................................................................... 11
2.1.3 Az oldal életciklusa ........................................................................................ 16
2.1.4 MVC és WebForms összehasonlítása ............................................................ 16
2.2 Vizuális komponensek .......................................................................................... 19
2.2.1 Twitter Bootstrap ........................................................................................... 19
2.2.2 Telerik Kendo UI ........................................................................................... 20
2.3 Windows Phone 8 ................................................................................................. 22
2.3.1 Felület ............................................................................................................ 22
2.3.2 Az alkalmazás életciklusa .............................................................................. 23
2.3.3 Hardver követelmények ................................................................................. 24
2.3.4 Fejlesztés Windows Phone 8 platformra ....................................................... 24
2.4 WCF ...................................................................................................................... 30
2.4.1 WCF architektúra és fogalmak ...................................................................... 30
2.4.2 Üzenetcsere minták ........................................................................................ 30
2.4.3 Végpontok ...................................................................................................... 30
2.4.4 WCF és WebAPI összehasonlítása ................................................................ 33
3 Specifikáció ................................................................................................................. 35
3.1 Szoftver célja ........................................................................................................ 35
3.2 Funkciók ............................................................................................................... 36
3.3 Felhasználói szerepkörök ...................................................................................... 37
3.4 Architektúra .......................................................................................................... 38
4 Megvalósítás ............................................................................................................... 40
4.1 Adatbázis tervezése ............................................................................................... 40
4.1.1 Code First vagy Database First? .................................................................... 40
4.1.2 Az adatbázis séma .......................................................................................... 41
4.1.3 Táblák és attribútumok .................................................................................. 43
4.1.4 Megjegyzések az adatmodellhez ................................................................... 44
4.2 Szerver és a szolgáltatás ....................................................................................... 45
4.2.1 Üzleti logika ................................................................................................... 45
4.3 Kliens alkalmazások ............................................................................................. 51
4.3.1 Mobil kliens (WP8) ....................................................................................... 51
4.3.2 Web kliens (ASP.NET MVC) ....................................................................... 58
5 Összefoglalás ............................................................................................................... 65
5.1 Továbbfejlesztési lehetőségek .............................................................................. 66
Irodalomjegyzék ............................................................................................................ 67
Függelék: Kliensek egyéb funkciói .............................................................................. 69
HALLGATÓI NYILATKOZAT
Alulírott Trajber Barna Viktor, szigorló hallgató kijelentem, hogy ezt a szakdolgozatot
meg nem engedett segítség nélkül, saját magam készítettem, csak a megadott forrásokat
(szakirodalom, eszközök stb.) használtam fel. Minden olyan részt, melyet szó szerint,
vagy azonos értelemben, de átfogalmazva más forrásból átvettem, egyértelműen, a forrás
megadásával megjelöltem.
Hozzájárulok, hogy a jelen munkám alapadatait (szerző(k), cím, angol és magyar nyelvű
tartalmi kivonat, készítés éve, konzulens(ek) neve) a BME VIK nyilvánosan hozzáférhető
elektronikus formában, a munka teljes szövegét pedig az egyetem belső hálózatán
keresztül (vagy hitelesített felhasználók számára) közzétegye. Kijelentem, hogy a
benyújtott munka és annak elektronikus verziója megegyezik. Dékáni engedéllyel
titkosított diplomatervek esetén a dolgozat szövege csak 3 év eltelte után válik
hozzáférhetővé.
Kelt: Budapest, 2014. 05. 15.
...…………………………………………….
Trajber Barna Viktor
6
Összefoglaló
Az életünk részét képző gyakori pénzáramlások szinte lehetetlenné teszik, hogy
fejben tartsuk az összes felmerülő anyagi tételt. A különböző számlabefizetések,
vásárlások, váratlan kiadások vagy a fizetések és egyéb bevételi források nyilvántartása
közben könnyen elveszíthetjük a fonalat. Eljuthatunk arra a pontra, amikor azt érezzük,
hogy szükségszerű lenne egy helyen tárolni a költségeinket. Napjaink informatikai
megoldásai ezt könnyedén lehetővé teszik, akár széles körű platform támogatottság
mellett is.
Munkám során egy olyan költségnyilvántartó keretrendszert hoztam létre,
melyben a felmerülő kiadásokat és bevételeket hatékonyan kezelhetjük elektronikusan,
rendszerezetten tárolva és áttekinthető formában megjelenítve a különböző kimutatások
és szűrések segítségével. A költségkategóriák testreszabásával az igényeknek
megfelelően tudjuk kialakítani a rendszer profilját, lehetővé téve, hogy akár személyes
vagy kisvállalati környezetben is alkalmazható szoftverrel rendelkezzünk. A felhasználói
szintek bevezetése tette lehetővé, hogy csak az adminisztrátorok legyenek képesek
beavatkozni a kategóriák kezelésébe, így az egyszerű felhasználóknak csupán a
költségeik nyilvántartásával kell foglalkozniuk.
A keretrendszer .NET alapokon nyugszik, szolgáltatás-orientált (SOA)
architektúrát valósítva meg. A rendszer magját egy WCF szolgáltatás adja, mely
elérhetővé teszi az üzleti logikát a kliensek számára, gondoskodva az adatok
feldolgozásáról és tárolásáról is. Az implementáció során két kliens alkalmazás készült el
különböző platformokra: egy vékony kliens az ASP.NET MVC keretrendszerre építve,
melynek a felületét a Twitter Bootstrap és Telerik Kendo UI csomagok segítségével
készítettem el, illetve egy Windows Phone 8 alapú mobil klienst is fejlesztettem.
A rendszer egyszerűen bővíthető újabb kliens alkalmazások hozzáadásával,
hiszen a szolgáltatással összeköttetésben állva a klienseknek csupán a megfelelő
felhasználói felületet és a platform specifikus részeket kell megvalósítaniuk.
7
Abstract
Cash flows form an important part of our lives but it is almost impossible to keep
in mind all the financial items that arise. You can easily lose the thread between different
kinds of bill payments, purchases, unexpected expenses or salaries. We may get to the
point when we feel that it is necessary to find a reliable place to store the costs. Today's
IT solutions allow us to make these tasks easy even with a wide range of platform support.
In my work I have created an expense manager framework that can efficiently
manage the expenses and incomes electronically in a systematic way and allow us to
browse the items using various reports and filters. We can determine the system profile
by the customization of the cost categories according to our needs, allowing this software
to be used either for personal purposes or in a small business environment. The
introduction of user roles made it possible that only administrators are able to take part in
the handling of categories so the basic users have to deal only with their costs
management.
The constructed framework presented in this thesis is based on .NET and it
implements a service-oriented architecture (SOA). The core of the system is a WCF
service that provides access to the business logic for the clients, ensuring the processing
and storage of data as well. I have created two different client applications: a web client
based on ASP.NET MVC extended by Twitter Bootstrap and Telerik Kendo UI packages,
and a mobile client for Windows Phone 8 platform was also developed.
The system can be easily extended by adding new client applications that are
connected to the service so we only need to develop the appropriate user interface and
platform specific parts.
8
1 Bevezetés
Egy háztartásban figyelemmel követni a havi bevételeteket, illetve kiadásokat már
rövid távon is meglehetősen összetett feladattá válhat. A probléma támogatásához precíz,
ugyanakkor egyszerűen kezelhető elektronikus keretrendszer fejlesztése úgy gondolom,
hogy indokolt és kihívást jelentő feladat.
A szakdolgozatom témája egy olyan költségnyilvántartó keretrendszer
létrehozása volt, melyben áttekinthető képet kaphatunk a napi költségekről és
bevételekről a különböző szűrések, kimutatások segítségével. A költség kategóriák
testreszabásával otthoni és kisvállalati környezetben is egyaránt használható alkalmazást
kellet létrehoznom. A rendszerben tehát szükséges a felhasználói szintek
megkülönböztetése, hogy az adminisztrátor az igényeknek megfelelően testre tudja
szabni a nyilvántartandó kiadások és bevételek kategóriáit, ezzel biztosítva a minél
teljesebb körű felhasználhatóságot. A rendszer felhasználói pedig élvezhetik a
keretrendszer nyújtotta kényelmet, melyben hatékonyan el tudják tárolni a felmerülő
anyagi tételeket.
Napjainkban minden szükséges technikai eszköz adott egy valóban jól
használható költségnyilvántartó szoftver megalkotásához. Az „okostelefonok” növekvő
népszerűségével költségeinket akár kézben is tarthatjuk. A célom egy olyan
bonyolultságú keretrendszert készíteni, mely egyszerre asztali, mobil, valamint webes
környezetben is megállja a helyét, könnyedén bővíthető újabb kliens alkalmazásokkal,
ezáltal szélesebb felhasználói közönséget célozva meg.
A tervezés során kiemelt hangsúlyt fektettem arra, hogy egy olyan keretrendszert
valósítsak meg, mely stabil, megbízható alapot nyújt az esetleges későbbi funkcionális
bővítések számára, egyszerűen használható és teljes értékű funkcionalitás nyújt az összes
kliens platformra. A fejlesztéshez plusz motivációt adott, hogy lehetőségem volt
alaposabban megismerkedni különböző .NET-es technológiákkal, hasznos csomagokkal
és osztálykönyvtárakkal.
9
A következő fejezetben egy technológiai ismertető keretében rövid áttekintést
kaphatunk a keretrendszer elkészítése során felhasznált technológiákról és eszközökről,
helyenként összehasonlítva alternatív .NET-es megoldásokkal. Először a vékonykliens
alapjául szolgáló ASP.NET MVC [1] keretrendszert mutatom be, majd az ehhez
kapcsolódóan felhasznált Twitter Bootstrap [12] és Telerik Kendo UI [14] vizuális
csomagokat ismertetem. A további részekben szót ejtek a Windows Phone 8 [15] mobil
platformról, melyre a mobil kliens alkalmazás készült; legutoljára pedig az üzleti logikát
biztosító WCF (Windows Communication Foundation) [29] szolgáltatás technológiájával
ismerkedhetünk meg.
A 3. fejezetben a rendszer specifikációját mutatom be. Először szó esik a szoftver
fejlesztése során kitűzött célokról, majd a feladat pontosítása érdekében a kötelezően
megvalósítandó funkciókat tekinthetjük át. Utolsó lépésként a felhasználói szinteket és a
rendszer architektúráját ismertetem.
A 4. fejezetben a megvalósított keretrendszer fejlesztésének néhány lépését
tekinthetjük át, melyben először az adatbázis tervezése során keletkezett adatmodellt
ismertetem. A további alfejezetekben a szolgáltatás üzleti logikáját és az egyes kliens
alkalmazások felépítését mutatom be az összetettebb implementációs részleteket
kiemelve. Mind a két elkészül kliens esetén a felhasználó kezelés ismertetésével kezdem,
majd pedig a platformra jellemző egyedi megoldásokat részletezem.
Az utolsó fejezetben összefoglalom a szakdolgozatomban elért eredményeket és
beszámolok a továbbfejlesztési lehetőségekről is.
10
2 Technológiai ismertető
Első lépésként a szakdolgozatban használt lényegesebb technológiákat
ismertetem egy rövid áttekintés erejéig. Az itt szereplő technológiák a .NET világában
ismertek, így a célom, hogy néhány érdekesebb részletet kiemeljek.
Először a kliens alkalmazások fejlesztéséhez használt eszközöket mutatom be, így
szó esik az ASP.NET MVC [1] keretrendszerről mely a web alkalmazásom alapja. Ezt
követően a weboldal készítése során felhasznált vizuális komponenseket ismertetem.
Továbbiakban a Windows Phone 8 [15] mobil platformot is áttekinthetjük, melyre a
mobil klienst fejlesztettem, a felhasznált csomagokkal és osztálykönyvtárakkal együtt. A
kommunikáció megteremtéséhez a szolgáltatás és a kliens alkalmazások között a WCF
[29] technológiát használtam, így legutoljára ezzel ismerkedhetünk meg.
2.1 ASP.NET MVC 4
Az ASP.NET MVC 4 keretrendszer segítségével jól skálázható web
alkalmazásokat készíthetünk, az ASP.NET, illetve az egész .NET keretrendszer erejére
építve a bevált tervezési minták használatával.
2.1.1 ASP.NET architektúra
A keretrendszer alapját képző ASP.NET architektúráját az alábbi ábrán
tekinthetjük meg.
A technológia blokksémán
látható, hogy az egész MVC az
ASP.NET-re épül, hasonlóan a zöld
sávban levő többi technológiához. Az
ASP.NET alapvetően 4 különböző
web fejlesztési irányt kínál
számunkra: Single Page Apps (SPA)
[2] , Web Pages [3], MVC és a Web
Forms [4], kiegészítve 2 féle szolgáltatással: Web API [27] és a SignalR [6].
2-1. ábra: ASP.NET technológia blokkséma [7]
11
A Single Page Applications (SPA) az interaktivitásra és felhasználói élmény
fokozására helyezi a hangsúlyt a kliens oldali szkriptek jelentősebb szerepvállalásával, a
HTML 5, CSS 3 és különböző JavaScript keretrendszerek használatával [2].
A Web Pages a Razor szintaxis erejét használja ki, hogy gyorsan fejleszthető,
könnyen járható utat biztosítson dinamikus web tartalmak előállítására a szerver oldali
kódok HTML-be ágyazásával [3].
A Web Forms használatával a már bevált fogd-és-vidd (drag-and-drop)
módszerrel, eseményvezérelten hozhatunk létre dinamikus oldalakat. A tervezői felület
és sok-sok vezérlő, valamint komponens segítségével gyorsan hozhatunk létre a
felhasználói felület által vezérelt oldalakat. A Web Forms-ról hamarosan több szó is esik
az MVC-vel való összehasonlítás során (2.1.4-es fejezetben).
A szolgáltatások közül a SignalR egy új osztálykönyvtár az ASP.NET fejlesztők
számára, mely segítségével egyszerűen fejleszthetünk valós idejű web alkalmazásokat.
Kétirányú kommunikációt tesz lehetővé a kliens és a szerver között, a szerverek tehát
azonnal tudják szolgáltatni a szükséges tartalmat, amint az elérhetővé válik. A
technológia a Web Socket-ekre épít, azonban a régebbi böngészők támogatása érdekében
képes egyéb technikákat is használni, további API-kat kínálva az összeköttetés
menedzselésére: kapcsolatok csoportosítása, kapcsolódási események és hitelesítés [6].
A WebAPI-ról a 2.4.4-es fejezetben olvashatunk bővebben, ahol összehasonlítom
a WCF nyújtotta szolgáltatással.
Az ASP.NET MVC keretrendszer nyílt forráskódú és rendkívül gyors ütemben
fejlődik. A szakdolgozatomban a 4-es verziót használtam, ugyanis ehhez volt csak Telerik
Kendo UI [14] támogatásom, azonban időközben már az 5-ös verzió is megjelent. A
Telerik Kendo UI egy fizetős kiegészítő csomag számtalan webes komponenst
tartalmazva, melyek használatával modern és látványos felhasználói felületeket
alakíthatunk ki (bővebben a 2.2.2 fejezetben).
2.1.2 MVC architektúra
Az ASP.NET MVC segít csökkenteni egy web alkalmazás komplexitását azzal,
hogy három rétegre különíti el az alkalmazást: Model (modell), View (nézet) és
Controller (vezérlő) részekre. Az MVC minta előnye, hogy a komponensei izoláltak, azaz
jól el vannak különítve egymástól. Minden lehetőségünk adott, hogy az alkalmazás
12
felelősségi köreit jól elszeparáltan tudjuk implementálni (Separation of Concerns1) és
szakítsunk a régi, mindent egy helyre zsúfoló megoldásokkal. A tervezésben és később a
megvalósításban is nagy segítség lehet, ha kialakított egységek külön-külön tovább
tervezhetőek, esetleg önmagukban is kivitelezhetőek, lecserélhetők és tesztelhetők. [7]
2-2. ábra: Az ASP.NET MVC keretrendszer komponensei [5]
A továbbiakban az MVC architektúra résztvevőit ismertetem.
Model (modell)
Összetartozó adatok halmaza. A modell az adatspecifikációja annak a
kapcsolatnak, ami az MVC keretrendszer View és a Controller elemei között végbemegy.
Gyakran a modell objektumok az állapotukat adatbázisból nyerik és ott is tárolják. Kis
alkalmazásokban a modell gyakran csak fogalmilag létezik, nem pedig fizikailag.
Például, ha az alkalmazásunk az adatbázisból olvas ki adatokat és azt elküldi a nézet
számára mindenféle módosítás nélkül, akkor nincs szükség erre a köztes rétegre. [5]
Fontos, hogy a modell osztályban definiált tulajdonságok (propertyk) jól legyenek
elnevezve, ugyanis ha ebből az osztályból egy példány valamely nézetnek a modellje lesz,
akkor abból a felhasznált HTML helperek segítségével a generált HTML elemek
elnevezései (name) és azonosítói (id) a tulajdonságok neveiből fognak képződni. Tehát
egy név megválasztásánál nemcsak a .NET/CIL2 elnevezési szabályoknak kell
megfelelnünk, hanem a HTML attribútumokra is legyünk tekintettel. [7]
1 Separation of Concerns – Egy tervezési alapelv arra, hogy szétválasszunk a teljes forráskódot
különálló részekre, ahol minden egyes szekciónak meghatározott felelőssége van.
2 CIL (MSIL) – Common Intermediate Language. A legalacsonyabb szintű programozási nyelv a
.NET keretrendszerben és a Common Language Infrastructure-ben. Azok a nyelvek, melyek a .NET
keretrendszert használják, a CIL-re fordítanak, ami végül a kezelt kódra fordul.
13
A modellünket bővíthetjük viselkedéssel is. Ide kerülhetnek olyan tulajdonságok,
melyek számított értékként funkcionálnak vagy attribútumokkal vannak dekorálva,
amivel szabályozzák a megjelenést. Az egyszerűbb üzleti logikát is megvalósíthatjuk a
modellben, kicsit felszabadítva ezzel a vezérlőt. Természetesen nagyobb rendszereknél,
komplex üzleti logika esetén kerülendő ez a megoldás, ilyenkor a kontrollerben vagy még
inkább egy szolgáltatásban érdemes megvalósítani az üzleti logikát.
Validáció (érvényesítés)
Az alábbi példa egy egyszerű modell osztály, ami validációs attribútumok
segítségével segít az adatérvényesítésben, illetve a megjelenést szabályozó attribútumok
segítségével formálja a generált HTML elemeket:
public class ChangePasswordModel { private const string validationErrorMessage = "{0} must be {2} to {1} characters long!"; // . . . Other properties [Required] [Display(Name = "New password")] [DataType(DataType.Password)] [StringLength(25, ErrorMessage = validationErrorMessage, MinimumLength = 3)] public string NewPassword { get; set; } [Required] [Display(Name = "New password again")] [Compare("NewPassword", ErrorMessage = "Passwords are not match")] [StringLength(25, ErrorMessage = validationErrorMessage, MinimumLength = 3)] public string PasswordAgain { get; set; } }
A Required attribútum segítségével jelezhetjük, hogy ez az érték kötelezően
kitöltendő egy HTML form elküldése esetén. A Display attribútum Name
tulajdonságának értéke a modellből generált HTML címke (<label>) szövege lesz. A
Compare segítségével két property mező tartalmát hasonlíthatjuk össze és csak akkor
érvényes a validáció, ha a kettő tulajdonság értéke megegyezik. A StringLength
használatával a szöveg maximális és minimális hosszát szabhatjuk meg. A DataType
attribútumok HTML 5 beviteli mezőtípusokat generálnak, aminek a validálása a
böngészőre van bízva. A valódi, MVC által kezelt validációs megoldásokat a DataType
attribútum leszármazottjai biztosítják (pl. EmailAddressAttribute,
PhoneAttribute, EnumDataTypeAttribute stb.).
14
A validációs attribútumok listáját az alábbi táblázatban figyelhetjük meg:
Lehetőségek .NET 4.0 esetében További attribútumok .NET 4.5 alatt
ValidationAttribute
CompareAttribute (System.Web.Mvc)
CustomValidationAttribute
DataTypeAttribute
EnumDataTypeAttribute
RangeAttribute
RegularExpressionAttribute
RequiredAttribute
StringLengthAttribute
RemoteAttribute
ValidationAttribute
CompareAttribute (DataAnnotations)
MaxLengthAttribute
MinLengthAttribute
MembershipPasswordAttribute
DataTypeAttribute
CreditCardAttribute (+Microsoft.Web.Mvc)
EmailAddressAttribute (+Microsoft.Web.Mvc)
FileExtensionsAttribute (+Microsoft.Web.Mvc)
PhoneAttribute
UrlAttribute (+Microsoft.Web.Mvc)
1. táblázat: Validációs attribútumok a .NET-ben [7]
View (nézet)
A nézet felelős azért, hogy előállítsa a választ a böngésző számára, legyen az akár
egy HTML, pdf vagy excel dokumentum. Más megfogalmazásban mondhatjuk azt is,
hogy a nézet felelőssége, hogy a modell adatait megjeleníthető formára transzformálja
[9]. A View tulajdonképpen egy sablon (template) a válasz előállításához. A statikus
szakaszok HTML nyelvi elemekből épülnek fel, míg az „üres helyeket”, azaz a dinamikus
adatokat a Controller tölti ki a Model alapján. Alapértelmezetten két sablon nyelvet
(ViewEngine) is használhatunk a nézetek leírásához az MVC 3-as verziója óta, melyeket
azonban ki is terjeszthetünk [8]:
ASPX (.aspx): az ASP.NET WebForms hagyományos <% %> markerek közé zárt
szintaxisa, ami egy régi örökség:
<ul id="products"> <% foreach (var p in products) { %> <li><%=p.Name %> ($<%=p.Price %>)</li> <% } %> </ul>
Razor (.cshtml/.vbhtml): Jelenleg ez az ajánlott szintaxis az MVC-hez:
<ul id="products"> @foreach (var p in products) { <li>@p.Name ([email protected])</li> } </ul>
Megfigyelhető, hogy a Razor szintaxisa sokkal letisztultabb, kevesebb jelölőre
van szükség, és a kód blokk végét nem kell külön jelölni, ellentétben a ’<% %>’
szintaxissal. A web kliensem fejlesztése során a Razor-t használtam a nézetek leírására.
15
Controller (vezérlő)
A vezérlő a böngésző felől érkező felhasználói kérések feldolgozását végzi, majd
az előállított választ visszaküldi valamely nézetnek. A vezérlő úgy működik, mint egy
koordinátor a nézet és a modell között, valójában az oldal generálás lelke [9].
Előfordulhat, hogy nincs modell definiálva, illetve olyan is, hogy View sem, de vezérlő
és action nélkül nem megy. Névkonvenció alapján dől el, hogy melyik View template
lesz az, ami sablonként fog szolgálni a dinamikus HTML tartalom előállításához. Ezen
az osztályok nevének hagyományosan Controller-el kell végződnie (pl.
AccountController) és a Controller ősosztályból öröklődnek. Az itt található
függvényeket, melyek az ActionResult ősből származó típussal térnek vissza, action-
öknek hívjuk és a feladatuk, hogy kiszolgáljanak egy-egy kérést.
Több lehetőségünk is van arra, hogy egy vezérlőhöz tartozó nézet számára
biztosítsuk az adatokat:
Modell: A legnyilvánvalóbb módja az adatok továbbításának. A Controller
ősosztályon levő View vagy PartialView metódus paramétereként átadhatjuk
kívánt modellt. A tárolási helye a ViewData-ban van.
HttpContext.Items[] gyűjtemény: Kulcs-érték párokat tároló dictionary.
Ideiglenes tárolási lehetőség, ami átível egy kérés feldolgozásának az életciklusán,
így már a global.asax-ban is használhatjuk. Nem MVC specifikus lehetőség, az
alap ASP.NET keretrendszer biztosítja ezt a gyűjteményt számunkra.
ViewData, ViewBag és a TempData: A ViewData egy szöveg (string, key) –
objektum (object, item) típusú dictionary, így az elemeit nem érhetjük el
típusosan, kénytelenek vagyunk az objektumot konvertálni. Tartalma a HTML
oldal generálása után elvész, azonban nem csak a vezérlőből, hanem a nézetekből
is elérhető a kérés feldolgozása során. A ViewBag a ViewData dinamikus
típusú párja (dynamic), ahol az egyes elemeket tulajdonságok formájában,
típusosan érhetjük el, így ennek a használata jóval kényelmesebb. A TempData a
ViewData-hoz hasonló dictionary, azonban a tartalma a teljes kérés feldolgozás
során elérhető, mert a Session objektumba van ágyazva.
16
2.1.3 Az oldal életciklusa
Az MVC-nél az oldal életciklusát a böngészőből érkező kérés (request) indítja el.
A keretrendszer ezt a request-et egy vezérlőhöz juttatja (amit az URL-ből a route
konfigurációnak megfelelőn választ ki), annak is egy metódusához, azaz egy action-höz.
Ez a metódus létrehozza a modell példányt, ha szükséges, majd meghatározza, hogy a
modell alapján az MVC melyik View-t használja fel a böngészőnek küldendő válasz
létrehozásához. Az alábbi ábra vázlatosan szemlélteti egy böngésző felől érkező kérés
életciklusát az MVC keretrendszerben:
2-3. ábra: ASP.NET MVC kérésfeldolgozás vázlata [7]
2.1.4 MVC és WebForms összehasonlítása
Fontos megjegyezni, hogy míg a WebForms – a szintén Microsoft-os – Active
Server Pages (ASP) technológiát hivatott leváltani, addig az MVC nem a WebForms
leváltásaként jött létre, hanem egy újabb alternatívaként arra, hogy ASP.NET weboldalt
készítsünk.
A Web Forms alapötlete arra épült, hogy közel hozzák a Windows
Forms/MFC/Delphi programozókat a web fejlesztéshez, ugyanis az asztali fejlesztői
környezetben már megszokott fogd-és-vidd módszerrel gyorsan kialakíthatjuk a felületet,
gazdag szerveroldali komponensek segítségével és eseményvezérelt támogatással. A
webes környezetben eleinte nagyon csábító ajánlat volt, hogy nincs szükségünk
különösebb HTML, JavaScript tudásra, hogy előállítsunk egy komplex web alkalmazást.
Az alábbi táblázatban összehasonlítom a két ASP.NET-re épülő technológiát pár
szempont alapján:
17
ASP.NET Web Forms ASP.NET MVC
Szerver
oldali
vezérlők
Az ASP.NET szerver oldali
vezérlők a böngészőtől függően a
megfelelő HTML és JavaScript
elemeket generálják számunkra,
hogy egységesen nézzenek ki a
vezérlőink. Sok vezérlő adatkötést
is támogat, amivel még
kényelmesebbé válik a
használatuk.
Az MVC-ben egyáltalán nem
találhatók szerver oldali vezérlők, a
kliens oldali szabványos HTML
elemeket és az így kialakított
vezérlőket támogatja.
Természetesen használhatunk külső
féltől származó komponenseket is,
mint pl. a Telerik Kendo UI [14].
Állapot
megőrzés
A ViewState minden egyes
vezérlőről eltárolja az utolsó
állapotát egy láthatatlan mezőbe
csomagolva (hidden input).
Az MVC-ben nincs ViewState,
teljes mértékben ránk van bízva a
vezérlők állapotának a mentése
(hidden HTML mező, localstorage
stb.)
Esemény-
vezérelt
programo-
zási modell
A web fejlesztőnek nem kell
törődnie, hogy éppen POST, vagy
GET http metódus kezeli a
felhasználói interakciót. Csupán
felrak egy vezérlőt a
tervezőfelületre, és valamely
eseményét a vezérlőnek
megvalósítja a mögöttes
kódfájlban (code behind).
Az MVC egy teljesen más
architektúra szerint épül fel, nem
eseményvezérelt módon. A nézeten
található HTML elemeket a kliens
oldali szkriptek segítségével
kezeljük, innen továbbíthatjuk az
adatokat egy Controller action-
jéhez, illetve kérhetünk le további
HTML részleteket a szervertől.
Projekt ar-
chitektúra
A Web Forms világában nincs
megszabott projekt struktúra az
alkalmazások készítéséhez, így
magunk választhatjuk meg, hogy
milyen minta szerint szeretnénk
csoportosítani a rétegeket. A
probléma, hogy a
legkézenfekvőbb megoldás, ha a
felülethez tartozó mögöttes
kódfájlban írjuk az alkalmazás
logikát ezzel teljesen összekötve a
felhasználói felületet (UI) az
üzleti logikával.
Az MVC kiköveteli az egyes
rétegek különválasztását,
rendszerbe szervezését, melyet
kiegészítve a tervezési minták
használatával elkerülhetjük a
komplex, átláthatatlan, egymással
szorosan összefüggésben levő
kódokat.
Egység
tesztek
(Unit
Testing)
A mögöttes kód általában sok
eseménykezelőt tartalmaz, amik
nehézkesen tesztelhetők. A
mostanában népszerű Test Driven
Mivel a vezérlők (Controller-ek)
egy külön osztályban találhatók és
nem kapcsolódnak szorosan egy
nézethez, így a funkcionalitás, az
üzleti logika egyszerűen tesztelhető,
ezzel megfelelve a TDD fejlesztési
elveknek is.
18
Development (TDD)3 fejlesztési
metódusban azonban különösen
fontos lenne a tesztelhetőség
minél hatékonyabb támogatása.
Teljesít-
mény
A ViewState az oldalon tárolódik,
ezzel növelve az oldal méretét,
így teljesítmény szempontjából
nem túl hatékony.
A ViewState hiányának
köszönhetően nincs automatikus
állapot kezelés, rajtunk múlik, hogy
mit szeretnénk megőrizni a
következő kérésig. Ennek
következtében gyorsabbak lehetnek
az oldalaink is.
Keresőop-
timalizálás
Az URL-ek fix ASPX
erőforrásokra mutatnak, query
string-ekkel dekorálva. Ez nem
felhasználóbarát és sérti a SEO
(Search Engine Optimization)
[10] előírásokat.
Gazdag URL útvonal építési
lehetőségek állnak
rendelkezésünkre, melyek
támogatják a RESTful interfész
kialakítását, ezáltal megfelelve a
keresőoptimalizálási elveknek is.
Párhuzamos
fejlesztés
Az ASPX oldalak szorosan
kapcsolódnak a mögöttes
kódfájlhoz, ezért körülményes
lehet, ha két külön fejlesztő
egyszerre akar egyazon nézeten és
a hozzá tartozó vezérlő logikán
dolgozni.
Az MVC rétegei gyengén függnek
össze egymással és így
megvalósítható az, hogy egy adott
funkcióhoz kapcsolódóan külön-
külön fejlesztő dolgozik a Model,
View és Controller rétegeken.
HTML kód
kezelhető-
sége
Sokszor nem tudjuk, hogy
pontosan milyen HTML kód
generálódik egy-egy vezérlőből,
így nehézkes együttműködni a
kliens oldali JavaScript
keretrendszerekkel, mint pl. a
JQuery [36].
Mivel az MVC a tisztán HTML
vezérlőkre és a kliens oldali
szkriptekre épít, így egyszerűen
együttműködhetünk a kliens oldali
keretrendszerekkel is.
2. táblázat: Az ASP.NET WebForms és MVC összehasonlítása [11]
Megvan tehát mindkét technológiának az előnye és hátránya, azonban az MVC
segítségével úgy gondolom, hogy jobban meg tudunk felelni a felhasználók elvárásainak.
Az egész ASP.NET MVC keretrendszerre elmondható, hogy egy kiváló alapot nyújt
nagyobb alkalmazások webes fejlesztéséhez számtalan testreszabási lehetőséggel, ezért
is választottam ezt a technológiát a vékonykliensem megvalósításához.
3 Test Driven Development (TDD) – Egy olyan programozási technika, ahol egyszerre írjuk újra
és újra a forráskódot és az automatikus tesztet végző kódsorokat, míg nem teljesítettük az összes tesztet
sikeresen és a kívánt követelményeknek megfelelünk.
19
2.2 Vizuális komponensek
Az alábbiakban a web kliens fejlesztése során felhasznált vizuális komponenseket
ismertetem pár szóban, melyek nagy segítséget nyújtottak a korszerű felhasználói felület
kialakításában.
2.2.1 Twitter Bootstrap
A Twitter Bootstrap [12] egy JavaScript/CSS könyvtár, mely elsősorban a design
szempontjából segít a web fejlesztésben, sok-sok komponenst biztosítva számunkra.
A szakdolgozatomban a 2.3.2-es verziót használtam, ugyanis ehhez fel tudtam
használni az ingyenesen elérhető TwitterBootsrapMVC [13] csomagot is, ami az
ASP.NET MVC-t egészíti ki HTML generáló segéd metódusokkal (HTML helper), hogy
még egyszerűbben használhatóvá váljon az amúgy gazdagon dokumentált könyvtár.
A bootstrap egyik fő építő eleme a Grid (táblázat) rendszer, mely 940 pixel
széles, összesen 12 oszlopra osztható fel és képes reszponzív4 módra is.
2.2.1.1 Felhasznált komponensek
A Grid rendszeren kívül az alábbi komponenseket használtam fel a web kliens
fejlesztése során:
Form: A bootstrap stílusfájl sok CSS osztály definíciót biztosít arra, hogy letisztult
megjelenésű űrlapokat és elegáns beviteli mezőket készítsünk.
Button és button dropdowns: Gombokat és legördülő
menüket hozhatunk létre csupán a megfelelő HTML inputok
és CSS osztályok alkalmazásával, ahol a gombok színe a
funkcióra jellemző plusz információt ad. (pl. piros – veszély,
zöld – siker, kék – elsődleges).
4 Reszponzív web design – Egy olyan web dizájn módszer, mely a különböző méretű és felbontású
kijelzőkhöz eltérő stílus szabályokat alkalmaz, de ugyanazt a tartalmat jeleníti meg minden eszközön. Így
akár mobilról böngészve is kényelmesen használhatóvá válik az weboldal.
2-4. ábra: Gombok és
legördülő menü használata a
web kliensben
20
Navbar: A navbar CSS osztály használatával stílusos menüket készíthetünk, melyet
az alábbi kép is illusztrál:
2-5. ábra: Bootstrap stílusú menü részlet (web kliens)
Modal: Modális dialógus ablakokat
tudunk megjeleníteni minimális
JavaScript segítségével különböző
események bekövetkezésekor.
ProgressBar: A ProgressBar
egy állapotjelző sávot jelenít meg, melyet tipikusan egy (hosszú) folyamat aktuális
állapotának a kijelzésére használnak. Az alábbi képen az eredeti funkcionalitástól
eltérően a ProgressBar-t a kiadások/bevételek arányának ábrázolására használtam:
2-7. ábra: Kiadások és bevételek aránya a Bootstrap ProgressBar használatával (web kliens)
Glyph-icons: Egy kiegészítő ikonkészlet, amit szinte minden komponensben fel
tudunk használni. A menüben található kisképek is ebből az ikonkészletből
származnak (2-5. ábra).
Természetesen ezeken kívül még számos hasznos komponenssel rendelkezik,
melyek mindegye példakódokkal van illusztrálva a Bootsrap dokumentációjában [12].
2.2.2 Telerik Kendo UI
A Telerik Kendo UI [14] több, mint 70 grafikai és webes komponenst biztosít az
ASP.NET MVC számára, kliens és szerver oldali vezérlők formájában is.
2.2.2.1 Felhasznált komponensek
Az alábbi kliens oldali vezérlőket használtam fel a webes projektben:
DatePicker: Dátumválasztó komponens, mely
beállítható, hogy éppen milyen intervallumot mutasson
(csak évek, csak hónapok, hagyományos havi-napi
bontás, stb.)
2-6. ábra: Tranzakciók törlése dialógus (web kliens)
2-8. ábra: Dátumválasztó
komponens
21
Combobox: Hagyományos legördülő menü, mely támogatja a keresést is.
NumericTextBox: Számokat (és mértékegységet) tartalmazó beviteli mező,
mely kiegészül egy léptető sávval, amivel meghatározott egységenként tudjuk
változtatni az értéket.
2-9. ábra: Tranzakció összege (NumericTextBox) és a valuta kiválasztása (Combobox)
Chart: Számos látványos grafikon hozható létre a Chart komponens
segítségével, mely szerver és kliens oldali adatkötést is támogat. Az alábbi
kódrészlet a web kliens kördiagramját definiálja, melyet a 4-9. ábra illusztrál:
@(Html.Kendo().Chart(Model) .Name("chart") .Title(title => title.Text(ViewBag.ChartTitle)) .ChartArea(chartArea => chartArea.Background("transparent")) .Series(series => { series.Pie(model=>model.Value, model=>model.Name, model => model.Color) .Labels(labels => labels .Visible(true) .Template("#= category # - #= kendo.format('{0:P}', percentage)#") .Align(ChartPieLabelsAlign.Column) ); }) .Legend(legend => legend.Position(ChartLegendPosition.Top)) .Tooltip(tooltip => tooltip .Visible(true) .Format("({0:0.00})") .Template("#= category #: #= kendo.format('{0:0.00}',value) # " + ViewBag.Currency) ) )
A Kendo UI kiegészítő nem ingyenes, azonban a látványos komponenseivel egy
újabb szintre emeli a web alkalmazásunkat, olyan gazdag vizuális élményt nyújtva, mely
akár új felhasználókat is csalogathat a rendszerbe, így idővel megtérülhetnek a befektetett
költségek. A részletes dokumentáció segít az eligazodásban, ám ha problémába
ütköznénk, akkor a Kendo UI fejlesztői is készséggel állnak a rendelkezésünkre. A próba
verzióban is megismerkedhetünk az összes komponenssel, azonban elérhető egy
ingyenes, nyílt forráskódú egyszerűsített verzió is Kendo UI Core néven, több, mint 40
HTML5 és JavaScript vezérlőt tartalmazva.
22
2.3 Windows Phone 8
A Microsoft 2012. októberén adta ki a Windows Phone 8 [15] platformot, egy új
generációs mobil operációs rendszert. A Windows Phone 8 (WP8) szakít az előd
Windows CE architektúrára épült alapjaival, az új rendszer már a Windows NT kernel
alapokon nyugszik, sok-sok komponenst közösen használva a Windows 8 operációs
rendszerrel.
A szakdolgozatom írása közben, 2014. április 2-án hivatalosan is megjelent a
Windows Phone 8.1 (WP8.1) operációs rendszer, egy hosszabb fejlesztői tesztet
követően. Az újítások között szerepel az értesítő központ, az Internet Explorer 11-es
verziója, mely képes szinkronizálni Windows 8.1 és WP 8.1 készülékek között, az élő
csempék (live tiles) is kibővültek a start képernyőn, a Cortana hangfeldolgozó asszisztens
segítségével pedig könnyedén navigálhatunk a rendszerben beszéd alapján. A Microsoft
a jobb támogatottság érdekében a hardver követelményeken is változtatott, a WP8.1
megjelenésével immáron nem követelmény, hogy az eszközök fizikailag három gombbal
rendelkezzenek (vissza, start és a keresés), ezek a vezérlő gombok lehetnek szimulálva is
a felületen. Ezzel az enyhítéssel a gyártók fejleszthetnek olyan készülékeket, melyek akár
Android és Windows Phone operációs rendszerrel is képesek üzemelni.
A továbbiakban a Windows Phone 8 rendszert fogom ismertetni, ugyanis a
költségnyilvántartó keretrendszer mobil kliense is ebben a környezetben készült.
2.3.1 Felület
A platform egyik fő ismertető jele a METRO stílusú felület. A METRO dizájn elvei a
modern és letisztult megjelenést képviselik, ahol a hangsúly a tipográfián és a tartalmon
van. A felületen található élő csempék (live tiles) az infografikus irányelvet követve a
tartalomból mutatnak élő, mozgó képeket, ezáltal sokkal személyesebbnek érezzük őket.
Ezzel ellentétben az ikonografikus elv képviselői (pl. Apple iOS) a valódi világ
objektumait képezik le minél életszerűbben, a hiper-realizmus jegyében, ahol az analóg
világ technikailag minél tökéletesebb digitális megfeleltetése a cél. A Windows Phone
megjelenésében jelentősen különbözik a riválisaitól, melyet az alábbi ábra is szemléltet:
23
2-10. ábra: Android, Windows Phone 8 és az iOS felülete
2.3.2 Az alkalmazás életciklusa
A telefonon egyetlen alkalmazás lehet az előtérben aktív egyszerre. Egy futó
alkalmazás többféleképpen is „alvó” (dormant) állapotba kerülhet:
Hívás érkezik, miközben fut az alkalmazás
Az alkalmazás Launchert vagy Choosert használ
Start gomb megnyomásának hatására
Megjelenik a zároló képernyő bizonyos idejű inaktivitás után
Az alvó állapotban a program továbbra is a memóriában marad, azonban semmi
sem garantálja, hogy az alkalmazásunk valaha is folytatódni fog, így a deaktiválás során
szükségünk van az aktuális állapot elmentésére. Ha az alvó állapotból újra „futó”
(running) állapotba kerül egy alkalmazás, akkor arról az oldalról fog folytatódni, ahonnan
deaktiválták, az aktiválás során betöltve a korábbi állapotot a memóriából. [15]
Ha az operációs rendszer kifutna a memóriából, akkor eldobja a legrégibb „alvó”
(dormant) alkalmazásnak a mentett állapotát, ezzel felszabadítva a memóriát. Ezt a
folyamatot nevezzük „sírkőbe zárásnak” (tombstoning). Ha egy „sírkőbe zárt”
(tombstoned) alkalmazást újra aktiválni szeretnénk, akkor annak a teljes állapotát újra be
kell töltenünk az alkalmazáshoz tartozó tárból. [16]
Az alkalmazás életciklusát az alábbi ábra szemlélteti:
24
2-11. ábra: Windows Phone alkalmazás életciklusa [15]
2.3.3 Hardver követelmények
Az alábbi felsorolásban a WP8 mobil készülékekre előírt hardver
követelményeket tekinthetjük meg:
Képernyő: Windows Phone 7: kizárólag 800x480 (WVGA, 15:9),
Windows Phone 8: 800x480 (WVGA, 15:9), 1280x720 (720p, 16:9) vagy
1280x768 (WXGA, 15:9), Windows 8.1: új felbontás 1920x1080 (1080p)
Kapacitív érintés érzékelés: Minimum 4 pontos
Processzor: Qualcomm Snapdragon S4 dual-core vagy Snapdragon 800
Memória: min. 512MB RAM a WVGA és min. 1GB RAM a 720p/WXGA/1080p
felbontásokhoz. Legalább 4 GB flash memóriával rendelkezzen
Grafikus egység (GPU): DirectX renderelés támogatása hardveres gyorsítással
(Direct3D), programozható GPU-val
Kamera: Autófókuszos, legalább 5 megapixeles, opcionálisan előlapi kamera is
Szenzorok: A-GPS, gyorsulásmérő, fényérzékelő, közelségérzékelő, opcionális
iránytű és giroszkóp
Gombok: Alábbi gombokkal rendelkeznie kell: Start, Keresés, Vissza, Kamera,
Hangerőgombok, Kikapcsoló/bekapcsoló/billentyűzár gomb. Az első 3 gomb
csak Windows Phone 7/8 esetén kötelező.
2.3.4 Fejlesztés Windows Phone 8 platformra
A fejlesztés során törekedjünk arra, hogy igazi felhasználói élményt adjunk,
hiszen az élmények ragadják meg igazán a METRO elveket.
25
A Windows Phone 8 közös alapokon nyugszik a Windows 8 operációs
rendszerrel. A CoreCLR a .NET keretrendszer CLR (Common Language Runtime)
magja, erre az alapokra épül a mobil platform, mely segítségével jól kihasználhatjuk a
többmagos környezetet, modern programozási technikákat és mintákat alkalmazva.
Az alábbiakban a platformra jellemző néhány technikai újdonságot és a fejlesztés
során felhasznált kiegészítőket mutatom be [17]:
2.3.4.1 Aszinkron programozási modell
A .NET 4.5 egyik jelentős újítása, hogy C# 5.0-ban (illetve a Visual Basic 11-ben)
új nyelvi elemek jelentek meg az aszinkron programozási modell támogatásához,
melyeket ebben a mobil környezetben kiválóan tudunk alkalmazni. Ennek segítségével
egyszerűbb gyorsan reagáló, nem blokkolódó felületeket készíteni, így a felhasználói
elégedettség is növelhető.
2.3.4.2 Garbage Collector (GC)
A CoreCLR-ben számos hasonló szolgáltatás és optimalizált megoldás áll
rendelkezésünkre, mint a NET 4.5 CLR-jében, ezáltal sokkal hatékonyabb, mint a .NET
Compact keretrendszer, amit az előd Windows Phone 7 használt. Az új három generációs
szemétgyűjtő (Garbage Collector) többmagos CPU-ra van optimalizálva, alacsony
késleltetéssel és javított élettartam követéssel.
2.3.4.3 A fordítás folyamata
A telefonra írt .NET kód a felhőben fordul le az alkalmazás feltöltésekor, így egy-
egy alkalmazás gyorsabban indul. Ezt úgy éri el, hogy a forrás C# kód először köztes
kódra fordul (MSIL/CIL assembly), majd a felhőben az MDIL (Machine Dependent
Intermediate Language) fordítóhoz kerül, ami a nem változó kódrészeket natív kódra
fordítja és megjelöli azokat a részeket, melyek eszközfüggően változhatnak. A folyamat
végén keletkezik egy majdnem teljesen natív kód, melyet a legutolsó lépésben a
készüléken tovább fordítva teljesen natív DLL-t kapunk. Ha bármi változás, frissítés
történik az alkalmazásban, akkor a változó részek már gyorsan újrafordíthatók a
telefonon. Ezzel a felhőben történő előkészítéssel közel 50%-os teljesítménybeli
növekedést értek el a WP7 platform alkalmazás indulási sebességéhez képest. [18]
26
2-12. ábra: Windows Phone 8-ra írt kód fordításának folyamata [15]
2.3.4.4 Kódmegosztás a Portable Class Library használatával
A megosztható osztálykönyvtárak (Portable Class Library) segítségével ugyanazt
a felügyelt .NET kódot felhasználhatjuk több platformon is (Silverlight 4+, WP7,
Windows Store alkalmazások stb.). Újrafelhasználható üzleti logikákat készíthetünk, ha
kiemeljük azokat a közös részeket, melyek más .NET-es környezetben is megállják a
helyüket.
2.3.4.5 Adatok tárolása
Az alkalmazások a privát adataikat az Izolált tárban (Isolated Storage) tárolhatják,
azon belül is több helyen:
Az alkalmazás beállításait az Application Dictionary-ben
A nem strukturált adatok fájlokban
Strukturált adatokat az adatbázisban
Az Isolated Storage alapértelmezetten az SQL Server Compact Edition (SQL CE)
adatbázis kiszolgálót támogatja, Code First megközelítéssel és a LINQ to SQL erejével.
2.3.4.6 Mobil kliens fejlesztéséhez felhasznált osztálykönyvtárak, csomagok
A költségnyilvántartó keretrendszer mobil kliensének fejlesztése során több
hasznos nyílt forráskódú (opensource) osztálykönyvtárat és csomagot használtam fel,
melyek közül párat az alábbi listában ismeretetek, a kliens forráskódjából származó
példakódokkal illusztrálva:
27
PropertyChanged.Fody [19]
A csomag használatával az INotifyPropertyChanged interfész megvalósítása
válik gyerekjátékká. Ez az interfész nagy szerepet játszik WPF/Silverlight
környezetben (így WP8 esetén is), ahol gyakoriak az adatkötések (binding) egy-
egy vezérlőhöz. Az adatokban történt változásról értesülnie kell a vezérlőnek is.
Ez az értesítés események elsütésével valósítható meg, így minden tulajdonságot,
amit fel szeretnénk készíteni változás-értesítésre, ki kell bővítenünk monoton
módon egy PropertyChanged esemény hívással:
public class RegisterPageViewModel: INotifyPropertyChanged { private string fullName; public string FullName { get { return fullName; } set { if (fullName != value) { fullName = value; NotifyPropertyChanged(); } } } // . . . Other properties public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged( [CallerMemberName] string propertyName = "") { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }
A PropertyChanged.Fody segítségével, ha a kívánt osztályon használjuk az
ImplementPropertyChanged attribútumot, akkor az osztály tulajdonságaiba
automatikusan injektálódik a fentebb látott NotifyPropertyChanged() hívás
és a környezete fordítás időben. Így rövidebb kódot kapunk és jelentős időt
takaríthatunk meg pl. egy-egy ViewModel implementálása során:
[ImplementPropertyChanged] public class RegisterPageViewModel { public string FullName { get; set; } // . . . Other properties }
28
Windows Phone Toolkit [20]
Ez a kiegészítő csomag a Windows Phone SDK-t új komponensekkel bővíti ki,
melyek között akadnak igen hasznos vezérlők is. A sok lehetőség közül mindössze
3 komponensre volt szükségem:
ListPicker: legördülő lista. Elemek közötti kiválasztás a cél,
valójában olyan, mint egy ComboBox vagy DropDownList mobilos
környezetben.
2-13. ábra: Nyelvválasztó komponens (ListPicker)
ExpanderView: lenyitható/összecsukható elem. Lista elemként
használtam több helyen is: a kategória választás során, az áttekintő
oldalon, illetve egy-egy tranzakció részletező oldalán. A fejlécre kattintva
ki/becsukhatjuk a tartalmat, így elrejthetjük a nem kívánatos elemeket egy
felsorolásban.
2-14. ábra: Kategóriaválasztó komponens (ExpanderView)
DatePicker: dátumválasztó komponens. A képen látható dátumválasztó
valójában egy egyedi User Control, ami a DatePicker-re építve
kiegészíti azt a jobboldali sarokban látható célkereszttel, amire kattintva
az aktuális napra ugrunk.
2-15. ábra: Dátumválasztó komponens (DatePicker)
AppBar Utils [21]
Az Application Bar a képernyő alján elhelyezkedő gombokat, menüelemeket
tartalmazza, melyek így egységes kinézetet biztosítanak az alkalmazások
számára. Ezek az AppBar elemek azonban alapvetően fix elemnek számítottak,
korlátozott testreszabási lehetőségekkel. Az AppBar Utils segítségével
leválthatjuk a WP8 SDK nyújtotta AppBar-t egy dinamikus verzióra, ahol
használhatunk adat kötéseket, triggereket és különböző akciókat is. Ezáltal a
29
menüelemek lokalizálása sem jelent akadályt többé, és a viselkedésnek
megfelelően testre szabhatjuk őket. Az alábbi kódrészletben a kategória választó
oldal Application Bar kódja látható, melyen egyetlen gomb szerepel, az új
kategória hozzáadása. Ez a gomb csak akkor engedélyezett, ha adminisztrátori
jogosultsággal bírunk:
<i:Interaction.Triggers> <abu:AppBarItemTrigger Type="Button" Id="new" Text="{Binding Path=LocalizedResources.AppBarCreateNewCategory, Source={StaticResource LocalizedStrings}}" IsEnabled="{Binding IsAdmin}"> <ec:CallMethodAction MethodName="appBarNewBtn_Click" TargetObject="{Binding}"/> </abu:AppBarItemTrigger> </i:Interaction.Triggers>
Coding4Fun Toolkit [22]
Ez a kiegészítő tartalmaz néhány igen hasznos vezérlőt a Windows Phone
platformra. Nekem csupán a MessagePrompt vezérlőre volt szükségem, mellyel
a hagyományos MessageBox dialógus ablakot cserélhetjük le egy testre szabható
verzióra. Az alábbi képen a jelszó emlékeztető dialógus látható, melyen
lehetőségünk van megadni egy e-mail címet, ahova az új jelszót küldi a rendszer:
2-16. ábra: Jelszó emlékeztető dialógus (MessagePrompt)
A MessagePrompt tartalmát felépíthetjük több vezérlő használatával is, így az
igényeknek megfelelően készíthetjük el a szükséges dialógust.
Windows Phone IsoStoreSpy [23]
Ez valójában egy alkalmazás Windows 8-ra, mely arra hivatott, hogy a WP7/8
emulátorok IsoStore tartalmát áttekinthessük, ami nagy segítség lehet a fejlesztés
során.
Úgy gondolom, hogy ezek a csomagok, kiegészítők hasznosak lehetnek akár egy
másik Windows Phone projekt fejlesztése során is.
30
A Windows Phone 8 a felügyelt .NET környezet erejének köszönhetően
kényelmesen fejleszthető, sebességben is felveszi a versenyt a vetélytársakkal. A teljesen
eltérő felhasználói felület és az egyedi megoldások teszik igazán érdekessé ezt a mobil
platformot.
2.4 WCF
A WCF (Windows Communication Foundation) [29] a Microsoft egységes
programozási modellje szolgáltatás-orientált (SOA – Service Oriented Architecture)
alkalmazások készítéséhez. A fejlesztők számára egy megbízható, biztonságos eszközt
kínál az egymástól eltérő platformok közötti együttműködéshez.
2.4.1 WCF architektúra és fogalmak
A WCF-ben két szereplő kommunikál egymással: a szolgáltatás és a kliens. Egy
szolgáltatás egy vagy több végpontot (endpoint) publikál, melyre a kliensek
csatlakozhatnak. A kliens és a szolgáltatás oldali végpontok között üzenetek mozognak.
2.4.2 Üzenetcsere minták
Az alábbiakban felsorolom, hogy mely üzenetváltási mintákat támogatja a WCF
[24]:
Kérés-válasz: a kliens üzenetet küld, a szolgáltatás válaszüzenetben válaszol.
Messze ez a leggyakoribb.
Egyirányú (OneWay): a kliens kérésüzenetére nincs válasz.
Duplex (Callback): a szolgáltatás visszahív a kliensbe, a szolgáltatás küld csak
üzenetet.
2.4.3 Végpontok
Minden szolgáltatás végpont három fő részből áll: Address (cím), Binding (kötés),
Contract (szerződés). Ezen alkotóelemekre szokás a WCF ABC-jeként is hivatkozni.
31
2-17. ábra: WCF végpontok ABC-je
2.4.3.1 Address (cím) – hol?
A végpont címe (URL), amin keresztül a kliensek el tudják érni a szolgáltatást. A
költségnyilvántartó rendszer szolgáltatása a fejlesztés közben az alábbi címen volt
elérhető: http://192.168.0.200:1617/ExpenseService.svc
2.4.3.2 Binding (kötés) – hogyan?
A kötések írják le, hogy a kliensek hogyan tudnak kommunikálni a szolgáltatással.
Egy kötés meghatározza a kommunikációs protokollt, melyre a WCF sok lehetőséget
kínál (pl. BasicHttpBinding – HTTP alapért., NetTcpBinding – biztonságos, TCP alapú,
MsmqIntegrationBinding – MSMQ alapú alkalmazások kommunikációjához, stb.) [29].
A végpont és a kliens közötti párbeszéd XML formátumú SOAP üzenetekbe van ágyazva,
ezáltal a WCF platform független szolgáltatást képes nyújtani.
2.4.3.3 Contract (szerződés) – mit?
A szerződés azokat a műveleteket, metódusokat definiálja, amiket a végpont
nyújt. A szolgáltatás interfész műveleteinek leírása .NET-ben a megfelelő attribútomok
használatával történik, amiből aztán elkészül a megfelelő WSDL (Web Service
Description Language) + XSD (XML Schema Definiton) leírás, így a kliensek használni
tudják az interfész metódusait. Több féle szerződés típus létezik [25]:
Service Contract
Leírja azokat a függvényeket, amiket a szolgáltatás kiajánl a kliensek számára.
.NET-ben a megfelelő attribútumok segítségével tudunk egy interfészt elérhetővé tenni
WCF-et használva:
[ServiceContract] public partial interface IExpenseService { [OperationContract] string GetData(int value); }
32
Az interfészt a ServiceContract, míg az interfész függvényeit
OperationContract attribútummal kell ellátni, hogy sikeresen definiáljunk egy
Service Contract-ot.
Data Contract
Azokat az egyedi adat típusokat definiálja, amiket a szolgáltatás leíró nyelv
alapértelmezetten nem ismerhet. Az egyedi osztályokat, illetve adattípusokat nem
ismerheti az XSD, így ezeket külön definiálnunk kell, hogy a kliensek is használni tudják
a szolgáltatás egy-egy metódusának paraméterlistájában, illetve visszatérési értékként fel
tudják dolgozni. A Data Contract létrehozásához az adatleíró osztályt DataContract, a
benne található publikálni kívánt mezőket pedig DataMember attribútummal kell ellátni:
[DataContract] public class DetailsItem { private string temp; [DataMember] public string Date; }
Message Contract
A WCF SOAP üzenetekkel kommunikál és ahhoz,
hogy teljesen kontrollálni tudjuk az üzenet formátumát,
használhatjuk a Message Contract-ot. Ennek segítségével a
teljes SOAP üzenet törzse és fejléce igények szerint
alakítható, míg a Data Contract és az Service Contract-ok
SOAP formátumát és sorosítását a WCF kezeli helyettünk.
Fault Contract
A Fault Contract a szolgáltatásban keletkező
hibákról, kivételekről nyújthat tájékoztatást a kliensek számára.
A projektemben a Service Contract és Data Contract szerződés típusokat
használtam a szolgáltatás implementációja során.
2-18. ábra: SOAP üzenet
struktúra
33
2.4.4 WCF és WebAPI összehasonlítása
A Web API az ASP.NET MVC 4-es keretrendszer részeként érkezett, azonban
külön csomagként is elérhető. Használatával egy egyszerű REST5 [26] képes web
szolgáltatást építhetünk fel, ami leginkább a kliens oldali JavaScript-ek adatigényét tudja
kielégíteni [27]. A Web API egy ideális platform olyan szolgáltatások létrehozásához,
ahol a kérés és válasz is a HTTP-n keresztül történik. A szolgáltatás a kliens GET, PUT,
POST és DELETE kéréseire válaszol alapértelmezetten JSON vagy XML formátumban.
A HTTP-nek köszönhetően széles körű kliens oldali támogatottságot érhet el, legyen szó
akár a böngészőkről, okostelefonokról vagy asztali alkalmazásokról.
Az alábbi táblázatban egy rövid összehasonlítást láthatunk a Web API és a WCF között:
WCF ASP.NET Web API
Támogatott
szállítási
protokollok
Többféle átviteli protokollt is
támogat (HTTP, TCP, UDP
és egyebek) melyek között
könnyedén válthatunk.
Csak HTTP protokollon
működik. Első osztályú
programozási modellt biztosít
a HTTP protokoll felett.
Hálózati
adatforgalom
A SOAP protokollnak
köszönhetően ugyan
kényelmesebb használatot
biztosít a kliens szoftverek
számára, azonban a nagyobb
hálózati adatforgalmat
generál az átvitt adathoz
kapcsolódó meta-adatok,
kiegészítő szolgáltatások
miatt.
Alkalmasabb arra, hogy
szélesebb körben hatékonyan
elérhetővé tegyen egy
szolgáltatást a különböző
böngészők, mobil eszközök
között, ugyanis kevés extra
rakománnyal viszi át az adatot
a hálózaton, HTTP fölött.
Üzenet
típusok
Többfajta üzenet kódolást is
támogat (Text, MTOM,
Binary) ugyanazon üzenet
típus számára, melyek között
válthatunk.
Olyan web alapú API-k
(Application Programming
Interface) létrehozását
támogatja, melyek sokféle
média típust támogatnak. Pl.
XML, JSON, stb.
5 REST (Representational State Transfer) – Egy szoftver architektúra elosztott hipermédia
rendszerek számára, mely állapotmentes, kliens-szerver alapú, cache-elhető kommunikációs protokollon
alapul (tipikusan a HTTP-n). A REST egy egyszerű alternatívát biztosít az eszközök összekötéséhez.
34
Biztonság
Támogatja a WS-* alapokon
nyugvó biztonsági
szolgáltatásokat, mint a
Megbízható üzenetváltás
(Reliable Messaging),
Tranzakciók (Transactions)
és Üzenet biztonság
(Message Security).
Alapszintű (biztonsági)
protokollokat és formátumokat
használ, mint a HTTP,
WebSockets, SSL, JQuery,
JSON és XML.
A magasabb szintű biztonsági
protokollokat nem támogatja
(pl. Transactions)
Üzenet iránya
Támogatja a kérés-válasz
(request-reply), egyirányú
(One Way) és a kétirányú
(Duplex) üzenetváltási
mintákat is.
A HTTP csak a kérés-válasz
üzenetküldést támogatja,
azonban ez kiegészíthető a
SignalR [6] és a WebSocket
integrációjának segítségével.
Szolgáltatás
leíró nyelv
A WCF SOAP szolgáltatást a
WSDL nyelv írja le, ami
támogatja az automatikus
kliens oldali proxy-k
generálását még a komplex
sémájú szolgáltatások
számára is.
Sokféle módon írhatjuk le a
Web API nyújtotta
szolgáltatást, kezdve az
automatikus generált HTML
segéd oldalakkal, melyek
leírják a kínált metódusokat,
egészen a strukturált meta-
adatokig az OData
támogatással rendelkező API-k
számára.
Elérhetőség A .NET keretrendszer
részeként érhető el.
A nyílt forráskódú ASP.NET
keretrendszer részeként érhető
el, de akár külön egységként is
letölthetjük.
3. táblázat: A WCF és a WebAPI összehasonlítása [28]
Általánosságban elmondható, hogy a WCF használatával biztonságos web
szolgáltatásokat építhetünk, számos átviteli közeg felett, míg az ASP.NET Web API
segítségével olyan HTTP alapú szolgáltatást építhetünk, mely széleskörű kliensoldali
támogatottsággal rendelkezik. A Web API-t akkor érdemes használni, ha REST képes
(RESTful) szolgáltatást akarunk építeni. Ugyan WCF is támogatja a REST végpontok
összeköttetését pl. a WebHttpBinding kötés használatával, azonban a Web API teljesebb
támogatottsággal rendelkezik ezen a téren.
Az általam fejlesztett keretrendszer szolgáltatásának megvalósításához azért a
WCF technológiát választottam, mert .NET környezetben a rendszer résztvevői így
könnyedén kommunikálhattak egymással és a kliens oldal ki tudta használni a SOAP
protokoll nyújtotta előnyöket.
35
3 Specifikáció
Ebben a fejezetben a költségnyilvántartó keretrendszer feladatainak pontos
leírását, a funkciónak specifikálását tekinthetjük át. Ezt követően a felhasználói
szerepköröket és a rendszer architektúráját ismertetem.
3.1 Szoftver célja
A feladatom egy költségnyilvántartó keretrendszer fejlesztése volt .NET
alapokon. A szoftver célja, hogy lehetővé tegye egy háztartás vagy akár kisvállalat
költségvetésének nyilvántartását, a kiadások, illetve bevételek elektronikusan való
tárolását.
A programban az egyes tételeket kategóriákba rendezve tárolhatjuk. A rendszer
adminisztrátorai a vállalat, illetve háztartás igényei szerint testre szabhatják ezeket a
költség kategóriákat, melyekre a felhasználók felvehetnek tételeket különböző
paraméterek megadásával. A megvalósítás során fontosnak tartottam, hogy az elkészült
szoftver egyszerűen kezelhető legyen webes és mobil platformon is, ezzel is növelve a
felhasználói tábort. A mobil kliens nagy előnye, hogy a költségeket, illetve bevételeket
akár azonnal feltölthetjük a rendszerbe, akár egy szupermarketben vásárlás közben is –
ahol a blokkról fotót is készítünk a telefonunkkal – vagy egy sikeres üzlet
lebonyolításának pillanatában.
A fejlesztendő alkalmazással szemben elvárás, hogy keretrendszerként működjön,
azaz legyen egy központi alkalmazás, ami megvalósítja az üzleti logikát, tárolja a
szükséges adatokat és kiszolgálja a különböző platformokon megvalósított kliens
alkalmazásokat. A kliens alkalmazások a központi szoftverrel kapcsolatban állva friss és
egyazon adatokkal dolgozhatnak, egymással együttműködve.
Végső célom az volt, hogy egy felhasználóbarát kiadás nyilvántartó alkalmazás
csomag készüljön, ami bátran felveheti a versenyt az ebben a kategóriában létrejött
szoftverekkel szemben. A hangsúlyt nem csupán a funkcionalitásra helyeztem, hanem
legalább ugyanakkora részben egy korszerű felület kialakítását is kitűztem magam elé.
További célkitűzésként szerepelt, hogy a rendszer funkcionális bővítése, illetve újabb
kliens platformok fejlesztése ne jelentsen különösebb akadályt a fejlesztő számára.
36
3.2 Funkciók
A keretrendszer funkciót az alábbi felsorolásban tekinthetjük át. Ezek a funkciók
minden kliens alkalmazásra érvényesek.
Felhasználók kezelése: A felhasználók regisztrálhatnak valamely kliens
alkalmazásból, ezután igénybe vehetik az összes felhasználói szintű
funkciót. Kizárólag regisztrált felhasználók használhatják a szoftvert,
hiszen teljes mértékben felhasználó orientált a termék. Az alkalmazáson
belül nincs értelme felhasználótól függetlenül kiadásokról vagy
bevételekről beszélni általánosságban, ez mindig egy felhasználóhoz kell,
hogy tartozzon. A regisztrált felhasználók szükség esetén kérhetnek jelszó
emlékeztetőt a regisztrációkor megadott email címre, illetve törölhetik is
magukat a rendszerből. Minden egyes felhasználóhoz tartozik egy egyedi
beállítás, ahol megadhatjuk, hogy milyen pénznemben történjen az
elszámolás, illetve, hogy a (külföldi) valutákban szereplő tételek
konvertálódjanak az elszámolás pénznemére vagy meg se jelenjenek.
Kategóriák: A rendszer adminisztrátorai kezelhetik a tranzakciókra
vonatkozó kategóriákat. Minden egyes tranzakciót (tételt) pontosan
egyetlen kategóriában tudunk felvenni az alkalmazásba. A kategóriák
hierarchikusan épülnek fel, a rendszer 2 szintet különböztet meg. Minden
alkategória hivatkozik a szülő kategóriájára. A szülő kategóriákról
tároljuk, hogy kiadás, illetve bevételi kategóriának számítanak-e. Egy
szülő kategória lehet pl. a Kiadás (Expense) vagy a Bevétel (Income).
Létrehozhatunk azonban semleges szülő kategóriát is (pl. Ajándék [Gift]),
melyre felvehetünk kiadásokat és bevételi tételeket is. Az alkategóriákról
a szülő kategória ismeretével együtt egyértelműen kiderül, hogy kiadás,
bevétel vagy semleges kategóriáról van szó. Ilyen alkategória lehet pl. az
Bevétel (szülő) / Fizetés.
Tranzakciók: A rendszerben szereplő tételeket tranzakcióknak nevezzük.
A felhasználók az előző pontban említett kategóriák közül egyet
kiválasztva felvehetnek egy új tranzakciót. Egy tranzakció csak kiadás
vagy bevétel lehet. A felvétel során kötelezően meg kell adnunk az
összeget, mely csak pozitív valós szám lehet. A rendszerben az előjelről
37
az fog dönteni, hogy kiadás vagy bevétel kategóriában szerepel az összeg.
Továbbá kötelezően meg kell még adnunk egy dátumot is és a valutát.
Opcionálisan megadhatjuk még a következő adatokat is egy új
tranzakcióra vonatkozóan: fizetőeszköz, megjegyzés, helyszín, fénykép
(célszerűen a nyugtáról/számláról). A rendszerben szereplő tranzakciók
képezik az alapját a kimutatásoknak, illetve áttekintő listának. A már
felvett tranzakciók megtekinthetők, illetve törölhetők az áttekintő listából,
ahol havi és azon belül napi bontásban szerepelnek a tételek, kategóriákba
rendezve.
Kimutatás: A szoftver leglátványosabb elemei a kimutatás diagramok. A
diagramok kategóriák szerint vannak rendezve. Az egyes klienseken eltérő
diagramok lehetnek, véleményen szerint mobil kliens esetén pl. egy
kördiagram jobban áttekinthető. A webes kliens képes megjeleníteni kör,
illetve oszlopdiagramot is, itt nagyobb felbontást feltételezünk. A
megjelenítendő adatokat szűrhetjük évenkénti, havi, heti, illetve napi
bontásban, illetve megadhatjuk, hogy a csak a bevételekre vagy csak a
kiadásokra vagyunk kíváncsiak, esetleg mindkettőre egyszerre.
Valuta konvertálás: Lehetőségünk van valuták közötti átváltásra is. A
valuták és az aktuális árfolyamok egy külső szolgálgatótól érkeznek, az
átváltás mindig az aktuális napi árfolyamon történik.
3.3 Felhasználói szerepkörök
A rendszer felhasználói között két szintet különböztetünk meg. Az egyik
csoportot az „egyszerű” felhasználók, míg a másikat az adminisztrátorok alkotják. Az
„egyszerű” felhasználók a valódi használói a rendszernek, a kategóriák kezelésén kívül
minden funkciót igénybe vehetnek. Az adminisztrátorok egyetlen plusz kiváltsága, hogy
menedzselhetik a kategóriákat, azaz újakat vehetnek fel, illetve törölhetnek a meglévők
közül. A rendszert használni kívánó látogatóknak regisztrálniuk kell ahhoz, hogy elérjék
a funkciókat, így nem beszélhetünk látogatói csoportról. A regisztráció után
automatikusan felhasználó szerepkörbe kerülünk, adminisztrátori jogosultság az
adatbázisban tárolt felhasználó típusának kézi módosításával adható egy-egy leendő
felhasználónak, amihez ideális esetben csak az adatbázis szerver üzemeltetője férhet
hozzá. A szerepköröket az alábbi use-case diagram ábrázolja:
38
3-1. ábra: Felhasználói szerepkörök use-case diagramja
3.4 Architektúra
A szoftver egy kliens-szerver alapú architektúrát valósít meg, ahol a szerver
kommunikál az adatbázissal, megvalósítja az üzleti logikát, amit egy interfészen keresztül
elérhetővé tesz a kliensek számára. A kliens alkalmazások egy-egy funkció használata
során a szerverhez fordulnak, majd a szerver válaszát feldolgozva megjelenítik a
szükséges adatokat.
A szerver egy külső valutaárfolyam szolgáltatóval is kommunikál, hogy minden
nap friss árfolyamokkal dolgozhassunk. A rendszer architektúráját a 3-2. ábra vázolja.
39
3-2. ábra: Architektúra vázlat
A szerveren egy szolgáltatás fut, mely WCF-en keresztül kommunikál a
kliensekkel SOAP üzenetek formájában, HTTP protokoll felett (lásd 2.4-es fejezetben).
A valutaárfolyam szolgáltató (https://openexchangerates.org/) RESTful
szolgáltatást biztosít, JSON formátumban kínálva a szükséges adatokat, melyet a szerver
eltárol, időnként újra lekérve az aktuális árfolyamokat. Ez a szolgáltatás szükség esetén
cserélhető, mivel azonban egy meghatározott struktúrában várjuk az adatokat, szükséges
lehet a szerveren futó szolgáltatás módosítására is.
Az adatbázis lehet akár a szolgáltatást futtató vagy egy külön adatbázis szerveren
is. Használhatunk bármilyen .NET és Entity Framework kompatibilis adatbázis
kiszolgálót, legyen az akár az MSSQL, Oracle vagy a MySQL.
Lehetőségünk van a tervezett Windows Phone 8 mobil és ASP.NET MVC-re
épülő webes kliensek mellett egyéb kliens alkalmazásokat is megvalósítani (pl. Java,
Android, iOS alapokon), hiszen a WCF segítségével platform független szolgáltatást
tudunk nyújtani (amennyiben a kliens boldogul a SOAP üzenetekkel).
40
4 Megvalósítás
Ebben a fejezetben a keretrendszer tervezésének és fejlesztésének lépéseit
mutatom be. Mivel a szakdolgozatom kereteibe nem férne bele minden lépés részletes
leírása, így próbáltam átadni a leglényegesebb információkat és egy-egy érdekesebb vagy
kihívást jelentő részletet kiemelni.
4.1 Adatbázis tervezése
A fejlesztés első állomása az adatmodell megtervezése volt. A tervezés során
először át kellett gondolnom, hogy milyen típusú adatokra lesz szükségem az alkalmazás
használata során. Továbbá azt is át kellett gondolnom, hogy az adatokat milyen formában
szeretném tárolni. A tárolás problémájára a megoldás viszonylag egyértelmű volt
számomra: a Microsoft SQL Server 2012 relációs adatbáziskelő rendszert választottam.
A döntés végkimenetelében szerepet játszott az, hogy a C#/.NET kiválóan együttműködik
ezen adatbázis kiszolgálóval, széleskörűen támogatott, valamint egyszerűen kezelhető. A
kiszolgálóval való kommunikáció kényelmesebbé tétele érdekében az Entity Framework
ORM (Object-relational mapping) [30] rendszert használtam.
4.1.1 Code First vagy Database First?
Az Entity Framework támogatja ezen kiszolgálóhoz a Code First megközelítést,
mely szemlélet szerint az egyes adatosztályok – mint entitások – és az osztályok között
levő kapcsolatok leképződnek adatbázis táblákra, valamint relációkba, amennyiben
megfelelő adatbázis kontextusba (DBContext) helyezzük őket. Ezt a módszert
választottam én is az adatbázis tervezése során, mert gyorsan létre tudtam hozni egy
adatbázist csupán az osztályok forráskódjának előállításával. Mindvégig kézben tudom
tartani az adatbázis tábláinak megfeleltethető osztályokat, nincsenek az adatbázis
sémából automatikusan generált osztályok (POCO entitások) ellenben a Database First
megközelítéssel szemben, ahol, ha a generált modellünket bővíteni szeretnénk valamilyen
új funkcióval vagy csupán egy új tulajdonsággal, akkor az csak úgy lehetséges, ha
kiterjesztjük a parciális modell osztályunkat. Ezzel sok-sok modell-kiterjesztés születhet,
ami átláthatatlanná teheti a projektet.
Természetesen megvannak a Database First technikának is az előnyei. Ide tartozik
az, hogy optimalizálhatjuk a táblák mezőit a megfelelő típusok, méretek megadásával
41
(igaz attribútumok segítségével a Code First módszert is finomíthatjuk valamilyen
mértékben), létrehozhatunk tárolt eljárásokat, triggereket. Az adatbázisokkal gyakran
foglalkozó szakértők talán jobban kedvelik a már bevált adatbázis létrehozási
módszereket, ahol teljesen testre szabhatják az igényeknek megfelelően az adatbázis
szerkezetét, és optimalizálhatják a rendszert. Kimerítőbb munka, azonban a befektetett
energiák könnyen megtérülhetnek.
A sémában történt változások frissítését mindkét technika támogatja. Code First
esetén az Entity Framework migrációs képességét használhatjuk ki, míg a Database First
módszernél frissíthetjük a generált modellt a séma aktuális állapota alapján. Ha
szeretnénk nyomon követni az adatbázisban történt változásokat, a különböző verziókat,
akkor a Code First migrációk hatalmas segítséget nyújthatnak számunkra, ahol egy
migráció hozzáadásával új fájl keletkezik időbélyeggel és egy általunk választott névvel,
majd ebben a fájlban automatikusan legenerálódnak a modellben történt változások egy
UP() és DOWN() függvényben. Az UP() függvény alkalmazza a modellben történt
változásokat, míg a DOWN() függvény eltávolítja a már nem kívánatos elemeket
(rollback). Mivel az adatbázis séma teljes mértékben a kódtól függ, a forráskód
verziózása is rendelkezésünkre áll. Bele tudunk avatkozni a kontextus inicializálásába is,
ahol például kezdeti üzleti adatokkal tölthetjük föl az adatbázisunkat. A verziózás
megvalósítása adatbázis oldal esetén már koránt sem olyan triviális feladat. [31]
4.1.2 Az adatbázis séma
Most áttérek a költségnyilvántartó rendszer adatbázis-tervének a
végeredményére. A tervezés több lépcsőből állt, először összegyűjtöttem a tárolandó
adatok listáját, amiket adatbázis entitásokba csoportosítottam, majd a folyamatos
finomítások után végül meghatároztam az entitások közötti kapcsolatokat is.
A tervezés befejeztével az alábbi Code First entitás modell készült el:
42
4-1. ábra: Adatbázis séma
43
4.1.3 Táblák és attribútumok
Az alábbi táblázatban a Code First segítségével generált adatbázis tábláit és
attribútumait tekinthetjük át. A táblák egyes oszlopaihoz rövid leírás tartozik, ami
tisztázza az attribútumok tárolási funkcióját.
Tábla Tárolási
funkció Oszlop Leírás
Users Felhasználók
adatai
Id Elsődleges kulcs
FullName A felhasználó teljes neve
Username A felhasználó azonosítója
Password A felhasználó jelszava (MD5
algoritmussal hashelt)
Email A felhasználó e-mail címe
Type Felhasználó szerepköre: admin /
user
Settings Felhasználó
beállításai
Id Elsődleges kulcs
BaseCurrency Alapértelmezett valuta
CurrencyConvert
Konvertálja az alapvalutát más
valuta esetén vagy csak az
alapvaluta tételei jelenjenek meg?
Language Használt megjelenítési nyelv
Transactions Tranzakció
adatai
Id Elsődleges kulcs
Note Megjegyzés
Date Tranzakció időpontja
Amount Tranzakció összege
IsExpense A tranzakció kiadás-e?
User_Id
Idegen kulcs
Payment_Id
Currency_Id
Location_Id
Category_Id
RecurringTransactions6
Ismételődő
tételek
(tranzakciók)
Id Elsődleges kulcs
LastDate Utolsó bekövetkezési időpont
NextDate Következő bekövetkezési időpont
Note Megjegyzés
Amount Tranzakció összege
IsExpense A tranzakció kiadás-e?
User_Id Idegen kulcs
Frequency_Id
Frequencies Ismétlődési
gyakoriság
Id Elsődleges kulcs
Freq Értesítési gyakoriság
Receipts Számlák,
blokkok
Id Elsődleges kulcs
Photo Számláról (bizonylatról) készült
fotó byte tömbként tárolva
Transaction_Id Idegen kulcs
Payments Fizetési
típusok
Id Elsődleges kulcs
Type Fizetőeszköz típusa
6 Ismételődő tételek jelenleg nincsenek kezelve az alkalmazásban, későbbi bővítési lehetőséghez
egy kiindulási alap ez a tábla
44
Categories Kategóriák
Id Elsődleges kulcs
Name Kategória megnevezése
IsExpense Azt jelöli, hogy a kategória kiadás-
e vagy bevétel
ParentCategory_Id
Idegen kulcs, egy adott kategória
szülőjére mutat. A
gyökérelemeknél a szülő kategória
azonosítója NULL
Locations Helyszínek
adatai
Id Elsődleges kulcs
Longitude Hosszúsági koordináta
Latitude Szélességi koordináta
Altitude Magassági koordináta
Postcode Irányítószám
City Város
Street Utca
Country_Id Idegen kulcs
Countries
Helyszínekhez
kapcsolódó
országok
Id Elsődleges kulcs
Name Ország neve
Currencies
Felhasználók
által használt
valuták adatai
Id Elsődleges kulcs
Code Valuta kód
Image Valuta szimbólum
Country_Id Idegen kulcs
4. táblázat: Az adatbázis tábláinak részletezése
4.1.4 Megjegyzések az adatmodellhez
Az adatmodell ebben a formájában nem támogatja a valuta átváltását bármely
dátumra visszamenőleg. Ha valamely kliens alkalmazás beállítások oldalán a valuta
átváltás opciót bekapcsoljuk, akkor a tranzakciós tételek mindig a lekérdezés aktuális
napjának árfolyamán lesznek konvertálva az alapvalutára. Az általam megvalósított
megoldás tehát nélkülözi a tétel dátumán érvényes valutaárfolyamot, mindig a
legfrissebbekkel dolgozik.
Az alábbiakban ismertetek egy elképzelést, mely szerint az adatbázis felkészíthető
lenne arra, hogy a tételeket a tranzakciós dátumnak megfelelő árfolyam szerint váltsuk
át. Ehhez először is szükségünk lenne az összes létező valutaárfolyamra azokon a
napokon, amelyeken történt tranzakció. Az architektúrában feltüntetett valuta kiszolgáló
támogatja a historikus valuta árfolyamok lekérdezését, azonban ez a lekérdezés időben
költséges művelet lenne minden egyes tétel esetén, amelyek külföldi valutában
szerepelnek. A művelet költségét csökkenthetjük azzal, ha a szerver adatbázisában
tároljuk a valutaárfolyamokat a számunkra szükséges dátumokon a következő tábla
felvételével: CurrencyRates(Id, Date, <Currency1...Currencyn>), ahol a
Currency1…Currencyn jelentik az egyes valuták értékét a mindenkori alapvalutához (1
dollárhoz) viszonyítva és az adott dátumra vonatkozóan. Még optimálisabb megoldás
45
esetén csak azon valuták értékét tároljuk, amelyeket használunk is az adott napon. Ezáltal
az adatbázisban állandóan rendelkezésre állhatnak historikusan a szükséges valuta
árfolyamok, melynek egy részét a szerver memóriájában tartva gyorsan hozzáférhetőek
lennének.
4.2 Szerver és a szolgáltatás
A specifikációban feltüntetett szerver központi szerepet tölt be a szolgáltatás-
orientált architektúrában (SOA – Service Oriented Architecture). Feladata, hogy IIS alatt
futasson egy WCF szolgáltatást. Ez a szolgáltatás gyakorlatilag egy .NET
osztálykönyvtár, mely kommunikál az adatbázissal és egy külső valuta szolgáltatóval. A
DLL (Dynamic-link library) egy WCF interfészt ajánl ki a kliensek számára, ami HTTP
protokollon keresztül érhető el a kliensek számára és megvalósítja az üzleti logikát
elfedve az adatbázis hozzáférést a kliens szoftverek fejlesztői elől. A szolgáltatás teljes
forráskódja a Service projektben található.
4.2.1 Üzleti logika
Az üzleti logikát teljesen egészében lefedi az alábbiakban ismertetett interfész és
annak implementációja a mögöttes adatbázissal együtt.
4.2.1.1 Adatbázis kontextus
Az adatbázis kontextust megvalósító osztály egy új projektbe került (Data), mely
akár egy külön szerveren is üzemelhet a szolgáltatást futtató szervertől, ha bármi
indokolná. A kontextus létrehozásnál figyelni kellett arra, hogy a Lazy Loading ki legyen
kapcsolva, ugyanis bekapcsolt állapotában a WCF nem tudja sorosítani a tábla-
osztályainkat7. Ezek a modell osztályok egyébként DataContract-ok is egyben, illetve
az adattagjaik DataMember attribútumokkal vannak ellátva, ha már a WCF
kontextusában használjuk őket. A Lazy Loading kikapcsolásával veszítünk ugyan a
kényelemből a lekérdezések során, azonban legalább két egyéb lehetőségünk is van
betölteni a kapcsolódó táblákat: Eagerly Loading és Explicitly Loading [32]. Eagerly
loading esetén a LinQ lekérdezés közben tudjuk betölteni a kívánt kapcsolódó entitásokat
az Include(<path>) függvény segítségével. Explicitly Loading esetén ki kell
7 Adatbázis táblákba képződő C# osztályok, Entity Framework és a Code First segítségével.
46
kényszerítenünk az explicit betöltését a kapcsolódó entitásnak, majd ezután ugyanúgy
használhatjuk az entitás már betöltött navigációs tulajdonságát, mintha a Lazy Loading
rendelkezésünkre állna. Lássunk egy-egy példát mindkét változatra a szolgáltatásból
hozott kódrészletekkel:
Eager loading példakód (egy felhasználó tranzakcióinak lekérdezése a kapcsolódó
táblákkal):
private IQueryable<Transaction> GetTransactionsByUser(int userID) { // Eagerly load related entites to a transaction var transactions = db.Transactions.Include("Category") .Include("Receipts").Include("Currency").Include("User"); // Get the user’s transactions var collection = from t in transactions where t.User != null && t.User.Id == userID select t; return collection; }
Explicit loading példakód (felhasználó törlése a kapcsolódó rekordokkal együtt):
public bool DeleteUser(int id, out string resultMsg) { try { var user = db.Users.Find(id); if (user == null) { resultMsg = "User not found!"; return false; } // Delete transactions of the user db.Entry(user).Collection(u => u.Transactions).Load(); var transactions = user.Transactions; if (transactions != null) { // Iterating over transactions of the user and delete them foreach (var t in transactions.ToList()) { db.Entry(t).Collection(t1 => t1.Receipts).Load(); . . . //Delete receipts associated with transaction db.Transactions.Remove(t); // Delete transaction } } . . . // Delete other related entites // Delete user db.Users.Remove(user); db.SaveChanges(); resultMsg = "Successfully deleted the user!"; return true; }
47
catch (Exception e) { // Something went wrong resultMsg = e.Message; return false; } }
4.2.1.2 Interfész és adatok
IExpenseService
Erre a közös interfészre kapcsolódhatnak a kliensalkalmazások. A
specifikációban ismertetett funkciók mindegyike elérhető ezen keresztül.
Az interfész egy ServiceContract, melyben a metódusok mindegyike
OperationContract attribútummal van ellátva.
Az interfész, illetve a következő alfejezetben ismertetett interfészt megvalósító
osztály is parciális, azaz az implementáció több részre van bontva, ami a gyakorlatban
annyit jelent, hogy a kódok külön fájlokban szerepelnek a könnyebb áttekinthetőség és a
funkciók kategorizálása miatt. A teljes interfészt leíró fájlok tartalmát az alábbi
felsorolásban ismertetem:
IExpenseService.cs: A kiinduló IExpenseService interfészt tartalmazó fájl.
Csupán teszt jellegű metódusokat tartalmaz, az ezt követő fájlokban ennek az
interfésznek a parciális darabkái találhatók meg.
ICategory.cs: Kategóriák menedzselésére vonatkozó metódusok. Ide tartozik
egy kategória törlése, szülő –és alkategória felvétele (csak admin felhasználók
számára érhetők el), valamint a különböző lekérdezések.
ICountry.cs: A helyszínekhez kapcsolódó országok lekérdezése.
ICurrency.cs: Valutákhoz kapcsolódó metódusok gyűjteménye. Fel tudunk
venni az adatbázisba egy-egy valutát, lekérdezhetünk az árfolyam szolgáltatótól,
illetve konvertálhatunk egy összeget másik valutára. A valutaváltáshoz az
adatokat az https://openexchangerates.org/ szolgáltatja, ahol a regisztrált
felhasználók JSON formátumban kérdezhetik le8 a legfrissebb, valamint az elmúlt
napokra vonatkozóan az egyes valutákhoz tartozó átváltási rátát.
8 Ingyenes licencszerződéssel 1000 lekérdezés/hónap
48
IPage.cs: Az egyes „oldalakra” vonatkozó adatok kérdezhetők le innen. 3
metódusa van: GetMainPageSource(…), GetOverviewSource(…),
GetDetailsSource(…), melyek mindegyike egy egyedi típusú
ObservableCollection-nel tér vissza. Alapvetően a mobil kliens korábban
elkészült felülete ihlette ezeket a metódusokat, hogy kiszolgáljon egy-egy
panoráma oldalt. Mivel azonban a web kliens is hasonló szerkezetű felületi
elemekkel és oldalakkal rendelkezik, ezért ott is tökéletesen használható volt.
IReport.cs: A kimutatásokhoz szükséges adatok lekérdező metódusai
tartoznak ide. Készült 4 különböző idő intervallumokra vonatkozó metódus (évi,
havi, heti és napi bontású), melyet később egyesítettem egy általánosabb
metódusba.
ITransaction.cs: Tranzakciók kezelése. Új tranzakció felvétele, meglévő
törlése, illetve lekérdezések tartoznak ide.
IUser.cs: A felhasználókra vonatkozó metódusgyűjtemény. Ide tartoznak a
következő funkciók: bejelentkezés, jelszó változtatás, törlés, lekérdezések,
beállítások mentése, illetve a jelszó egyezés ellenőrzése.
Természetesen az interfész metódusai által igényelt egyedi típusokhoz tartoznak
megfelelő osztályok, melyek mindegyike egy-egy DataContract.
4.2.1.3 Implementáció
A fentebb ismertetett interfészt egyetlen osztály valósítja meg, az
ExpenseService. Mint azt már olvashattuk, a teljes osztály itt is több fájlra lett bontva,
az interfész darabkákat tartalmazó fájlokkal összefüggésben:
ITransaction.cs TransactionOperations.cs,
ICurrency.cs CurrencyOperations.cs és így tovább…
Osztály szinten egy adatbázis kontextust tartok fenn, melyet az osztálypéldány
elpusztulásakor felszabadítok (Dispose minta [33]), így egy helyen cserélhető az aktuális
adatbázis kontextus és nincs szükség minden egyes adatbázis lekérdezésnél (valójában
LinQ to Entities lekérdezéseknél) létrehoznunk azt egy using blokkon belül. Hátránya,
hogy nincs lezárva az adatbázis kapcsolat a lekérdezés végrehajtása után.
49
A szolgáltatás implementációból egy kódrészletet emelnék ki némi magyarázattal
együtt. A valuta szolgáltatóval való kommunikáció részletébe pillanthatunk bele, mely
során az érkezett adatokat egy statikus gyűjteményben (Currencies) tárolom el a
szerver memóriájában.
CurrencyOperations.cs kódrészletek:
// Get currencies from provider if they are not up to date private void GetCurrenciesIfNotUpToDate() { if (Currencies == null || Currencies.Count <= 0 || CurrencyLastUpdatedDate.Date < DateTime.Now.Date) {
// block async operation (wait for the result) AsyncContext.Run(() => this.GetCurrenciesAsync()); } } // Trying to get currencies from the provider (openexchangerates) // in JSON format private async void GetCurrenciesAsync() { var httpClient = new HttpClient(); await httpClient.GetStreamAsync("http://openexchangerates.org/api" + "/latest.json?app_id=" + OpenExchangeApiKey) .ContinueWith(r => { Stream responseStream = r.Result; // Serializing response var serializer = new DataContractJsonSerializer( typeof(CurrencyResponse)); var jsonResponse = serializer.ReadObject(responseStream) as CurrencyResponse; if (jsonResponse == null) return; lock (CurrencyLock) {
// Uploading response to the currencies collection Currencies.Clear(); foreach (var item in jsonResponse.GetCurrencies()) { Currencies.Add(item); }
// Set currency last updated time to now CurrencyLastUpdatedDate = DateTime.Now; } }); }
50
A GetCurrenciesIfNotUpToDate() metódus minden valuta konvertálás
esetén hívódik meg, így egy ilyen környezetben képzeljük el. Hamar észrevehetjük, hogy
a metódus egyetlen feladata, hogy bizonyos feltétel esetén futassa a
GetCurrenciesAsync() függvényt. A feltétel akkor teljesül, ha üres a
valutaárfolyamokat tároló statikus kollekciónk (Currencies) vagy már elavult
árfolyamokat tartalmaz (jelenleg az 1 napnál régebbi árfolyamokat tekintem elavultnak).
Ekkor szeretnénk a külső árfolyam szolgáltatótól lekérdezni az aktuális állapotot és
feltölteni az árfolyam tárolónkat a friss adatokkal. Azt is megfigyelhetjük, hogy a hívandó
aszinkron valuta lekérdező függvény az AsyncContext.Run() metódusnak lett átadva
Action delegate típusú paraméterként. Ez az aszinkron kontextus a Nito AsyncEx
[35] osztálykönyvtárból származik. A feladata, hogy egy aszinkron függvényt szinkron
módon futtasson, tehát bevárja, míg feldolgozásra kerül a GetCurrenciesAsync()
függvényben indított httpClient.GetStreamAsync(<url>) kérés válasza, vagy
amíg nem keletkezik kivétel. Szükségem volt arra, hogy mindenképp szinkron módon
kérhessem el a valutákat, mert a hívás helye utána rögtön használni szeretném a friss
értékeket a valuta konvertáló függvényben.
Érdemes még figyelmet szentelni a valuták feltöltésekor használt zárra (lock).
Mivel egy web szolgáltatás kontextusában helyezkedik el az üzleti logika, ezért a
szolgáltatást megvalósító osztály statikus adattagjainak írásakor kétszer is fontoljuk meg
a zárak használatát. Úgy képzeljük el az egészet, mintha egy többszálú környezetben
lennénk, ahol párhuzamosan is indulhat egy-egy valuta-konvertálás. A többszálú
környezetet most a felhasználók kérései jelentik és bizony előfordulhat, hogy egyszerre
két kérés is befut, előteremtve a konkurenciát [35]. Ha nem szeretnénk, hogy hol az egyik,
hol a másik szál töltse fel a valuta gyűjteményt, ami könnyen duplikátumokat okozhat,
akkor érdemes zárolni a közösen használt erőforrást, hogy egyszerre csak egyvalaki férjen
hozzá, amíg a másik várakozni kényszerül.
Az üzleti logikát segítendő, a szolgáltatás tartalmaz pár statikus Helper metódust
is. Ide tartoznak a különböző bővítő metódusok (extension methods), a kimutatás diagram
színezéséhez használt színárnyalatot manipuláló függvények, adat-validációs
függvények, az e-mail küldéshez használt kódrészlet, illetve egy új véletlen jelszót
generáló függvény.
51
4.3 Kliens alkalmazások
Ebben az alfejezetben a megvalósított kliens alkalmazásokat tekinthetjük át.
Túlzottan részletes leírás nem férne bele a dolgozat keretébe, így a megvalósítás
mérföldköveit mutatom be, külön kiemelve a fejlesztői szempontból érdekes, kihívást
jelentő problémák megoldását.
4.3.1 Mobil kliens (WP8)
Az első kliens, ami a fejlesztés során elkészült, az a Windows Phone 8 platformra
íródott mobil alkalmazás.
4.3.1.1 Felhasználók kezelése
A felhasználói adatok tárolása úgy valósul meg, hogy a telefon helyi tárolójában,
az IsoStore-ban jegyzem fel (szerializálom9) az aktuálisan bejelentkezett felhasználóhoz
tartozó objektumot. Így, ha egyszer sikeresen beléptünk az alkalmazásba, akkor a további
használat során automatikusan be leszünk jelentkezve. A bejelentkező oldal csak akkor
jelenik meg, ha az alkalmazáshoz tartozó beállítások között nem található meg az aktuális
felhasználó adatai vagy éppen felhasználót váltunk.
4-2. ábra: Bejelentkezés és regisztráció mobilon
9 Szerializáció – segítségével egy objektum bájt-sorozatként reprezentálható egy fájlban. Ez a fájl
információt fog tartalmazni az objektum típusáról és minden adattagjáról, így az objektum állapotát
eltárolhatjuk.
52
A mobil kliens az aktuálisan bejelentkezett felhasználó mellett megjegyzi a
beállított nyelv, valuta konvertálás és az alapvaluta beállításokat is, mely beállításokat
szintén az IsoStore-ban tárolok.
4.3.1.2 Felület
A kliens felületét a METRO elveknek megfelelően próbáltam létrehozni, ahol a
hangsúly a tartalmon van. A kialakított felület így letisztult és átlátható képet ad a
felhasználók számára.
A kezdőképernyőn egy Panorama vezérlő található, három elemmel:
A Transactions (tranzakciók) oldal a tranzakciókhoz tartozó műveletek
lebonyolításáért felelős. A gombok felett található egy piros-zöld sáv, ami
a kiválasztott hónapban a kiadások/bevételek arányát szemlélteti. Továbbá
itt találhatók még a funkció gombok, melyek a kiválasztott művelethez
tartozó oldalra navigálnak minket.
Az Overview (áttekintő) oldalon megtekinthetjük a bevitt tételeket
részletesen napokra lebontva az aktuális hónapra vonatkozóan.
A Settings (beállítások) oldalon végezhetjük el az alkalmazásra érvényes
beállításokat, melyek automatikusan mentésre kerülnek az alkalmazás
bezárásakor, illetve deaktiválásakor. Itt állíthatjuk be a nyelvet
(magyar/angol), az alapvalutát, illetve a valuta átváltás módját (csak az
alapvalutabeli tételek megjelenítése vagy az összes tétel jelenjen meg
szükség esetén konvertálva az alapvalutára).
Az alábbi képen láthatjuk a panoráma vezérlő alkalmazását a főoldalon, melyen
minden lényeges funkciót hamar elérhetünk.
53
4-3. ábra: Panoráma főoldal
A legfontosabb funkció az alkalmazásban a tranzakciók bevitele. Tranzakció
hozzáadásakor a 4-4. ábra-n látható „Új tranzakció” feliratú képen is látható mezőket kell
megadnunk:
Amount (összeg): a tétel összege
Date (dátum): a tétel dátuma
Category (kategória): választhatunk megfelelő kategóriát attól függően,
hogy Income vagy Expense tételt rögzítünk. Lehetőségünk van új kategória
felvételére is, illetve egy kiválasztott kategória törlésére, ha admin
jogosultsággal rendelkezünk.
Payment (fizetőeszköz): fizető eszköz, valuta kiválasztása
Photo (photo): a telefon kamerája segítségével lefényképezhetjük a
tranzakcióhoz kapcsolódó számlát vagy blokkot. (nem kötelező)
Note (megjegyzés): megjegyzés hozzáfűzése (nem kötelező)
Location (helyszín): helyszín kiválasztása. Bing térkép segítségével tudjuk
kiválasztani a kívánt tartózkodási helyet (nem kötelező)
Az alábbi képen megtekinthetjük, hogyan néz ki egy új tranzakció hozzáadása és
néhány ehhez kapcsolódó választási lehetőség kezelőfelülete:
54
4-4. ábra: Új tranzakció hozzáadása
4.3.1.3 Kimutatás
A bevitt tranzakciókról célszerű készíteni valamilyen kimutatást is, hogy jobban
átlássuk a kiadott vagy éppen a bejövő összegek eloszlását. A tételek grafikus
reprezentálására mobil platformon a kördiagramot választottam, melyen éves, havi, heti,
illetve napi bontásban tekinthetjük meg kategóriánként csoportosítva a
bevételeinket/kiadásainkat.
4-5. ábra: Kördiagram kimutatás a kiadásokról és bevételekről a mobil kliensen
A kördiagram ábrázolásához készítettem egy saját vezérlőt (user control), melyet
egy külső osztálykönyvtárban (class library) implementáltam, lehetővé téve, hogy esetleg
más WPF/Silverlight felületű alkalmazásokban is felhasználható legyen.
Az alábbi metódus felelős egy körszelet kirajzolásáért:
55
private void drawPiChartSlice(double startAngle, double ratio) { Path path = new Path(); // . . . path kitöltés, vonalstílus Point point = new Point { X = 0.0, Y = 0.0 }; PathGeometry pathGeometry = new PathGeometry(); PathFigure pathFigure = new PathFigure(); pathFigure.StartPoint = new Point(0, 0); pathFigure.IsClosed = true; double angle = 360 * ratio / 100; if (angle == 360) { angle = 359.99; } // Starting Point LineSegment lineSegment = new LineSegment(); lineSegment.Point = new Point(this._radius, 0); // Arc ArcSegment arcSegment = new ArcSegment(); arcSegment.IsLargeArc = angle >= 180.0; arcSegment.Point = new Point(Math.Cos(angle * Math.PI / 180) * this._radius, Math.Sin(angle * Math.PI / 180) * this._radius); arcSegment.Size = new Size(this._radius, this._radius); arcSegment.SweepDirection = SweepDirection.Clockwise; pathFigure.Segments.Add(lineSegment); pathFigure.Segments.Add(arcSegment); pathGeometry.Figures.Add(pathFigure); path.Data = pathGeometry; RotateTransform rotate = new RotateTransform { CenterX = 0, CenterY = 0, Angle = startAngle }; path.RenderTransform = rotate; // Add pie chart slice to the placeholder this._piChartHolder.Children.Add(path); }
Bemeneti paraméterek:
startAngle – honnan kezdődjön a körszelet (fok)
ratio – körszelet mérete százalékban
56
Létrehozok egy PathGeomerty típusú változót, melyben felépítem a körcikk
alakzatot. A ratio értékéből kiszámítom a körcikk belső szögét (látószög). A
megjelenítéshez szükségem lesz LineSegment-re a határoló vonal megrajzolásához,
valamint ArcSegment-re, a cikkely kirajzolásához. A cikkely szegmenset 90 foktól
kezdve rajzolom ki, az előzőleg számított látószöget felhasználva. A felparaméterezett,
elkészült szegmenseket felveszem a PathGeometry alakzatok listájába. Mindezek után
szükségem lesz egy forgatásra, hogy a megfelelő irányba álljon a körcikk (itt használom
fel a startAngle paramétert). A visszatérés előtt hozzáadom az elkészült útvonalat (Path)
a tárolóhoz (placeholder), ami jelen esetben egy Canvas vezérlő.
4.3.1.4 Lokalizáció
Az alkalmazás jelenleg angol és magyar nyelv között képes váltani valós időben.
A Windows Phone telefonoknál egy szokás, hogy az operációs rendszer beállításaiban
kiválasztva a telefon használati nyelvét azt az alkalmazások figyeljék induláskor, így egy
közös helyen válthatunk nyelvet. Adódik azonban néhány probléma ezzel a megoldással:
nem tudunk valós időben nyelvet váltani
szükségünk lehet újraindítani a telefont egy új nyelv kiválasztása után
az éppen futó alkalmazásunk Running állapotból Tombstoned állapotba
kerül, tehát a használat folytonossága megtörik (lásd 2.3.2-es fejezetben)
Így feltétlenül szükségét éreztem annak, hogy a kliensalkalmazáson belül is
lehetőség legyen nyelvet változtatni. A megoldáshoz át kellett gondolnom, hogy
miképpen lehetne Culture-t váltani úgy, hogy arról az érintett elemek is értesüljenek.
Alapvetően minden UI elem, amin bármiféle szöveg van
a LocalizedStrings osztályra van kötve (bind-olva), ez tartalmazza az
aktuális AppResources referenciát (itt találhatóak a név – érték párokban megadott
szöveg fordítások).
Amikor a felületen a nyelvválasztó gombra kattintunk, akkor az alábbi metódus
gondoskodik arról, hogy kicserélje az aktuális alkalmazás Culture-t, ami egyben azt is
jelenti, hogy a megfelelő AppResources.resx fájl kerül felhasználásra (pl.
AppResources.hu.resx - magyar nyelv esetében). Az átadott paraméter a kívánt
kultúra rövidítése (hu, en-US):
57
public void SetUILanguage(string locale) { CultureInfo newCulture = new CultureInfo(locale); Thread.CurrentThread.CurrentCulture = newCulture; Thread.CurrentThread.CurrentUICulture = newCulture; AppResources.Culture = newCulture; ResourceTracker.OnPropertyChanged("Culture"); //. . . Set the FlowDirection of the RootFrame to match the new culture. //. . . Set the Language of the RootFrame to match the new culture. }
A bind-olt UI elemek azonban erről a változásról alapesetben nem fognak
értesülni, így létrehoztam egy statikus osztályt (ResourceTracker) egy eseménnyel,
amit minden AppResources.Culture értékadás után elsütök (kiemelt rész a kódban).
Erre az eseményre van feliratkozva a LocalizedStrings osztály (amire az UI
szövegek vannak kötve), amit kibővítettem, hogy implementálja
az INotifyPropertyChanged eventet. Így amikor elsül a ResourceTracker
eseménye, elsütök egy PropertyChanged eseményt a LocalizedStrings-en belül is
és így már frissülnek a felületen található szövegek is a kiválasztott nyelvnek
megfelelően.
58
4.3.2 Web kliens (ASP.NET MVC)
A web kliens fejlesztéséhez az ASP.NET MVC 4 –es keretrendszert használtam
fel. A szükséges üzleti logikát a szolgáltatás már tartalmazza, így az igényes megjelenés
és a felhasználóbarát környezet kialakítására került a fő hangsúly.
4-6. ábra: Web kliens főoldal
4.3.2.1 Felhasználók kezelése
A felhasználók kezelése során nem támaszkodtam az MVC 4 autentikációs
csomagjára, helyette a szolgáltatásban megvalósított felhasználó kezelést vettem igénybe
kiegészítve a Session használatával. Típusos és egységes Session kezelést valósítottam
meg kontroller szinten, az alábbi módon:
BaseController.cs részlet:
public class BaseController { . . . // Session handler property protected BaseSessionData BaseSession { get { string sessionName = this.GetType().Name; return (BaseSessionData)(Session[sessionName] ?? (Session[sessionName] = new BaseSessionData())); } } . . . }
59
[Serializable] public class BaseSessionData { public User User { get; set; } . . . }
Látható, hogy a BaseSessionData tároló osztályba csomagoltam a
felhasználóhoz tartozó adatokat. A Session kontrollerfüggő elemét a BaseSession
propertyben típusossá alakítva érhetjük el és így kényelmesen hozzáférhetünk az aktuális
felhasználói adatokhoz. Pl. int userid = BaseSession.User.Id értékadás a
Session-ből fogja előhalászni a felhasználó azonosítóját.
Szintén a BaseController-ben minden egyes kérés előtt ellenőrzöm, hogy az
aktuális felhasználó be van-e jelentkezve. Mivel a kontrollerek megvalósítják az
IActionFilter interfészt (Controller ősosztály implementálja), így lehetőségem
van beavatkozni az MVC szekvenciába, mielőtt egy Action-höz érkezne az eseménysor,
amennyiben felülírom (override) az OnActionExecuting(..) függvényt:
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) { // If we are at the login page do nothing var action = filterContext.RouteData.Values["action"].ToString(); var controller = filterContext.RouteData.Values["controller"].ToString(); if (controller == "Account" && (action == "Login" || action == "Register" || action == "PasswordReminder")) return; // Check if the current user is logged in before executing any action if (!this.LoggedIn) { // We are not logged in -> Redirect to the Login page filterContext.Result = RedirectToAction("Login", "Account"); } // . . . Load user settings to a ViewBag base.OnActionExecuting(filterContext); }
Ha a bejelentkező oldal felől érkezik a kérés (Account controller,
Login/Register/PasswordReminder action-je felől), akkor tovább engedjük az action
végrehajtással kapcsolatos szekvenciát, különben pedig ellenőrizzük, hogy a felhasználó
valóban be van-e jelentkezve (ezt a BaseSession-ből könnyedén kideríthetjük). Ha
nincs, akkor a login oldalra irányítjuk.
60
A bejelentkezés, kijelentkezés, regisztráció, jelszó változtatás, beállítások
kezelése, valamint a felhasználó törlése funkciók természetesen már a szolgáltatással
kommunikálva valósulnak meg, szükség esetén módosítva a BaseSession-ben tárolt
aktuális felhasználóhoz tartozó tulajdonságok értékét.
4-7. ábra: Belépés és regisztráció felületének részlete
4.3.2.2 Kontrollerek
Minden egyedi vezérlőm a BaseController-ből származik, ami főleg a
felhasználók kezeléséről gondoskodik számunkra, mint ahogy azt az imént is láthattuk.
Emellett tartalmaz még néhány segédmetódust, melyekre szükségem lehet a leszármazott
vezérlőkben.
A kontrollerek fő feladata, hogy WCF-en keresztül kommunikáljanak a
szolgáltatással és átadják a szükséges adatokat a nézetek (View) számára. A vezérlőket
funkciójuk szerint csoportosítottam az alábbi osztályokra:
AccountController: Bejelentkező oldalhoz tartozó funkciók, illetve
bejelentkezés után a felhasználói profil funkciót menedzseli.
CategoryController: Ide tartozik a Categories oldal kiszolgálása
(kategóriák listázása), a kategória választó legördülő menük megjelenítése
(parciális nézetként), és természetesen a kategóriák kezeléséhez tartozó
segéd metódusok, action-ök.
CurrencyController: A valuta konvertáláshoz tartozó, listázó segéd
metódusok és a valutaválasztó legördülő elemet kiszolgáló action-ök
vannak itt.
61
HomeController: A főoldalon található elemek megjelenítése. A
kiadás/bevétel arányát megjelenítő „grafikon”-hoz szükséges adatokat
szolgáltatatja.
OverviewController: Az Overview oldal tranzakció listázásához, a
részletek megjelenítéséhez és egy-egy tétel törléséhez tartozó action-ök
tartoznak ide.
ReportController: A kimutatás diagramokhoz tartozó vezérlő.
Parciális nézetben jeleníti meg a kívánt szűrési feltételeknek megfelelő
grafikont.
TransactionController: Új tranzakció felvételére vonatkozó
kontroller.
4.3.2.3 Nézetek
Igyekeztem a megjelenítés során minél több komponenst a kliens oldalról indítva
AJAX10 hívásokkal betölteni, ezzel is kényelmesebbé és gyorsabbá téve a szoftver
használatát. Természetesen vannak olyan nézetek is, melyek nem tartalmaznak parciális
elemet, ezek a Controller megfelelő action-jének ViewResult-jaiből állnak elő. A
kliens oldali szkriptekre külön hangsúlyt fektettem, szintén a látvány és az élmény
fokozása érdekében. A 4-8. ábra-n megfigyelhetjük, hogyan zajlik azon nézetek
előállítása, ahol egy-egy komponens betöltése AJAX módon történik:
4-8. ábra: Nézet előállítása AJAX segítségével [7]
Először egy kontroller action-je kezdeményezi a teljes nézet előállítását (1), majd
a kliens oldali jQuery [36] kód segítségével aszinkron módon betöltjük a nézet hiányzó
10 AJAX – Asynchronous JavaScript and XML. Aszinkron kliens-oldali kérések valósíthatók meg
vele, az oldal újratöltése nélkül. Ez növeli a honlap interaktivitását, sebességét és használhatóságát.
62
kisebb elemeit (2 és 3). Ezen elemek tartalma később önmagukban is frissíthetők, nem
szükséges az egész oldalt újratölteni. Nézzük egy példát egy parciális nézet betöltésére:
Views/Report/Index.cshtml részlet:
<script type="text/javascript"> $(document).ready(function () { // . . . // --- INIT --- initExpenseBtn(); initTabPage(); // ------------- // . . .
function refreshChart() { // Get chart $.get('@Url.Action("Chart", "Report")' +
'?type=' + paramType + '&filter=' + paramFilter + '&date=' + paramDate + '&chartType=' + paramChartType,
function (data) { $("#barChartData").html(data); }); }
// . . . }); </script>
Ebben az esetben a kimutatás oldal (Report) letöltése után a böngészőben összeáll
az oldal (Document Ready), majd ennek a „kész” eseménynek a hatására az inicializálós
függvények (initExpenseBtn(), initTabPage()) meghívásával együtt lefut a
refreshChart() JavaScript függvény. Továbbá minden szűrési feltétel módosítása
esetén is meghívódik ez a függvény, legyen az akár kiadás/bevétel közötti váltás, dátum
módosítás vagy a szűrési idő intervallum (összes, év, hónap, hét, nap) változtatása. A
refreshChart() aszinkron módon visszaszól a szerver action-jének (URL-en
keresztül), hogy kellene még a hiányzó View darabka is. A szűrési paramétereknek
megfelelően a Report kontroller Chart action-jéhez fut be a kérés. Miután az action
feldolgozta és előállította az adatokat szükséges grafikonhoz, elküldi a választ a kliens
oldalnak, ami már tartalmazza a kért grafikont. A tartalmat betöltjük a barChartData
div-be, végül a kívánt grafikon megjelenik a böngészőben a teljes oldal újratöltése nélkül:
63
4-9. ábra: Költség-kimutatás oszlop –és kördiagramokon
4.3.2.4 Felület
A web kliens projektet (WebClientApp) a Telerik Kendo UI for ASP.NET MVC,
Bootstrap 2.3.2 és a Twitter Bootstrap for ASP.Net MVC 4 1.0.9011 csomagok
felhasználásával készítettem. A Kendo UI csomagot a diagramok megjelenítéséhez
használtam fel, míg az utolsó kiegészítő HTML Helperekkel és segédosztályokkal
könnyíti meg számunkra a bootstrap használatát.
A felület kialakítása során reszponzív webdesign-t alkalmaztam, így akár mobilról
böngészve is kényelmesen használhatóvá vált az oldal. A reszponzivitást nagymértékben
elősegítette a Bootstrap (a bootstrap-responsive.css stílusfájl használatával),
azonban előfordultak olyan felületi elemek, ahol szükséges volt kiegészíteni a Bootstrap
stílus definícióit. Ezek a kiegészítések a Custom-responsive.css fájlban találhatók.
11 A NuGet csomag elérhetősége: https://www.nuget.org/packages/twitter.bootstrap.mvc4/1.0.90
64
Ilyen felületi elem például az oldal alján elhelyezkedő lábléc (footer), melyre az alábbi
reszponzív stílus szabályok érvényesek:
@media (min-width: 1367px) and (max-height: 640px) { footer { display: none; } } @media (min-width: 768px) and (max-width: 1366px) and (max-height: 639px) { footer { display: none; } } @media (max-width: 767px) and (max-height: 1000px) { footer { display: none; } }
A fentebb látható CSS (Cascading Style Sheet) stílusleírás elrejti a böngésző ablak
aljára pozícionált footer-t a media-query-kben meghatározott szélesség és magasság
intervallumok esetén, amire azért volt szükség, mert ha kis méretben böngésszük az
oldalt, akkor belelógott az oldal tartalmába.
Az alábbi képeken láthatjuk, hogyan érvényesül a reszponzív design egy
okostelefon felbontásához igazítva:
4-10. ábra: Webes felület alacsony felbontáson megjelenítve
65
5 Összefoglalás
A dolgozatban először a keretrendszer fejlesztéséhez felhasznált .NET-es
technológiákat ismertettem a kapcsolódó kiegészítő csomagokkal együtt, összehasonlítva
alternatív technológiai megoldásokkal is.
Ezután a specifikációban lefektettem a rendszerrel szemben elvárt
követelményeket, ismertetve a megvalósítandó funkciókat, a felhasználói szerepköröket
és a rendszer vázlatos architektúráját. A folyamat végén nekiláthattam az alkalmazások
tervezéséhez és fejlesztéséhez.
Utolsó lépésként a megvalósítás folyamatát közöltem, a tervezés során előforduló
döntésekkel és az implementációból kiemelt kódrészletekkel együtt. Először az adatbázis
tervezői döntéseit ismertettem, a végén bemutatva az elkészült adatbázis modelljét. A
további részekben a szolgáltatás által nyújtott interfész feladatköreit részleteztem. Az
elkészült kliens alkalmazásokat a legvégén mutattam be, kiemelve egy-egy platform
specifikus megoldást.
A megvalósított keretrendszer megfelel a specifikációban megfogalmazott
követelményeknek. Egy olyan költségnyilvántartó keretrendszer jött létre, mely stabil
alapokon nyugszik, valódi életben is használható és egyszerű bővítési lehetőségekkel
rendelkezik, akár újabb kliens alkalmazások hozzáadásával is. A felhasználók a felmerülő
költségeiket hatékonyan nyilvántarthatják a rendszer használatával. A tételeket
kategóriák szerint vehetik fel az összes létező valutában, melyeket aztán szűrhető
kimutatásokon és áttekintő listában böngészhetnek. Az egyes valuták alapvalutára történő
átváltását a rendszer automatikusan biztosítja, az aktuális napi árfolyamon. A kliensek
felülete letisztult, egyszerűen átlátható és könnyen kezelhető, a tartalmon van a fő
hangsúly. A rendszer az otthoni felhasználók és kisvállalkozások számára is egyaránt
hasznos lehet.
A szakdolgozat készítése során több .NET-es technológiát is tanulmányozhattam.
A szolgáltatás fejlesztéséhez a WCF-et használtam fel, míg a kliens szoftverek készítése
közben megismerkedhettem az ASP.NET MVC webes keretrendszerrel, a Windows
Phone 8 mobil platformmal, illetve az ezekhez kapcsolódó kiegészítő csomagokkal és
osztálykönyvtárakkal, mint pl. a jQuery, Telerik Kendo UI, Twitter Bootstrap és a
Windows Phone Toolkit.
66
5.1 Továbbfejlesztési lehetőségek
A továbbfejlesztésnél a célom az lenne, hogy minél több felhasználó érdeklődését
keltsem fel a rendszer iránt, melyre az újabb kliens alkalmazások megvalósításával
nagyobb esélyeim vannak.
Azon is érdemes elgondolkodni, hogy mivel lehetne még hasznosabbá tenni a
rendszert. Az adatbázis tervezésénél utaltam rá, hogy az ismétlődő tételek kezelését
tervezem megvalósítani. Elég csak a havi befizetendő számlákra vagy a rendszeresen
érkező fix jövedelemre gondolni, és máris értelmét nyeri a funkció. Részletesebb szűrési
lehetőségeket, másfajta kimutatásokat is lehetne készíteni. Szintén utaltam rá, illetve egy
megoldási javaslatot is tettem arra, hogy egy külföldi tranzakció összegének alapvalutára
történő átváltásakor lehetőséget kellene adnom arra, hogy a tranzakció dátumának
megfelelő árfolyamon történjen a konverzió. Még egy jól működő párkapcsolatban,
illetve barátok között is gyakran okozhat problémát a költségek közös elszámolása. Az
egymással kapcsolatban álló fiókoknak a támogatását is szeretném megvalósítani, ahol
képet kaphatunk arról, hogy ki mennyivel tartozik a másiknak, hogy ne legyen többé
probléma a tartozások nyilvántartása sem.
A jelenlegi keretrendszer adatbázis lekérdezéseit szükséges lehet optimalizálni,
illetve átvizsgálni a rendszert teljesítmény szempontjából. A szolgáltatás sokszor fordul
az adatbázisszerverhez, pár adatot lehetne cache-elni. A megvalósított Windows Phone 8
mobil kliens alkalmazást WiFi mellett érdemes használni, mert gyakran kommunikál a
szolgáltatással. Egy optimálisabb megoldás lehet, ha a telefon helyi tárolójában tárolnám
a felhasználóhoz tartozó adatokat, tranzakciókat, majd ezt időnként szinkronizálom a
szerverrel (illetve a felhasználó is kérheti a szinkronizálást). Ezzel csökkenne a mobil
adatforgalom, viszont nem mindig legfrissebb adatokkal dolgoznánk. Megfontolandó,
hogy a szélesebb kliensoldali támogatottság érdekében a szolgáltatást Web API alapokra
helyezzem, ezáltal is csökkentve a hálózaton átvitt adat mennyiségét.
Látható tehát, hogy bőven adódnak fejlesztési lehetőségek, amiknek a kiaknázása
egy még szerethetőbb terméket hozhat létre.
67
Irodalomjegyzék
[1] Jon Galloway, Phil Haack, Brad Wilson, K. Scott Allen: Professional ASP.NET
MVC 4
[2] ASP.NET: Single Page Application, http://www.asp.net/single-page-application
(2014. április)
[3] ASP.NET: Web Pages, http://www.asp.net/web-pages (2014. április)
[4] ASP.NET: Web Forms, http://www.asp.net/web-forms (2014. április)
[5] ASP.NET: MVC, http://www.asp.net/mvc (2014. április)
[6] ASP.NET: SignalR, http://www.asp.net/signalr (2014. április)
[7] Regius Kornél: ASP.NET MVC 4+, Szöveg verzió: V1.0.0827,
http://bit.ly/mvc4plusc (2014. március)
[8] Kovács Ferenc: Adatvezérelt alkalmazások fejlesztése előadás jegyzet (BME,
AUT, 2013)
[9] CodeProject, ASP.NET MVC 4 - Part [1] – Introduction,
http://www.codeproject.com/Articles/470107/ASP-NET-MVC-Part-Introduction
(2014. március)
[10] Danny Dover: Search Engine Optimization (SEO) Secrets, 1st edition (2011)
[11] CodeProject, Marla Sukesh: WebForms vs. MVC,
http://www.codeproject.com/Articles/528117/WebForms-vs-MVC (2014. május)
[12] Twitter Bootstrap v2.3.2, http://getbootstrap.com/2.3.2/ (2014. május)
[13] TwitterBootstrapMVC, https://www.twitterbootstrapmvc.com/ (2014. április)
[14] Telerik Kendo UI, http://www.telerik.com/kendo-ui (2014. május)
[15] Albert István, Fekete Krisztián: Windows Phone alapú szoftverfejlesztés előadás
jegyzet (BME, AUT, 2013)
[16] Andy Wigley, Rob Tiffany: M5: Windows Phone 8 Application Lifecycle,
http://download.microsoft.com/download/8/8/E/88E56A15-50E6-42D0-A71A-
CCD5673425C4/S5%20WP8%20Application%20Lifecycle.pdf (2014. május)
[17] MSDN Blogs, Brandon Bray: Announcing the release of the .NET Framework for
Windows Phone 8,
http://blogs.msdn.com/b/dotnet/archive/2012/10/30/announcing-the-release-of-
the-net-framework-for-windows-phone-8.aspx (2014. május)
68
[18] MSDN Blogs, Deepti Prakash: Compile in the Cloud with WP8,
http://blogs.msdn.com/b/msgulfcommunity/archive/2013/03/16/compile-in-the-
cloud-with-wp8.aspx (2014. május)
[19] GitHub, PropertyChanged.Fody, https://github.com/Fody/PropertyChanged
[20] CodePlex, Windows Phone Toolkit, http://phone.codeplex.com/
[21] CodePlex, AppBar Utils, http://appbarutils.codeplex.com/
[22] CodePlex, Coding4Fun Toolkit, https://coding4fun.codeplex.com/
[23] CodePlex, Windows Phone IsoStoreSpy, http://isostorespy.codeplex.com/
[24] Benedek Zoltán: Az újgenerációs .NET platform előadás jegyzet (BME, AUT,
2012)
[25] CodeProject, Praveen Kumar Katiyar: Understanding Contracts in WCF,
http://www.codeproject.com/Articles/664238/Understanding-Contracts-in-WCF
(2014. május)
[26] Roy Thomas Fielding: Architectural Styles and the Design of Network-based
Software Architectures, Doctoral dissertation, Chapter 5 (University of California,
Irvine, 2000), http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
[27] Reiter István: ASP.NET MVC Web API (2013), https://devportal.hu/download/E-
bookok/ASP.NET%20MVC%20Web%20API.pdf (2014. május)
[28] MSDN, WCF and ASP.NET Web API, http://msdn.microsoft.com/en-
us/library/jj823172(v=vs.110).aspx (2014. május)
[29] MSDN, Windows Communication Foundation, http://msdn.microsoft.com/en-
us/library/dd456779(v=vs.110).aspx (2014. május)
[30] Julia Lerman: Programming Entity Framework, 2nd Edition (2010)
[31] ITWorld, Matthew Mombrea: 3 reasons to use code first design with Entity
Framework, http://www.itworld.com/development/405005/3-reasons-use-code-
first-design-entity-framework (2014. április)
[32] MSDN, Loading Related Entities, http://msdn.microsoft.com/en-
us/data/jj574232.aspx (2014. április)
[33] MSDN, Dispose Pattern, http://msdn.microsoft.com/en-
us/library/b1yfkh5e(v=vs.110).aspx (2014. április)
[34] CodePlex, Stephen Cleary: Nito AsyncEx, http://nitoasyncex.codeplex.com/
(2014. április)
[35] Stephen Cleary: Concurrency in C# Cookbook
[36] jQuery, http://jquery.com/
69
Függelék: Kliensek egyéb funkciói
Jelen függelékben a dolgozatból kimaradt ábrák találhatók a mobil, valamint web
kliens felületéről, melyeken a nem részletezett funkciókat tekinthetjük meg.
Az 5-1. ábra a mobil kliens egyéb oldalait mutatja, magyar nyelvi beállítás mellett:
5-1. ábra: Valuta átváltás, új kategória és a tranzakció részletező oldalak (WP8)
Az alábbi képeken a web kliens nem ismertetett funkciónak a felületét láthatjuk:
5-2. ábra: Új kategória létrehozása (web)
70
5-3. ábra: Valuta átváltás (web)
5-4. ábra: Felhasználói beállítások (web)
5-5. ábra: Áttekintő lista részlete (web)