Professional Documents
Culture Documents
Krešimir Fertalj
Ivana Nižetić Kosović
Boris Milašinović
Razvoj primijenjene
programške potpore
Skripta
Predgovor ................................................................................................................................................ 1
1 Osnove programskog inženjerstva .................................................................................................. 2
1.1 Programska potpora ................................................................................................................ 2
1.2 Osnove programskog inženjerstva .......................................................................................... 2
1.3 Programsko inženjerstvo i srodna područja ............................................................................ 2
1.4 Modeli razvojnog procesa ....................................................................................................... 3
1.5 Životni ciklus programske potpore .......................................................................................... 3
1.6 Vodopadni model .................................................................................................................... 5
1.7 Iterativni postupak razvoja ...................................................................................................... 6
1.8 Ekstremno programiranje ....................................................................................................... 7
1.9 Zadaci....................................................................................................................................... 9
2 Specifikacija zahtjeva..................................................................................................................... 10
2.1 Vrste zahtjeva ........................................................................................................................ 10
2.2 Primjeri loše definiranih zahtjeva.......................................................................................... 11
2.3 Prioriteti zahtjeva .................................................................................................................. 12
2.4 Dokumentiranje analize (zahtjeva)........................................................................................ 13
2.5 Zadaci..................................................................................................................................... 14
3 Projekt izrade aplikacije................................................................................................................. 15
3.1 Osnove upravljanja projektom .............................................................................................. 15
3.2 Integrirana razvojna okruženja i kontrola programskog koda .............................................. 16
3.3 Plan projekta ......................................................................................................................... 17
3.3.1 Zadaci projekta .............................................................................................................. 18
3.3.2 Resursi projekta ............................................................................................................. 20
3.3.3 Upravljanje konfiguracijom ........................................................................................... 21
3.4 Zadaci..................................................................................................................................... 24
4 Osnove razvojnog okvira Microsoft .NET i programskog jezika C# ............................................... 25
4.1 Elementi jezika i struktura programa .................................................................................... 25
4.1.1 Identifikatori i ključne riječi ........................................................................................... 26
4.1.2 Prostor imena ................................................................................................................ 26
4.1.3 Postupak Main ............................................................................................................... 27
i
4.1.4 Razred ............................................................................................................................ 28
4.1.5 Standardni ulaz i izlaz .................................................................................................... 28
4.1.6 Komentari ...................................................................................................................... 29
4.1.7 Konzolna i grafička aplikacija ......................................................................................... 29
4.1.8 Ponovno korištenje koda ............................................................................................... 29
4.2 Tipovi podataka ..................................................................................................................... 31
4.2.1 Osnovni tipovi ................................................................................................................ 32
4.2.2 Varijable i pridruživanje vrijednosti............................................................................... 33
4.2.3 Vrijednosti i reference ................................................................................................... 33
4.2.4 Razredi String i StringBuilder ......................................................................................... 33
4.2.5 Nabrajanje - Enum ......................................................................................................... 34
4.2.6 Polja ............................................................................................................................... 34
4.2.7 Konverzija tipova ........................................................................................................... 36
4.2.8 Nulabilni tipovi podataka .............................................................................................. 37
4.2.9 Tipovi podataka var i dynamic....................................................................................... 38
4.3 Operatori ............................................................................................................................... 38
4.3.1 Aritmetički operatori, operatori usporedbe i logički operatori..................................... 38
4.3.2 Ostali operatori.............................................................................................................. 38
4.3.3 Prioritet operatora ........................................................................................................ 39
4.4 Naredbe za upravljanje programskim tokom ........................................................................ 39
4.4.1 Selekcija ......................................................................................................................... 39
4.4.2 Petlje .............................................................................................................................. 40
4.4.3 Skokovi........................................................................................................................... 40
4.5 Zadaci..................................................................................................................................... 40
5 Objektno orijentirano programiranje ............................................................................................ 42
5.1 Koncepti................................................................................................................................. 42
5.2 Razredi ................................................................................................................................... 43
5.2.1 Članovi razreda .............................................................................................................. 43
5.2.2 Modifikatori tipova i članova ......................................................................................... 43
5.2.3 Statički članovi, konstante i atributi .............................................................................. 44
5.2.4 Konstruktori ................................................................................................................... 44
5.2.5 Postupci ......................................................................................................................... 45
ii
5.2.6 Svojstva.......................................................................................................................... 47
5.2.7 Indekseri ........................................................................................................................ 48
5.2.8 Preopterećenje postupaka ............................................................................................ 48
5.2.9 Preopterećenje operatora ............................................................................................. 49
5.3 Nasljeđivanje ......................................................................................................................... 49
5.3.1 Nasljeđivanje općenito .................................................................................................. 49
5.3.2 Apstraktni razredi .......................................................................................................... 52
5.3.3 Dinamičko višeobličje .................................................................................................... 54
5.3.4 Agregacija i kompozicija ................................................................................................ 55
5.3.5 Sučelja............................................................................................................................ 56
5.4 Kolekcije ................................................................................................................................ 57
5.4.1 Kolekcija ArrayList ......................................................................................................... 58
5.4.2 Kolekcije Stack i Queue.................................................................................................. 59
5.4.3 Generičke kolekcije........................................................................................................ 59
5.4.4 Kolekcije Hashtable i Dictionary .................................................................................... 61
5.4.5 Proširenja....................................................................................................................... 62
5.5 Zadaci..................................................................................................................................... 63
6 Tehnike programiranja .................................................................................................................. 65
6.1 Defenzivno programiranje..................................................................................................... 65
6.2 Tehnike obrade pogrešaka .................................................................................................... 65
6.3 Iznimke .................................................................................................................................. 66
6.3.1 Obrada iznimki............................................................................................................... 66
6.3.2 Prosljeđivanje iznimki .................................................................................................... 67
6.3.3 Vlastite iznimke ............................................................................................................. 69
6.3.4 Preporuke za korištenje iznimki .................................................................................... 70
6.4 Tvrdnje................................................................................................................................... 71
6.5 Barikade ................................................................................................................................. 72
6.6 Otkrivanje pogrešaka............................................................................................................. 74
6.6.1 Količina defenzivnog koda u završnoj verziji ................................................................. 75
6.7 Životni vijek objekta .............................................................................................................. 75
6.8 Zadaci..................................................................................................................................... 78
7 Grafičko korisničko sučelje ............................................................................................................ 79
iii
7.1 WindowsForms ...................................................................................................................... 79
7.2 Događaji i delegati ................................................................................................................. 79
7.3 Prijenos parametara među formama .................................................................................... 81
7.4 Provjera valjanosti unosa podataka ...................................................................................... 83
7.5 Vlastite kontrole i vlastiti događaji ........................................................................................ 84
7.6 Višenitnost i paralelno programiranje u jeziku C# ................................................................ 87
7.6.1 Primjer potrebe za paralelnim izvršavanjem................................................................. 88
7.6.2 Stvaranje zadatka u pozadini ......................................................................................... 90
7.6.3 Čekanje zadataka i asinkroni postupci .......................................................................... 90
7.6.4 Kontrola ProgressBar..................................................................................................... 91
7.6.5 Pristup kontrolama korisničkog sučelja iz drugi niti ...................................................... 91
7.7 Zadaci..................................................................................................................................... 92
8 Aplikacija nad bazom podataka ..................................................................................................... 93
8.1 Ogledna baza podataka ......................................................................................................... 93
8.2 Tehnologija ADO.NET ............................................................................................................ 93
8.3 Izravna obrada podataka ....................................................................................................... 95
8.3.1 Priključak na bazu podataka .......................................................................................... 95
8.3.2 Primjer izravne obrade .................................................................................................. 97
8.3.3 Zatvaranje priključka ..................................................................................................... 98
8.3.4 Neovisnost o konkretnoj implementaciji ...................................................................... 98
8.4 Lokalna obrada podataka ...................................................................................................... 98
8.5 Entity Framework .................................................................................................................. 99
8.5.1 Načini kreiranja modela u Entity Frameworku .............................................................. 99
8.5.2 Stvaranje modela na osnovu postojeće baze podataka ................................................ 99
8.5.3 Elementi EF modela ..................................................................................................... 102
8.5.4 Važnija svojstva i postupci razreda DbContext i DbSet ............................................... 102
8.5.5 Dodavanja novog zapisa .............................................................................................. 103
8.5.6 Ažuriranje postojećeg zapisa ....................................................................................... 103
8.5.7 Brisanje zapisa ............................................................................................................. 104
8.5.8 Upiti nad EF modelom ................................................................................................. 104
8.5.9 EF i pohranjene procedure .......................................................................................... 104
8.6 Zadaci................................................................................................................................... 105
iv
9 Povezivanje podataka i složene zaslonske maske ....................................................................... 106
9.1 Povezivanje podataka s kontrolama na formi ..................................................................... 106
9.1.1 Razred BindingSource .................................................................................................. 107
9.2 Osvježavanje povezivanja .................................................................................................... 109
9.2.1 Razredi List i BindingList .............................................................................................. 111
9.2.2 Rukovanje podacima korištenjem kontrole BindingSource ........................................ 114
9.2.3 Promjena povezanog podatka i sučelje INotifyPropertyChanged ............................... 114
9.3 Povezivanje na podatke korištenjem EF modela................................................................. 115
9.3.1 Dinamičko postavljanje povezivanja ........................................................................... 116
9.3.2 Navigacija podacima vlastitim metodama .................................................................. 117
9.3.3 Rad s podacima (dodavanje, izmjena, brisanje) .......................................................... 118
9.3.4 Opoziv izmjena ............................................................................................................ 119
9.4 Validacija unosa podataka ................................................................................................... 119
9.5 Kontrola DataGridView........................................................................................................ 121
9.6 Kontrola BindingNavigator .................................................................................................. 123
9.7 Složene zaslonske maske ..................................................................................................... 123
9.7.1 Potrebne preinake na Entity Framework modelu ....................................................... 123
9.7.2 Izračunata polja ........................................................................................................... 124
9.7.3 Odabir vrijednosti stranog ključa ................................................................................ 124
9.7.4 Sinkronizacija stavki..................................................................................................... 126
9.7.5 Početne i referentne vrijednosti stavki ....................................................................... 126
9.7.6 Dodavanje novog dokumenta ..................................................................................... 128
9.7.7 Spremanje podataka ................................................................................................... 128
9.7.8 Brisanje zapisa zaglavlja (skupa s detaljima) ............................................................... 129
9.7.9 Brisanje pojedinačne stavke ........................................................................................ 129
9.7.10 Opoziv izmjena ............................................................................................................ 130
9.8 Zadaci................................................................................................................................... 130
10 Korisničko sučelje i dijalozi ...................................................................................................... 132
10.1 Načela oblikovanja korisničkog sučelja ............................................................................... 132
10.1.1 Raspored...................................................................................................................... 132
10.1.2 Uvažavanje sadržaja .................................................................................................... 132
10.1.3 Estetika ........................................................................................................................ 132
v
10.1.4 Iskustvo korisnika ........................................................................................................ 133
10.1.5 Dosljednost .................................................................................................................. 133
10.1.6 Lakoća korištenja ......................................................................................................... 133
10.2 Vrste korisničkog sučelja ..................................................................................................... 134
10.3 Izbornici i dijalozi ................................................................................................................. 134
10.4 Kriterij za odabir kontrola grafičkog sučelja ........................................................................ 134
10.5 Zadaci................................................................................................................................... 135
11 Dizajn sustava .......................................................................................................................... 136
11.1 Opći dizajn ........................................................................................................................... 136
11.2 Detaljni dizajn ...................................................................................................................... 136
11.3 Dizajn arhitekture sustava ................................................................................................... 136
11.4 Elementi arhitekture sustava .............................................................................................. 137
11.4.1 Centralizirana obrada .................................................................................................. 137
11.4.2 Dvoslojna arhitektura klijent-poslužitelj (client-server) .............................................. 138
11.4.3 Primjer arhitekture klijent-poslužitelj ......................................................................... 139
11.4.4 Troslojna ili višeslojna arhitektura klijent-poslužitelj .................................................. 141
11.5 Višeslojna aplikacija ............................................................................................................. 142
11.5.1 Odnosi među slojevima ............................................................................................... 143
11.5.2 Poslovni objekt ............................................................................................................ 144
11.5.3 Dohvat podataka kroz slojeve ..................................................................................... 145
11.5.4 Načini punjenja poslovnog objekta ............................................................................. 147
11.5.5 Izvedba podatkovnog sloja pomoću ADO.NET-a ......................................................... 148
11.5.6 Izvedba podatkovnog sloja pomoću Entity Frameworka ............................................ 149
11.5.7 Dodavanje, ažuriranje i brisanje artikla ....................................................................... 150
11.5.8 Izvedba šifrarničkih formi višeslojno. .......................................................................... 150
11.6 Zadaci................................................................................................................................... 151
12 Primjer višeslojne aplikacije – aplikacija FirmaWin ................................................................. 152
12.1 Nedostaci postojećeg rješenja ............................................................................................ 152
12.2 Struktura rješenja ................................................................................................................ 152
12.3 Firma.Framework ................................................................................................................ 153
12.3.1 Poslovni objekt i sučelje IBusinessObject .................................................................... 154
12.3.2 Bazni razred za poslovni objekt ................................................................................... 155
vi
12.3.3 Sučelje liste poslovnih objekata .................................................................................. 155
12.3.4 Liste poslovnih objekata .............................................................................................. 155
12.4 Dohvat liste artikala............................................................................................................. 156
12.5 Izvedba podatkovnog sloja .................................................................................................. 158
12.6 Poslovni objekt sa stavkama ............................................................................................... 159
12.6.1 Dohvat i spremanje složenog objekta ......................................................................... 160
12.6.2 Spremanje složenog objekta ....................................................................................... 163
12.7 Refleksija i korisnički atributi ............................................................................................... 164
12.7.1 Naknadno povezivanje ................................................................................................ 165
12.7.2 Atributi......................................................................................................................... 166
12.7.3 Univerzalni i samoprilagodljivi programski moduli ..................................................... 167
12.8 Zadaci................................................................................................................................... 171
13 Web aplikacije - ASP.NET Web Forms ..................................................................................... 172
13.1 ASP.NET Web Forms ............................................................................................................ 172
13.1.1 Prevođenje i prikaz web stranica ................................................................................ 173
13.1.2 Web aplikacija i/ili web mjesto ................................................................................... 174
13.1.3 Objava aplikacije i web poslužitelji .............................................................................. 175
13.2 Uobičajeni postupak izrade web stranica............................................................................ 176
13.3 Struktura Web Forms aplikacije .......................................................................................... 176
13.3.1 Osnovne Web kontrole................................................................................................ 177
13.3.2 Sintaksa kontrola ......................................................................................................... 177
13.3.3 Sintaksa aspx stranica .................................................................................................. 177
13.3.4 Odvajanje dizajna od koda .......................................................................................... 177
13.4 Životni ciklus web stranice .................................................................................................. 178
13.5 Objekti ASP.NET aplikacije................................................................................................... 179
13.6 Glavna stranica i izbornici .................................................................................................... 179
13.6.1 Glavna stranica ............................................................................................................ 179
13.6.2 Izbornici ....................................................................................................................... 180
13.6.3 Mapa web sjedišta....................................................................................................... 181
13.7 Složene kontrole i povezivanje podataka ............................................................................ 182
13.7.1 Povezivanje podataka .................................................................................................. 182
13.7.2 Povezivanje jednostavnih lista .................................................................................... 182
vii
13.7.3 Kontrola ObjectDataSource ......................................................................................... 182
13.8 Kontrola GridView ............................................................................................................... 185
13.8.1 Svojstva i događaji unutar mreže s podacima ............................................................. 186
13.8.2 Primjer dodavanja izvora podataka za GridView......................................................... 187
13.8.3 Definiranje i povezivanje stupaca u mreži s podacima ............................................... 188
13.8.4 Ažuriranje redaka u mreži s podacima ........................................................................ 189
13.8.5 Posebno dizajnirani stupci ........................................................................................... 190
13.8.6 Prikaz slike iz baze podataka ....................................................................................... 190
13.8.7 Prijenos argumenata stranici....................................................................................... 191
13.8.8 Povezivanje za posebno dizajnirane stupce ................................................................ 191
13.8.9 Dodavanje novih zapisa ............................................................................................... 192
13.8.10 Validacijske kontrole ............................................................................................... 192
13.9 Primjer Dokument-Stavka ................................................................................................... 193
13.9.1 Kontrola FormView ...................................................................................................... 194
13.9.2 Dohvat dokumenta ...................................................................................................... 194
13.9.3 Predložak za prikaz dokumenta................................................................................... 195
13.9.4 Predložak za ažuriranje dokumenta ............................................................................ 196
13.9.5 Odabir vrijednosti stranog ključa padajućom listom................................................... 196
13.9.6 Dodavanje novog dokumenta ..................................................................................... 197
13.9.7 Brisanje dokumenta .................................................................................................... 199
13.9.8 Prikaz stavki dokumenta.............................................................................................. 200
13.9.9 Oblikovanje pojedinog stupca u mreži sa stavkama i dodavanje nove stavke............ 201
13.10 Zadaci............................................................................................................................... 202
14 ASP.NET MVC........................................................................................................................... 203
14.1 Usporedba ASP.NET web formi s MVC-om ......................................................................... 203
14.2 Struktura ASP.NET MVC aplikacije ...................................................................................... 204
14.3 Inicijalne postavke MVC aplikacije ...................................................................................... 205
14.3.1 Paketi datoteka............................................................................................................ 206
14.4 Način rada MVC aplikacije ................................................................................................... 206
14.4.1 Usmjeravanje zahtjeva ................................................................................................ 206
14.4.2 Uobičajeni rezultati akcije upravljači ........................................................................... 207
14.4.3 Glavna stranica ............................................................................................................ 208
viii
14.4.4 Sintaksa pogleda .......................................................................................................... 209
14.4.5 Parcijalni pogled .......................................................................................................... 210
14.5 Primjer prikaza mjesta ......................................................................................................... 210
14.5.1 Akcija dohvata i pregleda svih mjesta ......................................................................... 211
14.5.2 Ažuriranje podataka .................................................................................................... 212
14.5.3 Prijenos dodatnih vrijednosti pogledu ........................................................................ 213
14.5.4 Prihvat podataka ......................................................................................................... 214
14.5.5 Validacija ..................................................................................................................... 214
14.5.6 Proširenja za straničenje ............................................................................................. 215
14.5.7 Forma za brisanje mjesta............................................................................................. 215
14.6 Prikaz artikala ...................................................................................................................... 217
14.6.1 Prikaz i dodavanje slike................................................................................................ 217
14.6.2 Ažuriranje unutar retka ............................................................................................... 218
14.7 Primjer Master-Detail .......................................................................................................... 222
14.7.1 Popis akcija i pogleda .................................................................................................. 223
14.7.2 Prikaz dokumenta ........................................................................................................ 224
14.7.3 Ažuriranje dokumanta i stavki ..................................................................................... 225
14.7.4 Validacija podataka ..................................................................................................... 226
14.8 Zadaci................................................................................................................................... 226
15 Web servisi .............................................................................................................................. 227
15.1 Osnovna pravila servisno orijentirane arhitekture ............................................................. 227
15.2 Standardi za web servisi ...................................................................................................... 228
15.3 Struktura primjera s web servisima..................................................................................... 228
15.4 Primjer web servisa ............................................................................................................. 229
15.4.1 Generiranje proxy razreda za pozive web servisa ....................................................... 229
15.4.2 Poziv web servisa......................................................................................................... 230
15.4.3 Nedostatci klasičnih web servisa ................................................................................. 231
15.5 WCF servisi .......................................................................................................................... 232
15.5.1 Protokoli povezivanja .................................................................................................. 232
15.5.2 Primjer izrade WCF servisa .......................................................................................... 233
15.5.3 Program WCF Test Client ............................................................................................. 235
15.5.4 Korištenje WCF servisa dodavanjem reference........................................................... 235
ix
15.5.5 Korištenje WCF servisa bez dodavanja reference ....................................................... 236
15.5.6 WCF i serijalizacija podataka ....................................................................................... 238
15.5.7 Iznimke (pogreške) u radu s WCF servisima ................................................................ 239
15.5.8 Postavke povezivanja .................................................................................................. 240
15.6 REST servisi .......................................................................................................................... 241
15.6.1 REST i vrste HTTP poziva .............................................................................................. 241
15.6.2 REST i WCF ................................................................................................................... 241
15.6.3 Primjer poziva REST servisa iz .NET klijenta ................................................................ 244
15.6.4 Alati za inspekciju prometa i stvaranje HTTP zahtjeva ................................................ 244
15.6.5 WebApi ........................................................................................................................ 245
15.7 Zadaci................................................................................................................................... 246
16 Reference ................................................................................................................................ 247
16.1 Literatura ............................................................................................................................. 247
16.2 Korisne poveznice................................................................................................................ 247
x
Predgovor
Ova skripta namijenjena su polaznicima predmeta Razvoj primijenjene programske potpore (RPPP ili
R3P) na preddiplomskom studiju Fakulteta elektrotehnike i računarstva, ali može dobro doći i kao
nastavni materijal sličnog predmeta na drugim visokim učilištima kao i štivo za sve one koji
namjeravaju savladati osnove razvoja aplikacija nad bazom podataka.
Uvodno su izložene osnove programskog inženjerstva i upravljanja projektima, nakon čega slijede
koncepti objektno orijentiranog programiranja i tehnika programiranja te primjeri arhitektura
dvoslojnih i višeslojnih aplikacija uključujući aplikacije nad web servisima.
Pretpostavlja se da je čitatelj prethodno savladao osnove programiranja, algoritme i strukture
podataka i baze podataka. Budući da na FER-u postoji predmet Objektno orijentirano programiranje,
skripta ne ulaze u detalje objektno orijentiranog programiranja, ali su izloženi neki koncepti ključni za
razumijevanje pojedinih segmenata aplikacija.
Kompletan izvorni kod programskih primjera priložen je kao dodatak predavanjima, a ovdje su
prikazani reprezentativni programski odsječci koji objašnjavaju pojedine koncepte na kojima se
zasniva programska potpora.
Osim toga, upute za rad u grupi i verzioniranje programskog koda, kao i upute za laboratorijske
vježbe odvojeni su i objavljuju se zasebno.
Svim čitateljima želimo da nakon polaganja predmeta RPPP ili čitanja ovih skripata postanu
programski inženjeri i o(p)stanu u struci te napreduju kao projektanti informacijskih sustava i
upravitelji projekata .
Autori
1
1 Osnove programskog inženjerstva
1
Gibbs, N.E. and Fairley, R.E. (Eds.). Software Engineering Education: Thr Educational Needs of the Software
Community. Springer-Verlag, New York, 1987.
2
1.4 Modeli razvojnog procesa
Model procesa je plan razvoja koji navodi opće postupke razvoja programskog proizvoda. Preciznije,
modelom procesa definira se koje aktivnosti (potprocesi) se trebaju obaviti, tko ih treba obaviti i u
kojoj ulozi kojim redoslijedom, koji će proizvodi biti razvijeni te kako ih vrednovati. Pri tome suradnik
koji obavlja posao u nekoj ulozi (voditelj projekta, arhitekt, programer…) koristi postojeće
programske uratke (dokumenti, modeli, programi) te primjenom metoda, preporuke, običaja, popisa
provjera, uzoraka te dostupne alati kreira novi ili izmijenjeni uradak (Slika 1). Programski proizvod je
tada skup programskih uradaka.
3
Slika 2. Tipične faze životnog ciklusa
Planiranje
Planiranje treba dati odgovor na pitanje zašto graditi sustav te odrediti poslovne ciljeve (koristi). U
studiji izvedivosti analizira se problemsko područja, utvrđuju problemi, određuju granice projekata o
procjenjuju ključni aspekti predloženog projekta – tehnička/ekonomska/organizacijska izvedivost.
Dolazi do ekipiranja projekta, određuje se način upravljanja i nadzora projekta te se izrađuje plan
rada (plan sustava, plan informatizacije).
Analiza
Analiza je traženje odgovora na pitanje tko će koristiti sustav, što će sustav raditi te gdje i kada će biti
korišten. Proučavaju se postojeći sustavi, ustanovljavaju moguća poboljšanja i razvija koncept novog
sustava. Rezultat je poslovni model sustava, tj. prijedlog sustava, odnosno specifikacija zahtjeva.
Oblikovanje (projektiranje)
Oblikovanje odgovara na pitanje kako napraviti sustav za određenu specifikaciju zahtjeva. Određuje
se kako će sustav funkcionirati sa stanovišta hardvera, softvera i mrežne infrastrukture, korisničkog
sučelja, programa te spremišta podataka. Specifikaciju sustava je tehnička specifikaciju koja se sastoji
od dizajna arhitekture, dizajna baze podataka i datoteka, dizajna sučelja i dizajna programa.
Specifikacija sustava predstavlja pogled projektanta (izvođača).
Izrada
Izrada predstavlja ugradnju (implementaciju) i provjeru rješenja. Na osnovu zadane specifikacije
konstrukcijom, testiranjem i instalacijom se isporučuje funkcionalni sustav.
Primjena i održavanje
4
Funkcionalni sustav se isporučuje korisniku čime postaje operabilni sustav koji se održava i
poboljšava.
Pregled
U ovoj fazi se utvrđuju popravci, dorade, prerade i nadogradnje koje treba izvršiti na sustavu. Time
se vrši revizija sustava, odnosno preispitivanje čitavog sustava kada su potrebne veće izmjene uslijed
promjena u poslovanju ili promjena poslovnih ciljeva nakon čega se ide u novi projekt i novi razvojni
ciklus.
5
Faze vodopadnog modela su:
Slika 4).
6
Rezultat iteracije je proizvod završne kakvoće (eng. production-quality), provjeren i integriran, koji
zadovoljava podskup ukupnih zahtjeva. Isporuke mogu biti interne ili prema korisnicima. Za različite
modele razvoja i tipove projekata RUP sadrži niz "predložaka" razvojnih procesa (eng. roadmaps).
Slika 4. Veze između glavnih faza RUP procesa i faza standardnog životnog ciklusa
Faze su sljedeće:
Faza počinjanja (eng. inception) ima svrhu opravdati razloge za pokretanje projekta. U ovoj
fazi prikupljaju se najvažniji zahtjevi (10% detaljno) te se određuje doseg projekta.
U fazi elaboracije (eng. elaboration) detaljno se prikupljaju zahtjevi (80%) i vrši se globalna
(eng. high-level) analiza i dizajn, ustanovljavanja se osnovne arhitekture i planira
konstrukcija.
7
Istraživanje Planiranje Iteracije do izdanja Produkcija Održavanje Smrt
Stalni pregled
Priče za
iduću Programiranje u paru
Redovne
iteraciju Analiza Dizajn Plan testa Test
nadopune
Povratne Stalna
Prič Prioriteti informacije integracija
e
Procjena
napora
Test Malo Nadopunjeno Finalno
Skupna baza
izdanje izdanje izdanje
Odobrenje
korisnika
U fazi istraživanja korisnici bilježe svoje priče na kartice pri čemu svaka kartica sadrži jednu
mogućnost programa. Faza istraživanja traje nekoliko tjedana do nekoliko mjeseci pri čemu
se skup priča redovno nadopunjuje. U ovoj fazi projektni tim se pobliže upoznaje s alatima,
tehnologijom i postupcima projekta te se radi prototip sustava za testiranje tehnologije i
varijanti arhitekture sustava.
U fazi produkcije vrši se dodatno testiranje i provjera performansi sustava prije isporuke
klijentu. Razrješavaju se primjedbe na sustav te se odlučuje da li će se primjedbe riješiti u
tekućem izdanju. Iteracije trajanja tri do najviše tjedan dana, a zakašnjele nove ideje i
prijedlozi se dokumentiraju i njihova implementacija odgađa.
8
Nakon što je prvo izdanje pušteno u produkciju, XP projekt mora istovremeno održavati
softver u primjeni i proizvoditi nove iteracije te se zbog toga brzina implementacije smanjuje.
Održavanje može zahtijevati nove članove projektnog tima i promjenu strukture tima.
Faza smrti je blizu kada klijent nema više novih kartica s pričama pri čemu se podrazumijeva
da sustav zadovoljava sve zahtjeve (npr. pouzdanost i stabilnost). Faza smrti je prikladno
vrijeme u XP projektu da se konačno napiše sva korisnička dokumentacija budući da više
nema promjena na arhitekturi, dizajnu i kodu sustava. „Smrt“ može nastupiti i kada sustav ne
ispunjava sva korisnička očekivanja, ili ako postane preskup za daljnji razvoj.
1.9 Zadaci
Zadatak 1. Koja je razlika između računarske znanosti i programskog inženjerstva?
Zadatak 2. Što su izlazi pojednih faza životnog ciklusa?
Zadatak 3. U kojoj fazi životnog ciklusa programske potpore se
a) razvija specifikacija zahtjeva,
b) odlučuje o dizajnu arhitekture, sučelja i baze podataka?
Zadatak 4. Koje su varijante vodopadnog modela razvoja?
9
2 Specifikacija zahtjeva
ISO/IEC/IEEE rječnik programskog inženjerstva definira zahtjev kao
1. uvjet ili sposobnost koje korisnik treba da bi riješio neki problem ili ostvario neki cilj
2. uvjet ili sposobnost koju mora posjedovati ili zadovoljiti sustav, komponenta sustava,
proizvod ili usluga da bi zadovoljila ugovor, standard, specifikaciju ili neki drugi formalni
dokument.
Norma koja se odnosi na inženjerstvo zahtjeva tomu dodaje
3. izjavu kojom se prevodi ili izražava potreba i njoj pridružena ograničenja i uvjeti
Udruga Project Management Institute definiciju proširuje izjavom da zahtjevi uključuju nabrojane i
dokumentirane potrebe, želje i očekivanja sponzora, korisnika i ostalih dionika u projektu.
Poslovni zahtjevi
Poslovni zahtjevi odgovaraju na pitanje zašto (se radi neki sustav) te su sadržani u dokumentima u
kojima se opisuje vizija i opseg projekta. Predstavljaju ciljeve organizacije ili korisničke zahtjeve na
višoj razini i ukratko opisuju problem koji treba riješiti. Neki primjeri poslovnih zahtjeva su:
poboljšanje usluge postojećim klijentima tvrtke i pridobivanje novih
evidencija članstva i automatizacija postupka primanja novih članova neke udruge
praćenje financijskih podataka udruge i njenih članova
poboljšanje procesa prodaje
omogućavanje internetske prodaje
podrška organiziranju natjecanja i okupljanja
Korisnički zahtjevi
Korisnički zahtjevi su zahtjevi krajnjih korisnika te opisuju zadatke koje korisnik mora moći obaviti.
Sadržani su u opisima slučajeva korištenja tj. opisima scenarija rada i obično se izražavaju u izjavama
oblika „Korisnik želi/treba/mora moći obaviti…“.
Neki primjeri korisničkih zahtjeva u sustavu subvencionirane prehrane studenata (X-ice):
10
Korisnik mora moći ostvariti pravo na prehranu kod bilo kojeg pružatelja usluge - Novi sustav
mora omogućiti da student ostvaruje svoje pravo kod bilo kojeg pružatelja usluge
subvencionirane prehrane. Dosadašnja praksa je bila da svaki pružatelj usluga izdaje svoje
bonove koji se mogu koristiti samo u određenim restoranima
Korisnik treba plaćati obroke nakon korištenja pojedinog obroka. - Treba izbjeći bilo kakvo
plaćanje od strane studenata za potrebe ostvarivanja prava, a posebice unaprijed.
Korisnik mora moći prijaviti gubitak kartice – Potrebno je smanjiti rizik gubitka ostvarenih
prava te sustav mora onemogućiti zloporabu stečenih prava.
Korisnik želi ostvariti i ostala prava iz studentskog standarda, npr. javni prijevoz po
povlaštenoj cijeni, kazališta, kina, smještaj u studentskim domovima, student-servis, itd.
Funkcionalni zahtjevi
Funkcionalni zahtjevi odgovaraju na pitanje što (se može/mora napraviti koristeći sustav).
Funkcionalni zahtjevi definiraju softversku funkcionalnost (očekivano ponašanje i operacije koje
sustav može izvoditi) koju treba ugraditi u proizvod da bi omogućio korisnicima obavljanje njihovih
zadataka ili posebno zanimljivu mogućnost programa (eng. feature) kao skup logički povezanih
funkcionalnih zahtjeva koje korisniku omogućuju ispunjavanje poslovnih zahtjeva.
Primjer funkcionalnih zahtjeva za sustav subvencionirane prehrane:
Nakon što se studentu jednom zavedu prava na matičnoj ustanovi, sustav mora proslijediti
informaciju svim pružateljima usluga, odnosno omogućiti distribuirane upite
Sustav treba dnevno kreirati izvještaje sa statistikom prehrane po pružateljima usluge i vrsti
obroka.
Nefunkcionalni zahtjevi
Za razliku od funkcionalnih zahtjevi koji opisuju što sustav radi, nefunkcionalni zahtjevi odgovaraju na
pitanje kako (sustav mora raditi). Nefunkcionalni zahtjevi su posljedica standarda, pravila i ugovora
kojih se proizvod mora pridržavati, opisi vanjskih sučelja, zahtjevi na performanse, ograničenja na
dizajn i implementaciju te svojstva kvalitete (preciziraju opis proizvoda navodeći karakteristike
proizvoda u različitim dimenzija koja su važne ili korisniku, ili graditelju).
U sustavu prehrane nefunkcionalni zahtjevi primjerice mogu biti vezani za oblik korisničke kartice,
protokol povezivanja,obvezu fiskalizacije itd.
Nepotpuni zahtjev
„Proizvod će dostaviti statusnu poruku u redovitim statusnim intervalima ne manjim od 60 sekundi“.
Ovo je primjer nepotpunog zahtjeva, jer nije jasno što je statusna poruka i pod kojim uvjetima će biti
dostavljena, koliko dugo ostaje vidljiva, koliko dosljedni intervali moraju biti te koji dio proizvoda će
dostaviti poruku te nije moguće odrediti.
11
Ovaj zahtjev treba preciznije i detaljnije definirati, primjerice sljedećim rečenicama:
Neostvarivi zahtjev
„Proizvod će se trenutno prebaciti između ispisivanja i skrivanja znakova koji se ne mogu tiskati“. Ovo
je primjer neostvarivog zahtjeva jer računala ne mogu ništa napraviti trenutno i nije jasno da li
programska podrška sama odlučuje kad će se prebaciti iz jednog stanja u drugo ili je to inicirano
akcijom korisnika. Također, nije jasno određeno na koji dio teksta će se primijeniti promjena prikaza
(da li samo označeni tekst, cijeli dokument ili nešto treće) te što su znakovi koji se ne mogu tiskati
(skriveni znakovi, posebne oznake, kontrolni znakovi, …).
Bolji zahtjev, kojim se može ostvariti bi bio npr. „Korisnik će posebno dogovorenom akcijom, odabrati
da li će se HTML oznake u trenutno otvorenom dokumentu prikazivati ili neće." Na ovaj način bi bilo
jasno da je riječ o HTML oznakama te da korisnik mora obaviti nekakvu akciju, ali nije točno
navedeno kakvu (npr. kombinacija tipki), što se prepušta dizajnerima programa.
Neodređeni zahtjev
„Parser će brzo generirati izvješće o pogreškama HTML oznaka, koje omogućava brzi ispravak
pogrešaka kada program koriste početnici u HTML-u.“. Ovo je primjer neodređenog zahtjeva, jer se
koriste pojmovi koji nisu egzaktno mjerljivi ili se mogu različito tumačiti od osobe do osobe. Primjeri
takvih pojmova su riječ "brzo" koja nije određena nekom mjernom jedinicom, „generirati izvješće“ za
koje nije definirano kada se generira i što tvori izvješće i to čini zahtjev nekompletnim. Također
postavlja se pitanje kako bi se za ovaj zahtjev ovjerilo da li je zahtjev ispravno ugrađen u sustav -
pronašlo nekoga tko se smatra početnikom u HTML-u i zatim vidjeti kako brzo će, uz pomoć izvješća,
ispraviti pogreške?!
Bolja verzija zahtjeva bi bila: „Nakon što je HTML analizator obradio datoteku generirat će izvješće
koje sadrži broj linije i tekst pronađenih HTML pogrešaka, te opis svake pogreške. Ukoliko nema
pogrešaka prilikom analize, neće se generirati izvješće.“
12
neobvezno svojstvo odgovarajući na pitanje koliko neko svojstvo (proizašlo iz zahtjeva) treba
korisniku.
Nužno svojstvo (eng. must have) predstavlja ono što korisnik stvarno mora imati da bi mogao početi
koristiti neki sustav. Po definiciji, ako sustav ne uključuje nužne zahtjeve, taj sustav ne može ispuniti
svoju svrhu. Postoji tendencija da se previše zahtjeva proglasi nužnim! Stoga treba testirati svaki
zahtjev koji se smatra nužnim i probati ga rangirati. Ako se zahtjev može rangirati onda nije obvezan.
Potpuno obvezni zahtjevi se ne mogu rangirati jer su nužni za prvu verziju sustava.
Poželjno svojstvo (eng. should have) je funkcija sustava koju korisnik želi imati na kraju. Ranije verzije
sustava mogu pružiti (ne potpunu) funkcionalnost bez tih zahtjeva. Poželjni zahtjevi mogu i trebaju
biti rangirani.
Neobvezna svojstva (eng. could have) su mogućnosti sustava nastale iz proizvoljnih zahtjeva
pojedinih korisnika bez kojih sustav može raditi. Primjer neobveznog svojstva bi npr. bilo ostvarivanje
ostalih prava iz studentskog standarda iz primjera zahtjeva krajnjih korisnika. Iako bi ih lijepo bilo
imati, to nisu pravi zahtjevi. Ovi zahtjevi također mogu biti rangirani.
Po potrebi može se navesti i nepotrebna svojstva (eng. won’t have this time but potentially later), jer
se time dodatno precizira opseg projekta.
13
1. Uvod 4. Mogućnosti proizvoda
1.1 Namjena 4.x Svojstvo X
1.2 Konvencije dokumenta 4.x.1 Opis i prioriteti
1.3 Upute za čitanje dokumenta 4.x.2 Slijed pobuda/odziv
1.4 Opseg proizvoda 4.x.3 Funkcijski zahtjevi
1.5 Reference 5. Ostali nefunkcionalni zahtjevi
2. Sveobuhvatni pregled 5.1 Zahtjevi za performansama sustava
2.1 Kontekst proizvoda 5.2 Zahtjevi za sigurnošću korisnika
2.2 Funkcije proizvoda 5.3 Zahtjevi za sigurnošću podataka
2.3 Kategorije korisnika i svojstva 5.4 Kvaliteta programske podrške
2.4 Okružje u kojem se izvodi proizvod 5.5 Poslovna pravila
2.5 Ograničenja dizajna i ugradnje 5.6 Korisnička dokumentacija
2.6 Pretpostavke i ovisnosti 6. Ostali zahtjevi
3. Zahtjevi za sučeljem Dodatak A: Rječnik
3.1 Korisničko sučelje Dodatak B: Modeli i dijagrami
3.2 Hardversko sučelje Dodatak C: Lista nedovršenih/neodređenih
3.3 Softversko sučelje zahtjeva
3.4 Komunikacijsko sučelje
2.5 Zadaci
Zadatak 1. Što je specifikacija zahtjeva?
Zadatak 2. Na koje pitanje odgovaraju poslovni, na koje funkcionalni, a na koje nefunkcionalni
zahtjevi?
Zadatak 3. Preoblikujte loše definirane u dobro definirane korisničke zahtjeve:
a) "Sustav treba javiti svim korisnicima ako dođe do pogreške."
b) "Sustav treba odmah prekinuti s radom ako dođe do sumnjive situacije korištenja."
c) "Sustav se treba prilagoditi hendikepiranim korisnicima."
14
3 Projekt izrade aplikacije
Izrada aplikacije nije samo kodiranje. Prije nego projektni tim započne pisanje programskog koda
aplikacije potrebno je izvršiti niz radnji, kao na primjer prikupiti korisničke zahtjeve, pobrojati
projektne zadatke, procijeniti trajanje projekta i tako dalje. Tijekom implementacije potrebno je
voditi računa o odstupanju od plana projekta, promjenama zahtjeva i slično, a poslije napisati
korisničku i tekničku dokumentaciju, organiziriati isporuku, plan održavanja te zatvoriti projekt.
Planiranje
o Utvrđivanje zahtjeva
o Postavljanje jasnih i ostvarivih ciljeva
o Uravnoteženje zahtjeva na kvalitetu, doseg, vrijeme i trošak
o Prilagodbu interesima i očekivanjima zainteresiranih strana – dionika (eng.
stakeholders)
Organiziranje
o Formiranje projektnog tima
o Koordiniranje sudionika na projektu
o Raspoređivanje obaveza
o Tko, što i kada treba napraviti
Usmjeravanje
o Nadgledanje, omogućavanje izvršenja
Kontroliranje
o Provjera učinka i rezultata
15
Voditelj projekta odgovoran je i za identificiranje i upravljanje interesnim sudionicima projekta -
dionicima projekta (eng. stakeholders). Dionici projekta (uloge) su pojedinci ili organizacije koje su
aktivno uključene u projekt ili rezultati projekta imaju utjecaj na njih.
Korisnik, Korisnik usluga, Klijent (eng. User, Customer, Client) - osoba ili grupa, naručitelj ili
krajnji korisnik
Sponzor projekta (eng. project sponsor) - osoba ili grupa koja osigurava resurse za projekt
Voditelj projekta (eng. project manager) - osoba imenovana kako bi ostvarila ciljeve projekta
Projektna ekipa - Svi članovi ekipe, uključujući voditelja, a u nekim slučajevima i sponzora
o sistem analitičar – određivanje potreba, specifikacija zahtjeva i dizajna
o projektant / arhitekt – uspostava osnovne arhitekture
o razvojnik (developer, builder) – kodiranje, testiranje
o administrator baze podataka – administriranje sustava za upravljanje bazama
podataka
o sistem inženjer / sistem administrator – administriranje OS i mreže
Osim ljudskih resursa (osoba), ostali su resursi projekta su oprema, usluge, materijal, budžet ili druga
sredstva, koje je također potrebno identificirati i njima tijekom projekta upravljati.
16
Kretanje kodom (eng. code navigation)
Generiranje koda pomoću predložaka koda (eng. code generation through code
templates)
Podrška za preradu, refaktoriranje (eng. refactoring)
Analiza programskog koda na različitim razinama
Funkionalnosti razvojnog okruženja korištenog u okviru predmeta RPPP opisano je u uputama za
laboratorijske vježbe.
17
3.3.1 Zadaci projekta
Osnovni gradbeni elementi svakog projekta su zadaci. Zadaci predstavljaju posao koji se mora obaviti
da bi se postigao cilj projekta te opisuju tijek događaja, trajanja i zahtjeva za resursima na projektu.
Razlikujemo tipove zadataka:
Primitivni zadaci - zadaci koji se dekompozicijom ne mogu podijeliti na jednostavnije zadatke
Skupni zadaci (eng. summary tasks) - zbrajaju trajanje i troškove primitivnih zadataka.
Trajanje, datum te izračunate vrijednosti se automatski izvode iz skupa primitivnih zadataka.
Prekretnice ili miljokazi (eng. milestones) - ključni događaj ili krajnji rok odnosno cilj koji
treba postići. Miljokazi služe za provjeru stupnja dovršenosti drugih zadataka. Trajanje im je 0
(sati, dana). Pomak ključnog događaja ima za posljedicu vremenski preraspored.
Zadaci projekta mogu se organizirati hijerarhijski, grupiranjem u radne pakete, aktivnosti i faze.
Gledano s vrha prema dolje, struktura zadataka naziva se se hijerarhijskom raščlambom posla (eng.
work breakdown structure, skraćeno WBS), koja se može se prikazati tablično ili grafički.
Dva su pristupa razvoju hijerarhije posla:
Planiranje s vrha prema dolje (eng. top-down) - pristup od općeg prema specifičnom.
Identificira glavne faze i rezultate projekta prije dodavanja zadataka potrebnih za završetak
tih faza. Složeni projekti mogu imati nekoliko slojeva razrade do zadataka na dnu hijerarhije.
Planiranje s dna prema dolje (eng. bottom-up) - pristup od specifičnog prema općem.
Identificira što više zadataka najnižeg sloja prije grupiranja u više razine, što se ponavlja do
vrha hijerarhije.
Za procijeniti trajanje cijelog projekta, potrebno je procijeniti trajanje pojednih zadatka projekta, tj.
odrediti očekivanu količina vremena za završetak zadataka. Trajanje se može defiirati u minutama
(m), satima (h), danima (d), tjednima (w) ili mjesecima (mo).
Projekt može zahtijevati da zadaci budu napravljeni u određenom redoslijedu (iza jednog slijedi drugi
zadatak). Zadatak sljedbenik (eng. successor) može biti izvršen ako je dovršen prethodnik (eng.
predecessor). Bilo koji zadatak može biti prethodnik jednom ili više sljedbenika.
Odnosi, to jest zavisnosti između zadataka mogu biti:
18
Finish-to-start (FS) –završetak prethodnika određuje početak sljedbenika
o Npr. instalacija softvera može započeti po nabavci hardvera
Start-to-start (SS) – početak prethodnika određuje početak sljedbenika
o Npr. unos podataka započinje s početkom njihovog prikupljanja
Finish-to-finish (FF) – završetak prethodnika određuje završetak sljedbenika
o Npr. provjera instalacije završava s dovršenjem ožičenja
Start-to-finish (SF) - početak prethodnika određuje završetak sljedbenika
o Npr. stari sustav prestaje s radom kad započne rad novog
Ukoilko nije eksplicitno definirano, podrazumijeva se da je zavisnost dva povezana zadatka FS.
Zavisnost zadataka prikazujej se mrežnim dijagramom (eng. project network diagram). Jedna od
metoda za određivanje trajanja projekta je metoda kritičnog puta (eng. critical path method).
Sumiraju se trajanja zadataka po svim putanjama u mreži zadataka te se određuje najduža koju
zovemo kritičnim putom. Kritični put je niz zadataka koji moraju završiti na vrijeme da bi projekt
završio u planiranom roku. Svaki zadatak na kritičnom putu je kritični zadatak, čije kašnjenje uzrokuje
kašnjenje projekta. Sljedeća slika prikazuje mrežni dijagram zadataka (pobrojani krugovi s oznakom
trajanja izvan kruga) s označenim kritičnim putom u trajanju 22 vremenske jedinice (suma svih
trajanja na tom putu). Kašnjenje početka ili dulje trajanje bilo kojeg kritičnog zadatka odgodilo bi
završetak projekta.
U praksi se radi preglednosti češće koristi Ganttov dijagram, kao u sljedećem primjeru. Tamno su
označene grupe zadataka (aktivnosti i faze), crveno zadaci na kritičnom putu, a plavo ostali zadaci.
19
Slika 10. Primjer Gantograma
Više o metodi kritičnog puta i drugim metodama može se naučiti na predmetu Upravljanje
projektima .
raspoloživost - u koje vrijeme određeni resurs može raditi na zadatku i koliko posla može
obaviti i
trošak – koliko novca će biti potrošeno na resurse.
Kod određivanja rasporeda projekta potrebno je raspodijeliti resurse imajući na umu dostupnost i
trošak resursa. Maksimalne jedinice (eng. max. units) prikazuju vrijednosti raspoloživosti resursa u
postocima, npr. 100% predstavlja jednog čovjeka punog radnog vremena, 300% predstavlja tri
čovjeka punog radnog vremena. Ako je projektni tim formiran, kao resurse možemo navesti članove
hjihovim imenima (npr. Pero Perić za razliku od Sistem analitičar u primjeru Slika 7).
Osnova po kojoj je resursu dodijeljeno obavljanje posla je kalendar resursa. Za pojedinačnu
prilagodbu kalendara (standardnog) uvažavaju se radni i neradni dani resursa. Na primjer, ako
kalendar evidentira radno vrijeme samo četvrtkom i petkom 13-17 sati, 100% raspoloživosti nekog
resursa ne znači 40 satno tjedno radno vrijeme, nego 8 sati rada tjedno.
Dodjelom resursa zadatku, dodjeljuje mu se određeni posao. Treba razlikovati posao (work) od
trajanja (duration). Posao je stvarni rad i odnosi se na zadatak - stvarni rad potreban za završetak
20
zadatka, dodijeljeni zadatak - stvarni rad nekog resursa na nekom zadatku i resurs - ukupni rad neke
osobe na svim zadacima. Trajanje je omjer posla i jedinica posla (eng. Duration = Work / Units) i ovisi
o kalendaru rada.
Metoda planiranja koja se koristi kod ažuriranja resursa zadatka jest raspoređivanje temeljem napora
(eng. effort-driven scheduling). Odnosi se samo na zadatke koji su automatski raspoređeni (eng.
Auto Schedule). Trajanje je obrnuto količini resursa.
Ako su resursi prekapacitirani, problem se rješava nekom od sljedećih metoda:
Pomaknuti rokove (trajanje)
Dodati dodatne resurse
Produžiti radno vrijeme
Povećati jedinice posla
Smanjiti količinu posla
…
21
Slika 11. Primjer oznaka verzija konfiguracije
Verzioniranje aplikacija
Važna tehnika upravljanja sofverskom konfiguracijom je kontrola verzija (eng. version control)
izvornog koda, ali i drugih datoteka (podsjećamo, aplikaciju čine programski kod, podaci i
dokumenacija). Kada na projektu radi više osoba, nekontrolirana istovremena izmjena istih
elemenata konfiguracije može dovesti do nekonzistentnosti pojedinih dijelova. Stoga se koriste
sustavi za kontrolu verzija koji, između ostalog, omogućavaju kontrolu pristupa zaključavanjem
dateoteka. Kao primjer takvih sustava mogu poslužiti Apache Subversion (s takozvanim SVN
klijentima) i Microsoft Team Foundation Server (TFS).
Mogućnosti sustava kontrole verzija:
baza projekata (eng. project database) ili riznica (eng. repository) - pohranjuje sve relevantne
objekte konfiguracije
verzioniranje - razlikovanje pohranjenih inačica objekata konfiguracije
pomagalo za izradu (eng. make facility) - prikuplja relevantne objekte i proizvodi određenu
verziju softvera
praćenje problema (eng. issue tracking), praćenje pogreški (eng. bug tracking) - bilježenje i
praćenje statusa tema koje se odnose na pojedine objekte konfiguracije
Na razvojnoj platformi Microsoft .NET, verzija objektne datoteke (eng. assembly) određena je s četiri
broja (definira se u razvojnoj okolini Visual Studio jedno od svojstava projekta):
<major version>.<minor version>.<build number>.<revision>
major version - mijenja se prilikom znatne promjene u (npr. kod redizajna koji prekida
vertikalnu kompatibilnost sa starijim verzijama)
minor version - mijenja se prilikom znatne promjene, ali uz zadržavanje kompatibilnosti s
prethodnim verzijama
build number - predstavlja ponovno prevođenje istog koda (npr. prilikom promjene
platforme, procesora i slično)
revision - primjenjuje se npr. prilikom izdavanja sigurnosnih zakrpa i sličnih manjih promjena
Prednosti i nedostatci automatskog odnosno ručnog označavanja verzija:
22
ne postoje dvije inačice s istom moguća je sinkronizacija između
oznakom verzije pojedinih komponenti i
verzije cijelog sustava
23
Slika 12. Primjer timske kontrole verzija
3.4 Zadaci
Zadatak 1. Što je projekt? Što je plan projekta?
Zadatak 2. Ako u planu projekta kalendar evidentira radno vrijeme nekog suradnika od
ponedjeljka do subote na pola radnog vremena (od 8 do 12 sati), što znači 100%
raspoloživosti tog suradnika/resursa?
Zadatak 3. Dijelovi razvojne okoline mogu biti različito razmješteni, mogu plutati ili biti usidreni.
a) Razmjestiti pojedine elemente
b) Pokazati/sakriti neke dijelove
c) Provjeriti dijelove izbornika View
d) Provjeriti postavke u Tools / Options
e) Resetirati razvojnu okolinu na tvorničke postavke.
Zadatak 4. Isprobati osnovne funkcije rada u timskom okruženju (TFS), dodavanjem projekta i
dodavanjem/izmjenom izvornih datoteka uz zaključavanje i otključavanje. Kako se rješava
problem istovremenog uređivanja datoteka?
24
4 Osnove razvojnog okvira Microsoft .NET i programskog jezika C#
Microsoft .NET Framework
Microsoft .NET Framework je okvir za razvoj softvera, nastao s idejom iste osnovice za izradu lokalnih
(desktop), internetskih (web) aplikacija i mobilnih (windows phone) aplikacija. Uključuje knjižnice za
razvoj neovisno o jeziku. Podržani su jezici Visual Basic .NET, Visual C++ .NET, C# i drugi. Sadrži
zajedničku knjižnicu osnovnih razreda Base Class Library (BCL) ili Framework Class Library (FCL),
zajedničke opće tipove podataka Common Type System (CTS), zajedničku specifikaciju jezika Common
Language Specification (CLS) podskup CTS-a zajednički za sve .NET jezike te zajednički pogon
programa - Common Language Runtime (CLR). Zamišljen je kao neovisan je o platformi, ali postoji
samo na operacijskim sustavima tvrtke Microsoft.
Jezik C#
Jezik C# je općenamjenski programski jezik razvijen od Microsofta (Anders Hejlsberg et al.) Objektno
je usmjeren (eng. object-oriented), vođen događajima (eng. event-driven), otvoren mreži (eng.
network-aware) i vizualan (eng. visual) to jest sadrži interaktivno sučelje razvojne okoline i aplikacija.
Prevođenje C#-programa odvija se u sljedećim koracima:
C# prevoditelj prevodi C# izvorni kod (.cs datoteke) u poseban međujezik MSIL (eng. MS
Intermediate Language - izvodi se u virtualnom stroju, a ne izravno na procesoru računala) i
stvara se asemblij (eng. assembly - skup prevedenih razreda)
Pokreće se izvršna datoteka s kodom
Učitavaju se potrebne biblioteke (eng. dynamic link libraries - DLLs)
Izvršava se funkcija _CorExeMain (entry point) koju je umetnuo kompajler
Pri prvom pokretanju programa (ili ako ima promjena u kodu prilikom pokretanja) Just-In-
Time compiler (JIT) prevodi MSIL u strojni kod (eng. native code)
Izvršava se strojni kod
Primjer Osnove\PozdravKonzola
/* korištenje knjižnice */
using System;
Program općenito sadrži jedan ili više razreda. Razred ili klasa (eng. class) sadrži članove – svojstva
(varijable) i metode, postupke (potprograme). Ne postoje slobodni potprogrami ni globalne varijable,
25
sve se zbiva unutar tijela razreda (za razliku od npr C++-a). Naredbe se kao u programskom jeziku C
odvajaju točka-zarezom (;), a blokovi programa označavaju se vitičastim zagradama {}.
Prostor imena System sadrži osnovne razrede za rad s tipovima podataka, sučeljima, događajima i
tako dalje. Razred Console se nalazi u prostoru imena System i njegovo potpuno ime je
26
System.Console, ali zbog navoda using System prilikom poziva postupka WriteLine nije potrebno
pisati: System.Console.WriteLine već samo Console.WriteLine.
Može se koristiti i zamjensko ime (eng. alias) – koristi se za definiranje skraćenih naziva i uklanjanje
neodređenosti kad u različitim imenicima postoje razredi istog imena.
using System; // navod imenika
using stdout = System.Console; // alias razreda
class Pozdrav {
static void Main(string[] args) {
System.Console.WriteLine("Kvalificirano!");
Console.WriteLine("Izravno!"); // zbog navoda using System
stdout.WriteLine("Zamjenski!"); // zbog aliasa using stdout =
}
}
Namespace Opis
System Osnovni razredi i tipovi podataka (npr. int, char, float)
System.Data Razredi koji čine ADO.NET, koji se koristi za pristup bazama
podataka i rukovanje podacima.
System.Drawing Razredi za crtanje i grafiku.
System.IO Čitanje i pisanje podataka, npr. u datotekama.
System.Threading Simultano izvođenje programa, višenitnost (multithreading).
System.Windows.Forms Razredi za kreiranje grafičkog sučelja
System.Xml Razredi za obradu XML datoteka.
System.String Razredi za rad sa nizovima znakova (string).
System.Char Razredi za rad sa znakovnim tipom podataka.
System.Collection Razredi za rad s kolekcijama (listama).
System.Collections.Generic Razredi za rad s generičkim (tipiziranim) kolekcijama.
27
4.1.4 Razred
Naredba class Pozdrav označava korisnički definirani razred (uvriježeni naziv je i klasa). U ovom
primjeru razred Pozdrav sadrži samo postupak Main. Razred općenito sadrži svojstva (varijable) i
metode tj. postupke (potprograme), kao u sljedećem primjeru.
class Tocka
{
public int cx;
public int cy; //javne varijable
public Tocka(int x, int y){ //konstruktor
cx = x; cy = y;
}
public int Kvadrant(){ //javni postupak
if (cx > 0){
if (cy > 0) return 1;
else return 4;
} else {
if (cy > 0) return 2;
else return 3;
}
}
}
Svaki prevedeni razred ima manifest - definiciju sučelja koju mogu koristiti drugi programi, uključujući
one napisane u nekom drugom jeziku.
28
4.1.6 Komentari
U jeziku C# postoje dvije vrste komentara: retkovni komentar – tekst od znakova "//" do kraja retka i
blok komentari – tekst oblika /* … */ koji se može se rasprostirati u više redaka.
Primjer Osnove\PozdravGraficka
using System;
class Pozdrav
{
static void Main(string[] args)
{
System.Windows.Forms.
MessageBox.Show("Pozdrav!");
}
}
Kod je gotovo isti (direktiva using System, kao i postupak Main), samo što se umjesto konzolne
naredbe za pisanje poziva Windows dijaloški okvir MessageBox.
using System;
public class Pozdrav
{
public Pozdrav()
{
Poziv("iz lokalnog");
}
public static void
Poziv(string poruka)
{
System.Console.WriteLine("Pozdrav " + poruka);
}
}
29
Primjer Osnove\Reuse - Pozdrav.cs
using System;
class Proba
{
static void Main()
{
Console.WriteLine("Glavni!");
Pozdrav.Poziv("iz glavnog");
Pozdrav p = new Pozdrav();
}
}
Izvorni kod sadržan je u dvije datoteke pa se prevodi pozivom prevoditelja u operacijskom sustavu (s
tzv. command prompta)
csc.exe program.cs pozdrav.cs
Prevođenjem nastane datoteka program.exe. Pokretanjem se ispiše
Glavni!
Pozdrav iz glavnog
Pozdrav iz lokalnog
Pri tome se poziv iz glavnog programa obavlja eksplicitnim navodom razreda i metode Pozdrav.Poziv,
a pozdrav iz lokalnog se dogodi automatski pri stvaranju novog objekta razreda pozdrav naredbom
new, koji pokrene metodu Pozdrav razreda Pozdrav. Metoda imena jednakog imenu razreda
zove se konstruktor, o čemu će više riječi biti kasnije.
Sljedeći primjer prikazuje poziv postupka VisokiC unutar istog razreda:
Primjer Osnove\vozdra.cs
30
Izvorni kod u datoteci proba.cs:
class Proba {
static void Main () {
Vozdra.VisokiC();
}
}
Nastane izvršna datoteka proba.exe koja poziva metodu VisokiC sadržanu u programu vozdra.exe, a
koja ispisuje:
C#
31
Slika 13. Tipovi podataka
Želimo li instancirati varijablu tipa int, možemo to učiniti koristeći dugi naziv tipa System.Int32 (32
označava broj bitova koje u memoriji zauzima varijabla navedenog tipa) ili skraćeni naziv tj. alias int
(obje deklaracije su jednako valjane). Na primjer:
System.Int32 broj = 42; ili int broj = 42;
32
4.2.2 Varijable i pridruživanje vrijednosti
Varijabla je imenovana memorijska lokacija određenog tipa i poznate veličine te vrijednosti koja se u
njoj nalazi a koja se može promijeniti. Prije uporabe (zadavanja ili korištenja vrijednosti) varijablu
treba deklarirati:
int broj1; // <type> <variable-name>;
Varijabli možemo pridružiti vrijednost operatorom = ovako:
broj1 = 45; // <variable-name> = <exp>
varijable val1 i val2 pri deklaraciji imaju vrijednost 0, nakon čega val2 poprimi vrijednost 5.
S druge strane, reference su slične onom što bismo u programskom jeziku C zvali pokazivačima.
Nakon izvođenja sljedećeg programskog odsječka
Primjer Osnove\VrijednostiReference
class Razred
{
public int Value = 0;
}
Razred ref1 = new Razred();
Razred ref2 = ref1;
ref2.Value = 123;
obje varijable ref1 i ref2 imaju istu vrijednost 123. Razlog tome je što operator new stvara novu
instancu razreda Razred i vraća pokazivač na nju, a taj pokazivač bude prepisan u varijablu ref2 pa
ref2 pokazuje gdje i ref1.
Da bismo izbjegli stvaranje novog stringa svaki put kada na originalnom radimo neku promjenu,
koristi se razred StringBuilder (System.Text.StringBuilder). Sve promjene obavljaju se na originalnom
nizu znakova. Na primjer:
Primjer Osnove\Enum
enum Dani
{
Ponedjeljak, Utorak, Srijeda, Cetvrtak, Petak, Subota, Nedjelja
}
int x = (int) Dani.Ponedjeljak; //dani počinju od 0
int y = (int) Dani.Utorak;
Console.WriteLine("Pon={0}", x);
Console.WriteLine("Uto={0}", y);
4.2.6 Polja
U jeziku C# polja su objekti čiji je bazni razred System.Array. Indeks prvog člana je 0. U deklaraciji
uglate zagrade se navode uz tip a ne varijablu (int[] a za razliku od int a[]). Slijede primjeri
jednodimenzionalnih polja (vektora), a zatim i drugih vrsta polja.
34
Primjer Osnove\Polja
Kad ne bismo instancirali ili inicijalizirali polje, varijabla bi bila null (analogno neinicijaliziranom
pokazivaču u jeziku C).
Za duljinu polja moguće je pri deklaraciji navesti i varijablu:
int n = 3;
int[] d = new int[n];
35
Primjer pravokutnih višedimenzionalnih polja :
int[,] a = new int[3,5]; //inicijalno vrijednosti 0
Napomena: u jeziku C# ne može se navesti dimenzija veća nego što je pobrojano elemenata, kao što
je to moguće u jeziku C.
Poseban slučaj višedimenzionalnih polja su nazubljena polja (eng. jagged array) ili polja polja, s
retcima različite duljine, korisna kad imamo takve podatke da bi korištenje pravokutnih polja
rezultiralo nepotrebnim rasipanjem memorijskog prostora, primjerice kad postoji veliki nesrazmjer u
broju podataka dva retka istog polja.
int[][] a = new int[][] {
new int[] {1,2}, // "slabo popunjeni" redak
new int[] {3,4,5,6,7,8,9} // "jako popunjeni" redak
};
int[][] b = { new int[]{1,2},
new int[]{3,4,5,6,7,8,9}
};
int[][] c;
c = new int[5][];
c[0] = new int[3];
...
36
pretvaranje tipa int u double, int u long i slično. Eksplicitna konverzija navodi se nekim od sljedećih
načina (ne samo njima):
Primjer: Osnove\Konverzija
operator konverzije tipa (cast):
int c = (int) 4.5;
metoda ToString():
int a = 154;
string s = a.ToString();
metoda Parse():
int c = Int32.Parse(s);
razred Convert:
decimal d = Convert.ToDecimal(c);
Pretvorba nekog vrijednosnog tipa podataka u referencijski tip object naziva se boxing. Postupak
alocira instancu i kopira vrijednost u novostvoreni objekt. Obrnuti postupak, izdvajanje vrijednosnog
tipa podataka iz tipa object, naziva se unboxing. Tim se postupkom vrši kopiranje vrijednosti
(objekta) s reference.
Primjer Osnove\Boxing
object o = i; // Boxing
int j = (int) o; //
Unboxing
Osnovni tipovi podataka smještaju se na sistemski stog (eng. stack) a objekti na hrpu (eng. heap).
String se ne može deklarirati kao nulabilan. String može biti prazan (tzv. null-string) ali to ne znači da
je null.
37
string s = string.Empty // isto što i s = ""
Varijable definirane kao dynamic varijable također nemaju unaprijed definirani tip podataka, već se
stvarni tip podatka određuje prilikom izvršavanja.
dynamic s;
s = "Neki tekst";
Console.WriteLine(s.GetType());
s = 12;
Console.WriteLine(s.GetType());
U ovom slučaju zaobilazi se provjera prilikom kompilacije (većinom nepoželjno osim u iznimnim
slučajevima).
4.3 Operatori
4.3.1 Aritmetički operatori, operatori usporedbe i logički operatori
Aritmetički operatori (+, -, *, /, %, ++, --) i operatori usporedbe (==, !=, >, >=, <, <=) isti su kao i u
jeziku C.
Operatori == i != mogu se koristiti sa svim tipovima podataka, a ostali usporedbeni operatori mogu se
koristiti samo s tipovima podataka koji podržavaju usporedbene operatore. Npr. bool vrijednosti ne
mogu se uspoređivati operatorima <, <=, >, >=. Pri usporedbi referenci uspoređuju se adrese
(pokazivači) na objekte. Izuzetak su nizovi znakova kao specifičan tip podatka.
Logički operatori (&, |, ^, &&, ||, !, ~) obavljaju se isključivo nad operandima tipa bool i rezultat
logičke operacije je tipa bool. U ovu grupu mogu se pribrojiti i unarni true i false.
38
int n = 3;
if (n is int)
...
Operator . (točka) za pristup članovima razreda: name1 . name2
Operator indeksiranja: []
Indirekcija i adresa: * -> [] &
Category Operators
Primary (x), x.y, f(x), a[x], x++, x--, new, typeof, sizeof, checked
Unary unchecked
+, -, !, ~, ++x, --x, (T)x
Multiplicative *, /, %
Additive +, -
Shift <<, >>
Relational <, >, <=, >=, is
Equality ==
Logical AND &
Logical XOR ^
Logical OR │
Conditional AND &&
Conditional OR ││
Conditional ?:
Assignment =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, │=
39
4.4.2 Petlje
Petlje omogućavaju kontroliranu iteraciju, odnosno ponavljanje bloka naredbi. U jeziku C# postoje
petlje while, do-while, for i foreach (sjetimo se da sve osim foreach postoje i u jeziku C). Standardne
petlje obavljaju se ovisno o logičkom uvjetu, dok foreach iterira kroz listu objekata.
While i do-while imaju sintaksu:
while (expression) statement
do statement while (expression);
gdje je logički izraz tipa boolean.
For-petlja ima sintaksu (logički izraz je također boolean):
for ([initializers]; [expression]; [iterators]) statement
Primjer:
int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0};
for(int=0;i<numbers.length;i++){
Console.WriteLine(numbers[i]);
}
Ali ne može:
foreach (int i in numbers){
numbers[i] += 1;
}
4.4.3 Skokovi
Kao i u jeziku C postoje naredbe za skok: break i continue.
Break iskače iz programske strukture u kojoj je naveden (npr. petlja for), a continue nastavlja s
provjerom uvjeta za sljedeću iteraciju petlje.
4.5 Zadaci
Zadatak 1. Napisati program koji iz polja stringova ispisuje one koji sadržavaju zadani podniz.
Zadatak 2. Napisati program koji učitava tekst sa standardnog ulaza, mijenja ga u velika slova te
ispisuje tekst u obrnutom poretku.
40
Zadatak 3. Demonstrirati generator pseudoslučajnih brojeva. Upotrijebiti razred
System.Random.
Zadatak 4. Iz kojeg se tipa podataka u jeziku C# izvode svi ostali tipovi podataka?
Zadatak 5. Može li se bez pogreške izvesti sljedeći programski odsječak? Zašto?
int[] list = {1,2,3,4,5};
foreach(int i in list){
i = i * 2;
}
41
5 Objektno orijentirano programiranje
Objektno orijentirano programiranje za razliku od proceduralnog programiranja zahtjeva drugačiji
način razmišljanja o problemu koji programom rješavamo. Objektno usmjerena paradigma entitete iz
stvarnog svijeta opisuje apstraktnim objektima (razredima, klasama objekata) to jest "Sve je objekt".
Objektni pristup integrira oblikovanje podataka i procesa. Tokovi podataka, entiteti i veze te procesi
budu integrirani u objekte, a složeni sustavi grade se iz pojedinačnih, objektnih komponenti.
5.1 Koncepti
Osnovni koncept objektnog programiranja jest promatranje podataka kao objekata. Objekt (eng.
object) je svaka pojava, pojam ili predmet (stvarni ili zamišljeni) o kojem se prate podaci i načini
rukovanja podatcima (procesi). Pojedinačna pojava ili instanca objekta (eng. object instance) ima
vlastito stanje i ponašanje kojim se razlikuje od drugih objekata (kao npr. ljudi). Postupak kojim se se
objekti stvarnog svijeta pojednostavljuju, obuhvaćanjem glavnih aspekata objekta uz ispuštanje
nevažnih detalja zove se apstrakcija (eng. abstraction). Apstrakcije mogu biti uređene hijerarhijski (o
tome više kasnije).
Nadalje, grupa objekata se generalizira u tip objekta (eng. abstract data type) tj. razred (eng. class) -
zajednički naziv za sve objekte sa zajedničkim svojstvima (eng. property) i postupcima rukovanja
(eng. process, method), npr. Proizvod. Opis grupe objekata koji imaju jednake atribute, operacije,
veze i semantiku. Objekt je instanca razreda, s vlastitim vrijednostima svojstava, a razred je njegova
apstraktna definicija. Razredi imaju već spomenuta svojstva to jest atribute (eng. attribute) - skup
vrijednosti koje instanca može poprimiti za neku karakteristiku. Svojstvo može biti nekog oćeg ili
korisnički definiranog tipa, npr. integer, boolean ili Adresa. Implementacije rukovanja objektima
zovemo postupcima (eng. method) ili operacijama (eng. operation) koje imaju prototip to jest
„potpis” (eng. signature), koji definira naziv, parametre i povratnu vrijednost potprograma koji ih
implementira.
Ključni koncepti objektno orijentiranog oblikovanja programa i programiranja:
42
5.2 Razredi
5.2.1 Članovi razreda
Osnovni element objektnog programiranja je razred. U jeziku C# razredi se sastoje od sljedećih
članova (eng. members):
abstract – razred može biti samo osnovni razred koji će drugi nasljeđivati
const – atribut (polja) ili lokalna varijabla je konstanta
new – modifikator koji skriva naslijeđenog člana od člana osnovnog razreda
readonly – polje poprima vrijednost samo u deklaraciji ili pri instanciranju
sealed – razred ne može biti naslijeđen
static – jedini, zajednički član svih instanci razreda (ne kopija nastala s instancom)
virtual – postupak ili dostupni član koji može biti nadjačan u naslijeđenom razredu – (prilikom
nadjačavanja dodaje se modifikator override)
Ako modifikator nije naveden onda su se primijenjuju pretpostavljeni modifikatori tj. smatra da je:
2
Razlikovati pojam polja kao članskog podatka (field) od polja programske strukture (array)
43
internal za razrede, sučelja, delegate i događaje
private za članske varijable, svojstva i postupke i ugniježđene razrede
public za postupke sučelja i članove enumeracija (nije ni dozvoljen drugačiji modifikator)
Napomena: Izvedeni razred ne može imati veću dostupnost od baznog razreda.
Primjer Razredi\Razred
5.2.4 Konstruktori
Konstruktor je postupak koji se obavlja pri stvaranju instance. Standardni (eng. default) konstruktor i
preopterećenje konstruktora s argumentima. Ne vraća vrijednost, služi za inicijalizaciju instance. Ime
mu je jednako imenu razreda. Razred može imati više konstruktora.
Primjer Razredi\Razred
class Razred
{
//atributi
public readonly int neDiraj;
public int var = 0;
...
//konstruktori
public Razred(){
neDiraj = 0;
}
public Razred(int neDiraj0, int var0) {
neDiraj = neDiraj0;
var = var0;
}...
}
44
Instanciranje objekta upotrebom različitih konstruktora:
Razred r1 = new Razred();
Razred r2 = new Razred(13,666);
Razred r2 = new Razred() {var=4};
Ako nije eksplicitno napisan niti jedan konstruktor, automatski postoji podrazumijevani ("prazni")
konstruktor bez parametara. Ako je napisan barem jedan konstruktor, onda se postojanje "praznog"
ne podrazumijeva.
Stvoreni objekti, za razliku od jezika C/C++, u automatski se uklanjaju iz memorije pomoću sakupljača
smeća (eng. Garbage Collector) ako na njih ne pokazuje niti jedna referenca. Sakupljanje smeća
obavlja tijekom izvođenja programa. Ne može se unaprijed točno odrediti kada će se memorija
osloboditi, ali se može potaknuti pozivom postupka sakupljača smeća GC.Collect().
Neposredno prije uništenja objekta od strane sakupljača smeća, automatski se poziva postupak
Finalize tog objekta. Postupak Finalize se ne može direktno napisati, nego se piše nalik destruktoru u
jeziku C++ . Naziv mu je jednak je nazivu razreda s predznakom '~‘ te ne vraća vrijednost. Nije ga
potrebno pisati ako se ne koriste takozvani “unmanaged” resursi (oni koje programer stvara i
uništava samostalno).
Primjer Razredi\Razred
class Razred
{
...
~Razred(){
Console.WriteLine("Finalizer");
}
}
5.2.5 Postupci
Postupak (metoda) je programska funkcija pridružena razredu (mora biti pridružena, C# ne dopušta
pisanje globalnih metoda). Metodama se definira određeno ponašanje razreda i običaj ih je nazvati
po ponašanju koje obavljaju - u ovom primjeru Zbroji i Oduzmi.
Primjer Razredi\Postupci
class Postupak
{
private int brOp = 0; // private: skrivanje člana
Primijetimo da je član brOp skriven, tj. ima privatni modifikator i moguće mu je pristupiti samo iz
samog objekta. Postupci Zbroji i Oduzmi mogu pristupiti članu brOp, ali mu se ne može pristupiti iz
glavnog programa. Skrivanje člana zove se učahurivanje ili enkapsulacija.
45
Postupak p = new Postupak();
int a = 10, b = 7;
int zbroj = p.Zbroji(a, b);
int razlika = p.Oduzmi(a, b);
Ključnom riječi params se prenosi varijabilni broj argumenata. Koristi se kad broj argumenata nije
unaprijed poznat. Polje argumenata može biti bilo kojeg tipa.
public static void TestParams(params object[] args){
Console.WriteLine("Params: ");
for(int i= 0; i< args.Length; i++)
Console.WriteLine("{0}:{1}", i, args[iArg])
}
TestParams("jedan", "dva", 3);
TestParams();
Primjer: TestParams(args);
Postoje i opcionalni argumenti kojima se zadaje pretpostavljena vrijednost. Navode se zadnji po redu.
public static void TestDefault(
int a,
int b = 99999,
string s = "default string")
{
Console.WriteLine("a = {0}, b = {1}, s = {2}", a, b, s);
}
...
TestDefault(1, 2, "RPPP");
TestDefault(2, 15);
TestDefault(3);
46
Imenovani argumenti - Prilikom poziva navodi se naziv argumenta i vrijednost odvojeni dvotočkom.
Imenovani argumenti se navode zadnji.
TestDefault(2, s:"moj string");
TestDefault(s: "moj string", b:55, a:4);
5.2.6 Svojstva
Svojstvo je postupak pristupa zaštićenim varijablama instance i specifično je za jezik C#.
Vratimo se na prethodni Primjer Razredi\Postupci u kojemu je član brOp privatan. Želimo li ipak
omogućiti npr. dohvat vrijednosti člana, umjesto da pišemo postupak za pristup skrivenom članu
GetBrOp() koji bi vratio vrijednost brOp, koristimo javno svojstvo:
public int BrOp
{
get //omogućava dohvat vrijednosti člana
{
return brOp;
}
}
Želimo li omogućiti i izmjenu člana brOp, pored get-dijela (eng. getter) dodajemo svojstvu set-dio
(eng. setter):
public int BrOp
{
get { //omogućava dohvat vrijednosti člana
return brOp;
}
set { //omogućava promjenu vrijednosti
brOp = value;
}
}
brojOperacija = p2.BrOp;
Console.WriteLine("{0} + {1} = {2}, {0} - {1} = {3}, Broj operacija = {4}",
a, b, zbroj, razlika, brojOperacija);
p2.BrOp = 100;
Za trivijalne slučajeve korištenja get i set u svojstvima tj. kada svojstvo služi samo kao omotač oko
privatne varijable može se olakšati pisanje korištenjem automatskog svojstva. Interno se kreira
privatna varijabla. Automatsko svojstvo iz primjera moramo inicijalizirati u konstruktoru. Želimo li
47
ipak zaštiti član brOp od vanjskih izmjena, kod automatskog svojstva može se postaviti private
modifikator na set dio.
public int BrOp { get; set; } //ili public int BrOp { get; private set; }
public Postupak_v4(){
BrOp = 0; //automatsko svojstvo moramo inicijalizirati u konstruktoru
}
Primjer Razredi\SvojstvaIndekseri
class Temperatura{
private float T;
public float Celsius{
get { return T - 273.16f; }
set { T = value + 273.16f; }
}
public float Fahrenheit{
get { return 9f / 5 * Celsius + 32; }
set { Celsius = (5f / 9) * (value - 32); }
}
}
5.2.7 Indekseri
Indekseri omogućavaju korištenje objekta kao niza (pristup elementima operatorom [ ]). Sintaksa je
ona uobičajena za svojstva (get i set).
public Temperatura this[int index] // Indekser
{
set{
if (index >= 0 && index < nizTemperatura.Length)
nizTemperatura[index] = value;
else throw new Exception("Pogreška!");
}
get{
if (index >= 0 && index < nizTemperatura.Length)
return nizTemperatura[index];
else throw new Exception("Pogreška!");
}
}
48
Primjer: Razredi\PreopterecenjePostupaka
Primjer: Razredi\PreopterecenjeOperatora
5.3 Nasljeđivanje
5.3.1 Nasljeđivanje općenito
Nasljeđivanje omogućuje izvođenje (deriviranje, ne pokretanje) novog razreda na temelju postojećeg
razreda. Time je izvedeni razred proširenje osnovnog razreda, odnosno nasljeđuje osnovnu
funkcionalnost osnovnog razreda (njegove članove) i definira vlastitu.
Osnovni se razred naziva još i bazni razred (eng. base class), superrazred (eng. superclass) ili roditelj
(eng. parent), a izvedeni derivirani (eng. derived), podrazred (eng. subclass) ili dijete (eng. child).
Osnovni je razred generalizacija izvedenog, odnosno izvedeni je specijalizacija osnovnog.
class DerivedClass: BaseClass { }
Prilikom nasljeđivanja, moguće je i operaciju deklariranu u osnovnom razredu poništiti u korist
operacije jednako deklarirane u naslijeđenom razredu. Ovo se svojstvo naziva višeobličje. Podrazred
49
se ponaša drukčije odnosu na nadrazred ili neki drugi podrazred. Razred je podrazred osnovnog
razreda ako je u aplikaciji moguće zamijeniti osnovni razred podrazredom, a da aplikacija normalno
nastavi s radom. Drugim riječima, ako postoji programski kod koji se odnosi na nadrazred Kupac,
umjesto njega može se supstituirati bilo koji njegov podrazred. Ovo se svojstvo naziva zamjenjivost
(eng. supstitutability). Slijedi primjer kao na slici. Nasljeđivanje se uobičajeno označava
transparentnom strelicom.
Razredi Motocikl i Automobil nasljeđuju osnovni razred MotornoVozilo. Sva tri razreda imaju osnovna
svojstva Model i Snaga a izvedeni razredi dodatno Prikolica odnosno BrojVrata. Slično, objekti sva tri
razreda imaju zajedničku metodu DajGas, ali izvedeni razredi različito implementiraju konstruktor i
metodu Start, a Automobil tome dodaje i metodu VeziPojas. Pri tom izvedeni konstruktor izvedenog
razreda poziva osnovni konstruktor, te implementira vlastitu dodatnu funkcionalnost. Primjeri i
specifičnosti u ovom i narednim potpoglavljima.
50
Primjer Razredi\MotornoVozilo – osnovni razred
class MotornoVozilo
{
// atributi
public string Model{ get; set; } // svojstvo
...
// konstruktor
public MotornoVozilo(string model, double snaga) { ... }
// nasljeđivanje i višeobličje
Automobil auto = new Automobil("Fiat Tumpo", 100, 5);
auto.VeziPojas();
auto.Start();
auto.DajGas();
// zamjenjivost
vozilo = auto;
Console.WriteLine(vozilo.Model);
auto.Start();
auto.DajGas();
Varijante nasljeđivanja
51
Virtual deklarira virtualni postupak roditelja koji može biti nadjačan.
Override deklarira postupak djeteta koji nadjačava, a može koristiti nadjačani postupak.
U programskom jeziku C# moguće je naslijediti samo jedan razred, a implementirati više sučelja.
class Osoba : Partner, IAdresa, IRazred { ... }
Varijable i postupci koje su javne ili zaštićene (public i protected) se nasljeđuju, dok privatne varijable
i postupci ne mogu biti naslijeđeni. Osim toga, razred označen kao sealed ne može biti naslijeđen.
Pokušaj nasljeđivanja razreda: sealed class SealedPoint { ... }:
class MyPoint : SealedPoint
dovodi do pogreške prevođenja.
Nadjačanim članovima pristupa se iz izvedenog razreda s base.member npr. base.F();
Instanciranje objekta izvedenog razreda izaziva poziv konstruktora osnovnog razreda. Pri uništenju
objekta prvo se poziva finalizator izvedenog razreda, a zatim finalizator osnovnog razreda.
52
Primjer apstraktnog razreda:
Primjer Razredi\PoslovniPartner
public PoslovniPartner(
string maticniBroj, string adresaSjedista, string adresaIsporuke)
{
this.MaticniBroj = maticniBroj;
// obavlja se validacija preopterećenom metodom!
if (!this.ValidacijaMaticnogBroja())
throw new Exception("Pogreška unosa matičnog broja!");
this.AdresaSjedista = adresaSjedista;
this.AdresaIsporuke = adresaIsporuke;
}
...
public abstract bool ValidacijaMaticnogBroja();
...
}
53
5.3.3 Dinamičko višeobličje
Za razliku od „običnog“ statičkog višeobličja kod kojeg je unaprijed jasno koja će se izvedena metoda
izvesti, kod dinamičkog višeobličja pretvorba ovisi o dinamičkoj konverziji tipa.
Može na primjer postojati hijerarhija nasljeđivanja kao na sljedećoj slici. Kadrovska služba ima listu
djelatnika za koje se obavlja isplata. Apstraktni razred Djelatnik predstavlja korijen, a PoSatu i
Pausalac listove hijerarhije.
U listu djelatnika stavljamo instance svih razreda osim korijena. Pojedina referenca u listi može
pokazivati na različite objekte, a tip trenutnog objekta određuje postupak koji se obavlja.
Želimo li pozvati neku od metoda specifične za naslijeđene razrede, trebamo načiniti konverziju tipa
koja će odrediti raspoložive metode (npr. Dividendaj i PisiSate). Osnovna metoda Plati postoji
međutim u svim naslijeđenim razredima pa bude pozvana baš ona koja se odnosi na referencu
elementa liste, kao u naredbi lista[count].Plati();
54
Primjer Razredi\Kadrovska
public Kadar () {
lista = new Djelatnik[6];
lista[0] = new Pausalac ("Bobi", ...);
lista[3] = new Pausalac ("Rudi", ...);
...
((Pausalac)lista[0]).Dividendaj (500.00); // cast
((PoSatu)lista[3]).PisiSate (40); // cast
}
Primjer Razredi\Kompozicija
class Osoba
{
PoslovniPartner poslovniPartner;
private string ime;
private string prezime;
...
}
Možemo stvoriti i listu referenci na objekte drugih razreda, kao što je bio slučaj u prethodnom
primjeru liste djelatnika. Ukoliko ovi objekti mogu postojati i bez da bude instanciran objekt koji ih
okuplja, veza se naziva agregacija.
55
Odjel
1..n +TraziPovisicu() 1
Nasuprot tome, kompozicija je takav odnos u kojem jedan razred instancira (u svom konstruktoru)
kolekciju pripadnih objekata, te uništava pripadne objekte (u svom destruktoru). U jeziku za
obliovanje UML, ove se asocijacije označavaju transparentnim, odnosno punim rombom.
StudentskaSlužba Studomat
- studomati: Studomat
1 3
+ dohvatiStudomat() + prijaviIspit()
+ dohvatiSveStudomate() + odjaviIspit()
+ azurirajStudomat()
+ azurirajSveStudomate()
Razvojne okoline kao što je Visual Studio nemaju mogućnost takvog tumačenja programskog koda te
prikazuju pojedinačne reference ili polja referenci usmjerenim strelicama.
5.3.5 Sučelja
Sučelje (eng. interface) omogućava definiciju određenog ponašanja to jest svojstava objekata koji se
mogu primijeniti na razrede neovisno o hijerarhiji. U sučelju se članovi razreda specificiraju bez
implementacije, to jest sučelje sadrži samo deklaracije operacija. Može sadržavati postupke, svojstva,
indeksere i događaje. Svaki postupak je apstraktan.
Sučelje definira obavezu ugradnje. Razred koji nasljeđuje sučelje, mora implementirati sve postupke.
Sučelje može implementirati i apstraktni razred.
Sučelja su posebno važna u jeziku C# gdje razred može naslijediti samo jedan razred, a implementirati
više sučelja.
Realizacija (eng. realisation) - veza izvornog razreda i sučelja. Sučelje može biti argument nekog
postupka čime se postiže veća općenitost.
Standardni naziv za sučelje ima veliko početno slovo I (npr. INaziv). U razredu koji realizira sučelje se
koristi proširena i skraćena (eng. lollipop) notacija.
56
Primjer Razredi\Sucelje
interface IPoint
{
// Property signatures:
int x { get; set; }
int y { get; set; }
}
InterfaceMain.PrintPoint(tocka);
Može naravno postojati više realizacija istog sučelja i sve bi one bili ispravni argumenti.
5.4 Kolekcije
Kolekcija je skup povezanih objekata. U jeziku C# prostor imena koji sadrži sučelja i razrede za rad s
kolekcijama zove se System.Collections. Sadrži sučelja: ICollection, IEnumerator, IEnumerable,
57
IDictionary i IList koja određuju osnovne funkcionalnosti kolekcija. Razred koji implementira jedno ili
više tih sučelja naziva se kolekcija.
Razredi sadržani u System.Collections:
ArrayList implementira sučelje IList pomoću polja za pohranu objekata čija se veličina po
potrebi povećava
BitArray Radi s poljem bitova koji su predstavljeni kao Boolean vrijednosti (true
predstavlja 1 a false 0)
Hashtable Predstavlja kolekciju vrijednosti ključ-i-vrijednost parova (vrijednost je objekt
pohranjen u kolekciji) organiziranih pomoću hash vrijednosti ključa
Queue Predstavlja first-in-first-out kolekciju objekata
SortedList Predstavlja kolekciju ključ-i-vrijednost parova poredanih (sortiranih) po ključu,
uz moguć dohvat po ključu i indeksu
Stack Predstavlja last-in-first-out kolekciju objekata
Primjer Razredi\Kolekcije
lista.Add(1);
lista.Add("abc");
if (lista.Contains("abc"))
Console.WriteLine("Lista sadrži abc");
lista.Clear();
58
5.4.2 Kolekcije Stack i Queue
Stog (eng. stack) i red (eng. queue) predstavljaju nizove podataka istog tipa s ograničenim pristupom
elementima. Kod stoga je dozvoljen unos elementa samo na vrh i skidanje s vrha, a kod reda unos
elementa na dno i skidanje s vrha.
Neka svojstva i postupci kolekcije Stack:
Primjer Razredi\Kolekcije
stog.Push("abc");
stog.Push(123);
59
Slika 22. Parametrizirani razred
Slično, općenita klasa "račun" može imati realizacije "cjelobrojni račun" i "decimalni račun".
Primjer Razredi\Generics
Prednost generičkih kolekcija je ta što su tipizirane. Negeneričke kolekcije objekte pohranjuju kao
System.Object i takva pohrana je prednost sa stanovišta fleksibilnosti, ali ima nedostataka. Glavni je
60
nedostatak je obavljanje boxinga prilikom dodavanja podataka tipa vrijednosti (dobivanje reference
na value podatak da bi se s tim podatkom moglo postupati kao sa System.Object). To utječe na
performanse za veće količine podataka. Također je potrebna konverzija (unboxing) da se od objekta
dobije smisleni podatak. Generičke kolekcije su dakle imaju bolje performanse (ne mora se obavljati
boxing/unboxing) i tipski su sigurne (eng. type safety) to jest zaštićene su od unosa podataka
nepoželjnog tipa i pogrešaka koje pritom mogu nastati (npr. pokušaj izvršavanja naredbe neprikladne
za dani tip podataka).
Evo primjera vlastitog parametriziranog razreda:
Primjer Razredi\Generics
using System.Collections.Generic;
Tip parametriziranog razreda se može ograničiti ključnom riječi where. Primjeri ograničenja nekog
tipa T:
where T:struct – tip T mora biti tip vrijednosti (nullable također isključen)
where T:class – tip T mora biti tip reference
where T:new() – tip T mora imati prazni konstruktor
where T:naziv baznog razreda – tip T mora biti navedeni razred ili razred koji ga nasljeđuje
where T:naziv sučelja – tip T mora implementirati navedeno sučelje
where T:U – tip T mora biti tipa U ili izveden iz tipa U pri čemu je U drugi tip po kojem se vrši
parametrizacija
U sljedećem primjeru GenRazred je određen s dva tipa pri čemu prvi tip mora biti Stog iz prethodnog
primjera određen tipom koji implementira sučelja IPoint i ima prazni konstruktor:
public class GenRazred<T, U>
where T:Stog<U> where U:IPoint, new(){
...
61
Primjer Razredi\HashTablice
a.Remove(200); // ukloni
a.Clear(); // isprazni
Rječnik (eng. dictionary) je kolekcija koja ima istu funkcionalnost kao tablica s raspršenim
adresiranjem, ali su ključ i vrijednost tipizirani.
Imenik System.Collection.Generic sadrži razred Dictionary(Tkey, TValue).
Primjer Razredi\HashTablice
a.Add(100, "Jedan");
a[200] = "Dva";
foreach(KeyValuePair<int,string> d in a){
Console.WriteLine(d.Value);
}
...
5.4.5 Proširenja
Proširenje (eng. extension) omogućava dodavanje postupaka postojećem razredu bez da je potrebno
stvaranje novog razreda ili promjena postojećeg razreda. Razred za koji se piše proširenje je naveden
kao prvi parametar statičke metode u statičkom razredu, uz koji se navodi prefiks this. Proširenje se
poziva kao da se radi o postupku unutar tog razreda (iako to nije).
62
Primjer Razredi\Generics
5.5 Zadaci
Zadatak 1. Implementirati razred Planet. Konstruktor neka prima radijus, gravitaciju i ime
planeta. Razred sadrži i statičku varijablu za brojanje instanciranih planeta, svojstva
Ime, Radijus, Gravitacija i postupak GetCount(). Demonstrirati rad implementiranog
razreda.
Zadatak 2. Implementirati razred PlanetCollection. Razred predstavlja listu planeta. Iskoristiti
razred iz prethodnog zadatka s planetima. Napisati postupak Add za dodavanje
planeta. Planetima se može pristupati preko indeksa.
Zadatak 3. Implementirati razred PlanetCollection. Razred predstavlja listu planeta. Iskoristiti
razred iz prethodnog zadatka s planetima. Napisati postupak Add za dodavanje
planeta. Planetima se može pristupati preko indeksa.
Zadatak 4. Definirati i ugraditi razrede s dijagrama iz primjera Razredi\Kadrovska
Zadatak 5. Napisati razred DjelatnikCollection - kolekciju djelatnika. Naslijediti sučelje IList.
Napisati parametriziranu kolekciju i postaviti ograničenje da prima samo tipove
izvedene iz Djelatnik.
Zadatak 6. Za model/kod sa slike (Motorno vozilo) za primjer Razredi\MotornoVozilo
odgovoriti na sljedeća pitanja:
a) Tko što nasljeđuje?
b) Može li se „sakriti” bazno svojstvo ili metoda (public pretvoriti u private) ?
c) Što bi bilo da metoda Start nije virtualna?
63
Zadatak 7. Napisati programski kod sučelja i realizacije.
StoreHome Store
POSterminal +create()
<<use>> <<interface>> +login(UserName, Passwd)
POSterminal Store +find(StoreId)
+getPOStotals(POSid)
+getPOStotals(POSid) +updateStoreTotals(Id,Sales)
+updateStoreTotals(Id,Sales) +get(Item)
+get(Item)
StoreHome Store
64
6 Tehnike programiranja
provjeriti ispravnost svih vrijednosti podataka iz vanjskih izvora (datoteka, korisnik, mreža, ...)
provjeriti ispravnost svih vrijednosti ulaznih parametara
odlučiti kako postupiti u slučaju neispravnih podataka
Primjer defenzivnog programiranja može se ilustrirati jednostavnim primjerom rekurzivnog računanja
funkcije za faktorijele u kojoj za negativne vrijednosti nastupa (teorijski) beskonačna rekurzija.
int faktorijel( int N )
{
if ( N == 0 ) return 1;
else return N * faktorijel( N-1 ) ;
}
Matematički neprecizno rješenje, ali takvo da sprječava beskonačnu rekurziju u slučaju negativnih
brojeva je prikazano u donjem primjeru.
int faktorijel( int N )
{
if ( N <= 0 ) return 1;
else return N * faktorijel( N-1 ) ;
}
65
pozvati „globalnu“ metodu za obradu pogreške
bezuvjetno završiti program, npr. Application.Exit(CancelEventArgs)
6.3 Iznimke
Iznimka predstavlja problem ili promjenu stanja koja prekida normalan tijek izvođenja naredbi
programa. U programskom jeziku C#, iznimka je objekt instanciran iz razreda koji nasljeđuje
System.Exception iz kojeg su izvedena dva značajna razreda: SystemException, bazni razred za
iznimke koje generira CLR i ApplicationException, bazni razred za iznimke aplikacije. Značajnija
svojstva svake iznimke su:
StackTrace – sadrži popis poziva postupaka koji su doveli do pogreške
Message – sadrži opis pogreške
Source – sadrži ime aplikacije koja je odgovorna za pogrešku
TargetSite – sadrži naziv postupka koji je proizveo pogrešku
Neke od ugrađenih sistemskih iznimki su:
ArrayTypeMismatchException: tip vrijednosti koji se pohranjuje u polje je različit od tipa polja
i implicitna konverzija se ne može obaviti
DivideByZeroException: pokušaj dijeljenja s 0
IndexOutOfRangeException: indeks polja je izvan deklarirane veličine polja
InvalidCastException: nedozvoljena konverzija tipa
OutOfMemoryException: nedostatak memorije za alociranje objekta
OverflowException: preljev pri izračunavanju aritmetičkog izraza
NullReferenceException: referenci nije pridružen objekt
StackOverflowException: stog je prepunjen
3
Treba napomenuti da mora postojati ili blok catch ili blok finally, to jest blok try ne može biti jedini blok. Za
razliku od programskog jezika Java u kojem je takva mogućnost ostavljena zbog varijante try-with-resourses, C#
to ne dozvoljava, a automatsko otpuštanje resursa umjesto blokom try-with-resourses u C#-u je riješeno
korištenjem bloka using.
66
try {
//dio koda koji može dovesti do iznimke
}
catch (ExcepType1 exOb){
//kod koji se obavlja u slučaju iznimke tipa ExcepType1
}
catch (ExcepType2 exOb) {
//kod koji se obavlja u slučaju iznimke tipa ExcepType2
}
...// ostali catch blokovi
finally {
//kod koji se obavlja nakon izvođenja try, odnosno catch blok
}
U sljedećem primjeru ovisno o vrijednosti slučajno generiranog broja može se dogoditi pogreška
nastala dijeljenjem s nulom nakon čega se prekida normalno izvršavanje programa te se počinje
izvršavati programski kod u bloku catch pridruženom iznimci DivideByZeroException. Ako slučajno
generirani broj nije bio nula tada dolazi do pogreške u pristupu elementu polja
(IndexOutOfRangeException). Blok finally će se izvršiti neovisno o tome da li je programski kod u
bloku try ispravno završio ili je došlo do iznimke i eventualne obrade iznimke. U ovom primjeru blok
catch s iznimkom Exception se neće nikada izvršiti, jer se uvijek događa iznimka koja je uhvaćena
jednim od prethodnih blokova catch.
try
{
int x = new Random().Next(2); //0 ili 1
int y = 10 / x;
int[] a = { 1, 2, 3 };
Console.WriteLine(a[3].ToString());
}
catch(DivideByZeroException e)
{
Console.WriteLine("Dijeljenje s 0. " + e.Message);
}
catch(IndexOutOfRangeException e)
{
Console.WriteLine("Indeks izvan granica polja. " + e.Message);
}
catch (Exception e)
{
Console.WriteLine("Pogreška. " + e.Message);
}
finally
{
Console.WriteLine("Napokon.\n");
}
67
throw new ApplicationException("poruka");
...
catch(Exception e){
Console.WriteLine( "Izvor: {0}", e.Source );
Console.WriteLine( "Postupak: {0}", e.TargetSite );
Console.WriteLine( "Poruka: {0}", e.Message );
Console.WriteLine( "Trag: {0}", e.StackTrace );
}
Naredbom throw moguće je proslijediti već uhvaćenu iznimku. Bitno je naglasiti da je u tom slučaju
moguće napisati throw ili throw e, gdje je e uhvaćena iznimka. Ključna razlika između ova dva
pristupa je (ne)očuvanje traga iznimke. Primjerice ako se u sljedećem primjeru dogodila iznimka, tada
u trenutku kad je uhvaćena iznimka, neposredno prije retka C, objekt e sadrži informaciju da se
iznimka dogodila u retku B kojem je prethodio redak A. Proslijeđivanjem iznimke samo s throw za
posljedicu će imati da će prilikom sljedećeg hvatanja iznimke postojati informacija da se iznimka
dogodila u retku C4 kojem je prethodio redak A. Proslijeđivanjem iznimke s throw e kod sljedećeg
hvatanja tako proslijeđene iznimke postojat će samo informacija da se iznimka dogodila u retku C,
bez informacija što je prethodilo toj iznimci5.
4
Primijeniti da više nema informacija o retku B
5
Ponašanje je u skladu s očekivanim, jer je formalno došlo do generiranja nove iznimke, a ne prosljeđivanja
68
Primjer Kodiranje \ CustomException
Dodatne mogućnosti su zamjena uhvaćene iznimke s nekom drugom (bacanjem neke druge iznimke)
ili omatanje postojeće iznimke u drugu čime se dobije ugniježđena iznimka dostupna u svojstvu
InnerException.
69
Primjer Kodiranje \ CustomException
Prosljeđivanje iznimki treba raditi kada želimo specijalizirati iznimku, primjerice zamijeniti je nekom
drugom ili omotati nekom drugom prikladnijom za prikaz informacije korisniku pri čemu se originalna
iznimka može dohvatiti u svojstvo InnerException.
6
Primjer jednog konzistentnog centraliziranog sustava obrade iznimki je paket Enterprise Library – Exception
Handling Block
70
Primjer Kodiranje \ InnerException
class Primjer
{
public void F()
...
catch(Exception e){
throw new ApplicationException
("Iznimka u Primjer.F() :", e);
...
class Program
{
static void Main(string[] args){
try{
new Primjer().F();
}
catch (Exception e)
{
Console.WriteLine("Iznimka u Main: {0}\nInnerException: {1}",
e.Message, e.InnerException.Message);
...
Iznimke treba koristiti za obavijest drugim dijelovima programa o pogreškama koje se ne smiju
zanemariti, ali te pogreške trebaju predstavljati stanja koja su stvarno iznimna, to jest situacije u
kojima programski odsječak ne možete nastaviti dalje s radom, za razliku od pogrešaka koje se mogu
obraditi lokalno. Potrebno je izbjegavati bacanje iznimki u konstruktorima i finalizatorima, osim ako
ih na istom mjestu i ne hvatamo, jer to može dovesti do inkonzistentnih stanja objekta koji se stvara,
odnosno uklanja.
6.4 Tvrdnje
Tvrdnja je naredba7 kojom se program testira tako da određeni izraz mora biti istinit, a inače se
izvršavanje programa zaustavlja. Tvrdnje se koriste za uklanjanje pogrešaka (debugging) i
dokumentiranje ispravnog rada programa u fazi kodiranja, naročito u razvoju velikih, kompliciranih
programa te u razvoju programa od kojih se zahtijeva visoka pouzdanost. Za korištenjem tvrdnje u
C#-u koristi se prostor imena System.Diagnostics i postupak Debug.Assert kojem se predaje logički
izraz za koji se pretpostavlja (tvrdi) da je istinit. Ako izraz nije istiniti ispisuje se poruka oblika
„Assertion Failed“.
7
Ovisi o programskom jeziku: u C-u su to naredbe, u C#-u postupci neke klase
71
Primjer Kodiranje \ Assert
//izračun brzine
//...
int brzina = 650;
Tvrdnje se pišu na mjestima gdje se pogreške ne očekuju, tj. ne smiju se pojaviti. Na mjestima gdje
se pogreške očekuju vrši se obrada pogreške (iznimke). Za robustan programski kod potrebno je
koristiti i tvrdnje i programski kod za obradu pogreške, pri čemu treba izbjegavati pozive metoda u
izrazima tvrdnji, npr. Debug.Assert (Obavi(), "Neobavljeno").
Preporuka je da se tvrdnje koriste za dokumentiranje i verificiranje uvjeta koji moraju vrijediti prije
pozivanja metode ili instanciranja razreda (preconditions), te uvjeta koji moraju vrijediti poslije
djelovanja metode ili rada s razredom (postconditions).
6.5 Barikade
Barikade predstavljaju sučelja koja služe kao granica prema „sigurnim“ dijelovima koda. U tu svrhu
definiraju se dijelovi softvera koji će rukovati „prljavim“ (nesigurnim) podacima i dijelovi koji rukuju
samo s „čistim” podacima. Validacijski razredi koji su odgovorni za provjeru ispravnosti podataka
sačinjavaju barikadu prema internim razredima koji rukuju s podacima za koje se pretpostavlja da su
provjereni i ispravni.
72
Slika 26. Koncept barikada
Programski primjer barikade može se ilustrirati sljedećim primjerom u kojem je varijabla index
privatna varijabla iza barikade, a u dio set svojstva Indeks služi kao sučelje barikade, jer provjerava
ulaznu vrijednost koja može biti neispravna i omogućava da ostatak razreda uvijek radi s ispravnom
varijablom index.
class Primjer
{
private int index; //privatna varijabla (iza barikade)
public Primjer()
{
}
public int Index //javna metoda (služi kao sučelje barikade)
{
get { return index; }
set
{ //provjeravamo je li unutar zadanih granica,
//ako ne, pridjeljujemo najbližu vrijednost
if (value <= 0) { this.index = 0; }
else if (value > 100) { this.index = 100; }
else { this.index = value; }
}
}
}
Barikade naglašavaju razliku između tvrdnji i obrade iznimaka. Metode s vanjske strane barikade
trebaju koristiti programski kod za obradu pogreške, a unutarnje metode mogu koristiti tvrdnje jer se
ovdje pogreške ne očekuju! Na razini razreda javne metode rukuju s „prljavim“ podatcima i „čiste“ ih,
a privatne metode rukuju samo s „čistim“ podatcima. U tom slučaju pojava „prljavog“ podatka u
73
privatnoj metodi nije iznimka koja se očekuje, već neispravnost tvrdnje koja ukazuje na pogrešku u
kodiranju. Općenito, podatke je potrebno pretvarati u ispravan tip odmah pri unosu.
Prethodni primjer ilustrira mogućnost korištenja pretprocesorskih direktiva u svrhu uklanjanja koda
koji se koristio za utvrđivanje pogreške iz produkcijske verzije programa. U prikazanom primjeru će
do ispisa različite poruke na ekranu u ovisnosti o tome je li definiran simbol RAZVOJ ili ne. Umjesto
korištenja pretprocesorskih direktiva u C#-u se može koristiti atribut Conditional. Kod za testiranje je
potrebno odvojiti u posebni postupak i iznad postupka navesti atribut Conditional i naziv simbola. U
8
ako to već sam programski jezik ne spriječava
74
slučaju da simbol nije definiran, u kompiliranoj verziji nije uključen poziv označenog postupka. Simbol
se može definirati u kodu, ali i kao parametar prilikom kompiliranja (Properties → Build →
Conditional compilation symbols). Primjerice, ako u donjem primjeru uklonimo definiciju simbola
RAZVOJ poziv metode Test bit će zanemaren prilikom kompilacije.
9
Objekti se smještaju u različite generacije, pa je moguće da se objekti više generacije uopće ne brišu dok ima
dovoljno slobodne memorije
75
Primjer Kodiranje \ Using
Ako neki razred implementira IDisposable, preporuka je da se za objekte tog razreda uvijek pozove
postupak Dispose nakon što objekt više ne bude potreban. Iako bi se za istu svrhu mogao koristiti i
bilo koji drugi postupak, prethodnost ovog sučelja očituje se u kombinaciji s ključnom riječi using i
tzv. using-blokovima. Iako se Dispose može pozvati eksplicitno, postoji mogućnost da se prethodno
dogodi iznimka te da se izvršavanje koda preusmjeri na obradu iznimki. Za objekt stvoren unutar
using bloka, Dispose se automatski poziva nakon napuštanja bloka bez obzira na razlog izlaska iz
bloka10. Using-blok se može koristiti samo za one razrede koji implementiraju IDisposable.
10
Interno, za svaki using-blok kompajler stvar kombinaciju blokova try-finally, gdje se u finally dijelu poziva
Dispose na svim objektima navedenim pod using. Slično ponašanje se u programskom jeziku Java može ostvariti
korištenjem try-with-resources.
76
Primjer Kodiranje \ Using
...
try {
Razred r1 = new Razred("A1");
Slika 27 prikazuje neke moguće ispise koji nastanu pokretanjem prethodnog programskog odsječka.
Postavljanjem reference r3 na null, na objekt s tekstom C3 više ne pokazuje ni jedna referenca i on je
objekt kojeg sakupljač smeća može obrisati. Međutim, iako je poziva sakupljača smeća forsiran, to još
uvijek nije jamstvo da će objekt biti obrisan, što se vidi na lijevoj slici. Nakon što je sakupljač pozvan,
očekivali bismo da je objekt C3 očišćen te da je nakon toga bačena iznimka poruke. Umjesto toga,
program izlazi iz using bloka i ide na obradu iznimke. Odmah pri napuštanju using-bloka, a prije
obrade iznimke automatski se poziva Dispose za D4 i B2. Nakon izlaska iz obrade iznimke program
11
Desni ispis dobiven je korištenjem .NET Frameworka 3.0, a lijevi u .NET Frameworku 4.0 u kojem sakupljač
smeća radi u pozadini, a ne na glavnoj niti.
77
završava i sakupljač smeća uništava sve objekte iz programa. Potrebno je uočiti da za A1 i C3 Dispose
nije pozvan.
Desna slika ilustrira situaciju u kojoj su čišćenje objekta C3 i Dispose za D4 i B2 obavljeni prije obrade
iznimke.
6.8 Zadaci
Zadatak 1. Obraditi iznimku kada se ostvari Debug.Assert
Zadatak 2. Implementirati razred Niz koji osim niza cijelih brojeva sadržava gornju i donju
granicu niza. Baciti iznimku ako je gornja granica manja od donje, te ako se preko indeksera
pristupa članu izvan gornje odnosno donje granice.
Zadatak 3. Implementirati razred Temperature koji prima razred Niz. Razred treba imati metodu
za računanje prosječne temperature. Ubaciti provjere da niz temperatura nije prazan prije
izračuna. Provjeriti i da je dobiveni prosjek unutar granica definirane gornje i donje
vrijednosti niza.
78
7 Grafičko korisničko sučelje
Forma (eng. form) je strukturirani prozor ilil okvir koji sadrži prezentacijske elemente za prikaz i unos
podataka. Svaka forma je ujedno i prozor (eng. window), ali se uobičajeno podrazumijeva da je forma
dijalog na kojem se nalazi određeni broj kontrola.
Razvojni .NET omogućava izradu grafičkog korisničkog sučelja (eng. Graphical User Interface – GUI) u
klijentskim (Windows) aplikacijama korištenjem skupa biblioteka WindowsForms te biblioteka
Windows Presentation Foundation (WPF). Iako je WPF zamišljen kao nasljednik WindowsFormsa i
omogućava naprednije mehanizme povezivanja i oblikovanja formi, ove dvije tehnologije još uvijek
paralelno žive te ćemo se unutar ovog predmeta zadržati se na tehnologiji WindowsForms. Izrada
WPF aplikacija zahtjeva ponešto kompliciraniju paradigmu i dizajn koji u primjerima koji će slijediti ne
donosi konkretnu dobit. Slično tehnologiji WindowsFoms postoji WebForms za izradu Web stranica
(obrađen u jednom od narednih poglavlja) koji se zaniva na slično principu kao WindowsForms.
7.1 WindowsForms
WindowsForms predstavlja skup baznih razreda za podršku prozorima i kontrolama sučelja. Svaka
forma nasljeđuje System.Windows.Forms iz istoimenog prostora imena. Hijerarhija razreda
WindowsForm pojednostavljeno se može prikazati kao na sljedećoj slici.
System.Object
System.MarshalByRefObject
System.ComponentModel.Component
System.Windows.Forms.Control
System.Windows.Forms.ScrollableControl
System.Windows.Forms.ContainerControl
System.Windows.Forms.Form
79
Uobičajeno je naziva ControlName_EventName12 s dva argumenta: objektom koji je izazvao događaj i
podacima vezanim uz događaj. Za svaki događaj može biti pridruženo više rukovatelja događaja, te će
oni biti redom pozivani nakon što se događaj ostvari.
Oblik postupka (povratne vrijednosti i argumenti) koji obrađuje neki događaj opisan je tipom
delegata i u prethodnom slučaju taj tip delegata je System.EventHandler13. Delegati nekog tipa
delegata su objekti koji ne sadrže podatke, već reference na jedan ili više postupaka (slično
pokazivaču na funkciju u C/C++ ili razredu Observable u Javi). Postupak se pridružuje delegatu
operatorom =, a operatorom += se dodaje u već postojeću listu postupaka pridruženih tom delegatu.
Operatorom -= neki postupak se uklanja iz liste pridruženih postupaka. Događaj je delegat kojem su
dozvoljene samo operacije += i -=. Više o delegatima i događajima objašnjeno je u primjeru s
vlastitom kontrolom u poglavlju 7.5.
U slučaju pridruživanja rukovatelja događajem nekom događaju u dizajnu forme stvara se programski
kod kao u gornjem primjeru. U slučaju da ipak sami moramo napisati takav kod može se upotrijebiti
kraći zapis navodeći samo ime metode ili navođenjem lambda izraza za obradu događaja.
this.button1.Click += this.button1_Click;
U nastavku je dan primjer dinamičkog kreiranja gumba na lokaciju gdje se dogodio klik miša na formi i
pridruživanje ispisa poruke svakom od tako kreiranih gumba.
12
Promjenom naziva kontrole, naziv rukovatelja događajem se neće promijeniti. Štoviše, moguće je da više
različitih kontrola ima isti rukovatelj događajem.
13
Pojam event handler treba razlikovati od razreda System.EventHandler.
80
Primjer GUI \ JednostavnaForma \ Form1.cs
Izuzmemo li mogućnost korištenja globalnih varijabli ili nekog zajedničkog spremišta, dvije su
mogućnosti za prijenos iz jedne forme u drugu. Jedna je promijeniti konstruktor pozvane forme tako
da prima sve potrebne argumente. Ovaj način se ne preporuča, jer može uzrokovati probleme u
dizajnu forme kroz radno okruženje14. Bolji način, a i uobičajen u ugrađenim dijalozima u .NET-u (npr.
kod OpenFileDialog i sl.) je kreiranje svojstava u pozvanoj formi koja služe kao omotač oko pripadnih
kontrola pozvane forme. U sljedećem primjeru u kojem forma FormaUnos poziva formu
FormaAdresa, Drzava, Mjesto i Ulica su takva svojstva.
14
Da bi se forma mogla dizajniti u Visual Studiu mora imati prazni konstruktor. Doda li se osim željenog
konstruktora i prazni konstruktor, upravo se otvorila mogućnost da netko pozove forme, a da joj ne prenese
sve potrebne parametre.
81
Primjer GUI \ PrijenosParametara \ FormaAdresa.cs
Nakon kreiranja objekta koji će predstavljati pozvanu formu, a prije samog trenutka poziva postupka
za prikaz (postupak ShowDialog) postavljaju se vrijednost svojstava čime se mijenja sadržaj kontrola
na formi koja će upravo biti prikazana. Nakon što se forma FormaAdresa zatvori, izvršavanje koda
forme FormaUnos će se nastaviti dohvatom vrijednosti svojstava Drzava, Mjesto i Ulica forme
FormaAdresa te će se dohvaćene vrijednosti postaviti kao vrijednosti pripadajućim kontrolama forme
FormaUnos.
Forma koju se pozove sa ShowDialog predstavlja dijalog i može se zatvoriti na nekoliko načina. U
većini slučajeva potrebno je ustanoviti razlog zatvaranje forme, primjerice je li korisnik odustao od
unosa ili je unio podatke i namjerava ih snimiti. Rezultat zatvaranja dijaloga sprema je rezultat poziva
postupka ShowDialog i jedna je od vrijednosti iz enumeracije DialogResult. U ovom primjeru gumbi
Spremi i Odustani na formi FormaAdresa imaju postavljena svojstva DialogResult na OK, odnosno
Cancel te je prilikom obrade akcije na tim gumbima dovoljno zatvoriti formu, a rezultat je već
postavljen.
Napomena: Zatvorena forma još uvijek čuva svoje podatke, ona nije obrisana iz memorije, već samo
više nije prikazana.
82
7.4 Provjera valjanosti unosa podataka
Provjerom (validacijom) se želi upozoriti na unos neispravnih podataka. Slika 31 prikazuje primjer
validacije prilikom unosa pri čemu ime i prezime moraju biti uneseni te ne smiju sadržavati brojeve, a
OIB mora biti niz brojeva duljine 11 znakova.
Validaciju je moguće obaviti u obradi događaja forme ili korištenjem naprednijih mehanizama
povezivanja podataka na kontrole u formi (postavljanje svojstva DataSource na objekt koji
implementira sučelje IDataErrorInfo što je objašnjeno u poglavlju 9.4). Prilikom napuštanja svake
kontrole čija je vrijednost svojstva CausesValidation istinita, podiže se događaj Validating (s
parametrima object sender, CancelEventArgs e). Obradom ovog događaja moguće je uobičajeno se
postavlja vrijednost svojstva e.Cancel. Postavljanjem vrijednosti false smatra se da je podatak
ispravan i omogućava se napuštanje kontrole. Postavljanjem e.Cancel = true blokira se napuštanje
kontrole u slučaju pogrešnog unosa ako svojstvo forme AutoValidate nije postavljeno na
EnableAllowFocusChange ili Disable.
Problem na kojem treba obratiti pažnju je da ako postoje neispravni podaci, nije moguće poduzeti
nikakvu akciju, to jest napustiti kontrolu s pogrešnim upisom sve dok se pogreška ne popravi pa čak
ni zatvoriti formu. Rješenje ovog problema je postaviti svojstvo Cancel na false u obradi događaja
zatvaranja forme (događaj FormClosing).
Osim napuštanjem pojedine kontrole, validacija svih kontrola na formi se može pokrenuti pozivanjem
postupka ValidateChildren što je svakako potrebno napraviti prije pohrane podataka u neko
spremište. Validacija prilikom napuštanja pojedine kontrole na razini svih kontrola može se isključiti
postavljanjem svojstva forme AutoValidate na false.
Komponenta ErrorProvider služi za uniformni prikaz poruka o pogrešnom unosu na način da se pored
neispravnog unosa pojavljuje ikona uskličnika dok unos nije valjan, a prelaskom preko ikone
pojavljuje se tekst poruke o pogrešci. Tekst poruke se postavlja postupkom SetError(Control, string)
čime se nekoj kontroli postavlja tekst pogreške i uzrokuje prikaz ikone za pogrešku (osim ako poslani
string nije prazni string).
83
Primjer GUI \ PrijenosParametara \ FormaUnos.cs
U primjeru koji slijedi prikazan je primjer „korisničke“ kontrole u kokoj su grupirani okvir za unos
teksta i tekst ispred okvira, što je tipično na raznim formama za unos. Kontrola je izdvojena u posebni
projekt tipa Class Library koji kao rezultat izgradnje daje datoteku s ekstenzijom dll.
Naziv koji će se pojaviti ispred okvira moguće je promijeniti korištenjem svojstva Labela koje vrši
dohvat i postavljanje teksta na odgovaraću labelu. Okvir za unos teksta će prilikom početka unosa
teksta promijeniti svoju boju u svijetlo plavu, a nakon unosa vratiti početnu boju, što je
implementirano obradom događa Enter na kontroli TextBox.
84
Primjer GUI \ VlastiteKontrole \ VlastitiTextBox
public class VlastitiTextBox : UserControl {
public string Labela {
get { return labelText.Text; }
set { labelText.Text = value; }
}
Dodatno, korisnička kontrola definirat će i neke vlastite događaje na koje će se korisnik kontrole moći
pretplatiti, što je u skladu s modelom izdavač-pretplatnik koji je već korišten za ugrađene kontrole.
Kontrola (ili bilo koji drugi razred, jer koncept nije vezan samo za grafičko sučelje) definira određene
događaje na koje se moguće pretplatiti. Pretplaćivanje vrši aplikacija nad konkretnim objektom i u
tom slučaju objekt je „izdavač“, a aplikacija „pretplatnik“.
Defiranje događaja počinje definiranjem tipa delegata kojim se opisuje prototip postupka koji
obrađuje željeni tip događaja. U ovom primjeru takav postupak će biti morati biti tipa void i primati
dva argumenta tipa object i EventArgs. Iako već slični tipovi delegata postoje (System.EventHandler ili
Action<object, EventArgs) definirat ćemo novi tip za ilustraciju kako se definira novi tip delegata.
Gore navedenom konstrukcijom interno se stvara novi razred TextBoxActivityHandler koji nasljeđuje
razred MultiCastDelegate. Nakon što je definiran tip delegata moguće je definirati članske varijable
tog tipa, npr.
85
public TextBoxActivityHandler TextBoxChanged;
nakon čega je na nekom objektu tipa VlastitiTextBox moguće napisati nešto nalik sljedećem:
vlastiti.TextBoxChanged = M1;
vlastiti.TextBoxChanged += M2;
vlastiti.TextBoxChanged += M3;
vlastiti.TextBoxChanged -= M2;
vlastiti.TextBoxChanged += M4;
pri čemu se su M1, M2, M3 i M4 postupci oblika void Mx(object sender, EventArgs e);
Prethodni kod bi uzrokovao da TextBoxChanged sadrži skup pridruženih postupaka pa se onda tako
definirana članska varijabla naziva delegat, jer sadrži popis postupaka koji će se slijedno pozivati
nakon što se na napiše TextBoxChanged()15. U gornjem primjeru to bi uzrokovalo pozive M1, M3 i
M4. Postupak M2 ne bi bio pozvan, jer je otkazana pretplata s -=. Nedostatak ovako definiranog
delegata je mogućnost da netko u kodu napiše =, umjesto += i ukloni prethodno pridružene postupke
iz delegata. U tu svrhu dodajemo ključnu riječ ispred tipa delegata te umjesto delegata definiramo
događaj. Time nastaje članska varijabla koja se zove događaj, što je delegat na kojem je samo
dopušteno += i -=, a ne više i operacija =.
U trenutku kad vlastita kontrola želi pobuditi (propagirati) neki događaj, odnosno obavijestiti
pretplatnike o promjeni stanja, provjerit će je li netko pretplaćen na događaj (obavlja se usporedbom
članske varijable za događaj s null) i ako nije pozvati redom pretplatničke postupke. U ovom primjeru
vlastita kontrola obrađuje događaj završetka unosa u tekstualnom okviru (obrada događaja Leave),
nakon čega podiže vlastiti događaj TextBoxChanged i izaziva pozive pretplaćenih postupaka.
15
Može se povući analogija s pokazivačom na funkciju u C-u koji bi mogao pokazivati na više funkcija umjesto
na samo jednu ili razredu Observable u Javi.
86
Primjer GUI \ VlastiteKontrole \ VlastitiTextBox
Vlastitu kontrolu može se dovući na neku formu iz alatne trake16 i koristiti kao i ugrađene kontrole.
Svojstva i događaji koje kontrola definira pojavit će se zajedno sa svim ostalim svojstvima i
događajima koje posjeduje razred UserControl. Stoga se može i obraditi vlastiti događaj kao u
sljedećem primjeru:
this.vlastitiTextBoxIme.TextBoxChanged += new
VlastiteKontrole.VlastitiTextBox.TextBoxActivityHandler
(this.vlastitiTextBox_Changed);
//ili samo vlastitiTextBoxIme.TextBoxChanged += vlastitiTextBox_Changed
...
private void vlastitiTextBox_Changed(object sender, EventArgs e) {
VlastitiTextBox t = (VlastitiTextBox)sender;
t.Tekst = t.Tekst.Substring(0, 1).ToUpper()
+ t.Tekst.Substring(1).ToLower();
}
16
Prethodno je potrebno dodati referencu na projekt s vlastitom kontrolom (desni klik na projekt → Add
reference - Project – VlastiteKontrole) ili dodati eksplicitno na alatnu traku s Desni klik na Toolbox Choose
Items Browse... VlastiteKontrole.dll
Ili, desni klik na projekt – Add reference - Project - VlastiteKontrole
87
U jeziku C# višenitnost je moguće ostvariti putem više mehanizama koji su nastajali u različitim
verzijama .NET Frameworka. Ti mehanizmi su:
Asinkrono pozivanje postupaka: Svaki delegat ima mogućnost asinkronog poziva
(BeginInvoke, EndInvoke)
Kontrola BackgroundWorker
Stavljanje postupka u postojeći red niti (razred ThreadPool)
Stvaranje nove niti pomoću razreda Thread
Korištenjem biblioteke TPL (Task Parallel Library) stvaranjem jednog ili više zadataka (razred
Task), paralelnim izvršavanjem dijelova kod (razred Parallel) ili korištenjem paralelnih LINQ
upita (PLINQ)
Korištenje asinkronih verzija postupaka ako takvi postoje za određenu namjenu i korištenje
ključnih riječi async i await.
Napredniji mehanizmi poput TPL-a te async i await osiguravaju jednostavniji način pisanja u odnosu
na kod koji bi direktno koristio razred Thread i njegove sinkronizacijske mehanizme.
Primjer koji slijedi ilustrira stvaranje pozadinskog zadatka korištenjem razreda Task uz korištenje
async i await.
namespace RacunanjePI {
public delegate
void ShowProgressDelegate(string pi, int totalDigits, int digitsSoFar);
}
Postupak koji će se moći pretplatiti na događaj kojeg će naš kalkulator podizati morat će biti takav da
je tipa void i da prima tri parametra: trenutnu vrijednost broja π prikazanog u stringu, ukupni broj
znamenki i dosad izračunati broj znamenki. Nužnost prototipa osigurana je definiranjem tipa
88
delegata ShowProgressDelegate i definiranjem da je događaj ProgressChanged tipa
ShowProgressDelegate. Prilikom podizanja događaja potrebno je provjeriti je li događaju pridružen
koji pretplatnik na način da se provjeri da li je događaj null ili ne.
Ako se prilikom klika na gumb forme izračun pokrene u istoj niti (prethodno obavivši pretplatu na
događaj koju PiCalculator nudi) forma neće reagirati na pomak ni na druge događaje dok se postupak
izračuna ne završi.
string pi = piCalculator.CalcPi(digitsToCalc);
89
7.6.2 Stvaranje zadatka u pozadini
Za definiranje zadatka u pozadini koriste se razredi Task ili Task<TResult> ovisno o tome je li
potrebno vratiti vrijednost tipa TResult ili ne. Konstruktor razreda Task očekuje delegat tipa Action ili
Action<object>.
Tip delegata Action, odnosno Action<object> propisuje da će konkretni delegat imati vezu na void
postupak bez argumenata ili s jednim argumentom tipa object. Konstruktor razreda Task<TResult>
očekuje delegat tipa Func<TResult> ili Func<object, TResult>.
Tip delegata Func<TResult>, odnosno Func<object, TResult> propisuje da će konkretni delegat imati
vezu na postupak bez argumenata ili s jednim argumentom tipa object koji vraća objekt tipa TResult.
Ostali (opcionalni) parametri konstruktora uključuju argument koji se prosljeđuje postupku te razred
za signalizaciju otkazivanja zadatka. Umjesto eksplicitno definiranih delegata uobičajeno je koristiti
lambda izraze - neimenovane funkcije koje mogu biti predane kao argument ili vraćene kao rezultat.
Nakon stvaranja objekta tipa Task ili Task<TResult> pozadinski zadatak može se pokreniti s
postupkom Start. Alternativno, isto se može napraviti odmah pri definiranju zadatka ako se koristi
Task.Run.
Uobičajeno je postupke koji su asinkroni označiti sufiksom Async, ali nije nužno. Poziv gore
navedenog postupka izazvat će izvršavanje novog zadatka u pozadini, a pozivatelju će se vratiti
referenca na objekt tipa Task<string>.
17
Interno, kompajler će generirati kôd potreban za traženu izvedbu.
90
dovršen, ali se istovremeno omogućava formi da reagira na druge događaje. Povratna vrijednost
poziva await + zadatak tipa Task<TResult> je tip TResult.
Postupak u kojem se koristi await mora se označiti s async. Rukovatelji događaj mogu se označiti s
async, odnosno moraju ako se unutra koristi await.
Postupak označen s async može imati povratnu vrijednot Task, Task<TResult> ili void i ne može imati
ref i out parametre (ali može pozvati postupke koji imaju out i ref). Vrijednost iz postupka oblika async
Task<TResult> je tipa TResult, to jest naredba return vraća neki TResult. Primjer alternativnog
rješenja bi bio async postupak koji čeka zadatak u pozadini. Prethodni kod se takvom promjenom ne
mijenja.
91
pozivatelju da li je nalazi na nekoj drugoj niti. U slučaju da jest, onda je potrebno isti postupak pozvati
korištenjem postupka BeginInvoke. 18 Postupak BeginInvoke prima delegat i proizvoljan broj objekata
koji će biti predani kao parametri postupku pridruženom navednom delegatu. Tip delegata mora biti
takav da se podudara argumentima postupka kojeg se želi pozvati na glavnoj niti.
Napomena: u primjeru se umjesto vlastitog tipa delegata mogao koristiti i delegat tipa Action<string,
int, int>.
7.7 Zadaci
Zadatak 1. Napraviti formu za uređivanje slike. Ugraditi mogućnosti mijenjanja boje, svjetline,
itd. (vrijednosti su mijenjaju uz pomoć NumericUpDown kontrole). Omogućiti spremanje
promijenjene slike.
Zadatak 2. Napraviti formu za pogađanje države čija je zastava prikazana ( GUI \Dodatak \
Zastave).
Zadatak 3. Napraviti formu za prikaz vješala za igru Vješala. Unaprijed pripremljen niz slika
prikazati u ImageList. Slike su pohranjene u binarnom formatu u Form1.resx. Klikom
na gumb Prikaži dodaje se sljedeća slika. Klikom na gumb Dodaj se može dodati nova
slika. ( GUI \Dodatak \ Vjesala)
Zadatak 4. U sljedećoj liniji koda, što predstavlja
a) naredba this.button1.Click, što System.EventHandler
b) a što this.Spremi? this.button1.Click += new
System.EventHandler(this.Spremi);
18
Sličan koncept se koristi i npr. u Javi gdje se koristi SwingUtilities.invokeAndWait koji stavlja predani postupak
u red čekanja za izvršavanje na grafičkoj niti
92
8 Aplikacija nad bazom podataka
Partner Dokument
PK IdPartnera PK IdDokumenta
Artikl
TipPartnera VrDokumenta
BrDokumenta PK SifArtikla
OIB
FK1,I1 IdMjestaPartnera DatDokumenta
FK2,I4,I2 IdPartnera U1 NazArtikla
AdrPartnera
FK1,I1,I3 IdPrethDokumenta JedMjere
FK2,I2 IdMjestaIsporuke
PostoPorez CijArtikla
AdrIsporuke
IznosDokumenta ZastUsluga
SlikaArtikla
Stavka
PK IdStavke
Tvrtka Osoba
FK2,I3,I2 IdDokumenta
FK1,I1 SifArtikla
PrezimeOsobe KolArtikla
U1 MatBrTvrtke
ImeOsobe JedCijArtikla
I2 NazivTvrtke
PostoRabat
93
ADO.NET podržava unificirani pristup različitim tipovima spremišta podataka: strukturiranim i
nehijerarhijskim podacima (CSV datoteke, Microsoft Excel tablice, …), hijerarhijskim podacima (XML)
te relacijskim bazama podataka (MS SQL Server, Oracle, MS Acess, PostgreSQL, …).
Od verzije .NET Framework 3.5. podržan je mehanizam Entity Framework (EF) za objektno-relacijsko
preslikavanje izgrađen nad ADO.NETom. Naknadno je EF izdvojen kao paket otvorenog koda
dostupan kroz alat za distribuciju programskih paketa NuGet.
Opskrbljivači podataka
Postoje dvije osnovne kategorije davatelja podataka prilagođene različitim tehnologijama i smještene
u odgovarajuće prostore imena: System.Data.SQLClient optimiziran za rad s MS SQL Serverom te
System.Data.OleDb za davatelje za rad s bilo kojim OLE DB izvorom podataka (Object Linking and
Embedding Database je Microsoftov API za uniformni pristup izvorima podataka). Nazivi razreda u
ovim prostorima imenima imaju slične nazive (npr. SqlCommand i OleDbCommand, SqlConnection i
OleDbConnection, SqlDataReader i OleDbDataReader, …) i implementiraju zajednička sučelja i/ili
zajedničke apstrakne razrede čime se postiže neovisnost aplikacije o fizičkom smještaju podataka.
Ključni pojmovi u davatelju podataka su:
94
Odnosi među elementima prikazani su na sljedećoj slici.
95
System.Data.IDbConnection i apstraktnog razreda System.Data.DbConnection. Konkretne
implementacije ovih sučelja i razreda su npr. OleDbConnection, SqlConnection i druge.
Važniji postupci priključka su Open i Close za prikapčanje odnosno otkapčanje s izvora podataka, a
važnija svojstva su:
ConnectionString: jedino promenjivo svojstvo tipa string i predstavlja postavke za spajanje na
izvor podataka. Sastoji se od parova postavki oblika naziv=vrijednost međusobno odvojenih
točka-zarezom
State: oznaka stanja priključka s jednom od vrijednosti iz enumeracije ConnectionState
{ Broken, Closed, Connecting, Executing, Fetching, Open}
Data Source: predstavlja naziv samostojne baze podatke ili drugog izvora podataka (npr. MS
Access, Excel, …), naziv ili mrežnu adresu poslužitelja i ime njegove instance (npr.
rppp.fer.hr\SQL2014 ili 31.147.204.102\SQL2014). Za poslužitelja na lokalnom računalu može
se koristiti naziv local ili „.“ (primjerice .\SQL2014)
AttachDBFilename: koristi se kada se želi pristupiti bazi podataka koja nije registrirana u
SUBP (npr. jednokorisnički .MDF koji nije vezan na SQL Server).
Initial Catalog / Databse: Naziv željene baze podataka na poslužitelju s više baza podataka
ConnectTimeout: označava vrijeme čekanja do otvaranja ili bacanja iznimke po isteku
vremena
User ID / UID: korisničko ime u bazi podataka
Password / PWD: lozinka za korisničko ime
Integrated Security: Postavlja se na false (pretpostavljena vrijednost ako nije navedeno), true
ili SSPI (Security Service Provider Interface – standardizirano sučelje za sigurnost
distribuiranih aplikacija). Kada se postavi na true ili SSPI, .NET se povezuje koristeći sustav
zaštite OS Windows kao alternativa pristupu s korisničkim imenom i lozinkom.
Persist Security Info: true ili false (pretpostavljena vrijednost). Kad je postavljen na false,
sigurnosno osjetljive postavke (npr. lozinka) se automatski uklanjaju iz ConnectionStringa
nakon što je priključak otvoren.
ConnectioonString se može ručno navesti, a može se i složiti korištenjem razreda
SqlConnectionStringBuilder. Slijedi nekoliko primjera postavki priključaka na bazu prikazanih u
primjeru ADO\Upitnik dok se opširiniji skup primjera može se pronaći na
https://www.connectionstrings.com.
96
Postavke priključka ne bi trebalo pisati unutar programskog koda iz sigurnosnih (prikaz traga stoga
može otkriti podatke o priključku) i praktičnih razloga, jer bi promjena postavki bi zahtijevala
ponovnu izgradnju programa (i eventualnu novu verziju programa ako se radi automatsko
verzioniranje). Stoga se postavke evidentiraju u konfiguracijskoj datoteci (app.config odnosno
web.config za web aplikacije) pod stavkom connectionStrings.
<configuration>
<connectionStrings>
<add name="Firma"
connectionString="Data Source=rppp.fer.hr\SQL2012,3000;
Initial Catalog=Firma; User Id=rppp;Password=šifra;"/>
</connectionStrings>
</configuration>
Primjer ADO\UsingDataReader\PopisArtikala
U primjeru se definiraju postavke priključka na bazu podataka, priprema se naredba koja će se izvršiti
na tom priključku te se priključak otvara i izvršava se upit s ExecuteReader na takvoj naredbi. Rezultat
upita je SqlDataReader koji služi za slijedno čitanje rezultata.
Za prijelaz na prvi redak u rezultatu, a zatim na svaki sljedeći koristi se postupak Read sve dok ne vrati
false što označava da se čitanjem došlo do kraja. Vrijednost pojedinog atributa (stupca) u retku
rezultata može se dohvatiti korištenjem rednog broja stupca ili, kao u primjeru, navođenjem naziva
stupca.
97
8.3.3 Zatvaranje priključka
Svaku otvorenu vezu prema bazi podataka treba zatvoriti! U slučaju da se u primjeru iz poglavlja 8.3.2
dogodila conn.Close() se ne bi izvršio te veza ostaje otvorena i ne može se ponovo iskoristiti. Budući
da sustav za upravljanje bazom podataka uobičajeno ima ograničen broj mogućih otvorenih veza to
znači da bi nakon nekog vremena bilo nemoguće više se spojiti na bazu podataka do ponovnog
pokretanja aplikacije. Jedno od rješenja je staviti naredbu za zatvaranje veze unutar finally bloka
(primjer ADO \ UsingDataReader \ PopisArtikalaTryCatch). Bolje rješenje je koristiti činjenicu da
priključak na bazu implementira sučelje IDisposable pri čemu je Dispose u ovom slučaju ekvivalentan
postupku Close, pa se može koristit using blok
Napomena: rješenje s using nije uvijek moguće, primjerice ako će povezivanje/čitanje podataka
naknadno nastupiti. U tom slučaju se koristi koncept po kojem se vrši automatsko zatvaranje
priključka kad se zatvori čitač, što se inicira prilikom dohvata čitača s:
command.ExecuteReader(System.Data.CommandBehavior.CloseConnection).
Ovaj i drugi primjeri (npr. parametrizirani upiti, upiti s više kompleta rezultata, pozivi pohranjenih
procedura) dostupni su u riznici programskog koda na poslužitelju predmeta.
98
Postupak lokalne obrade podataka na poslužitelju pojednostavljeno se može opisati sljedećim
koracima:
1. Otvori priključak DataSet
2. Napuni DataSet
3. Zatvori priključak
DataAdapter
4. Obradi DataSet
5. Otvori priključak
6. Ažuriraj izvor podataka
Connection
7. Zatvori priključak
99
edmx je xml datoteka s nekoliko sekcija koje sadrže opis modela (csdl), opis fizičkog modela (ssdl),
preslikavanja (c-s mapping) i postavke grafičkog prikaza. Grafički prikazano, stvoreni objektni model
izgleda kao na sljedećoj slici.
Na modelu koji je inciijalno stvoren, potrebno je napraviti nekoliko preinaka kako bi izbjegle
višeznačnosti u kôdu zbog neodređenih veza i bolje oblikovao objektni model. Mjesto i Mjesto1 su
paralelne veze, pa postoji neodređenost u nazivu jer se može sa sigurnošću reći koje je koje, pa je
potrebno promijeniti nazive asocijacija iz Mjesto u MjestoIsporuke i Mjesto1 u MjestoSjedista. Zbog
jednostavnosti u primjerima koji slijedi mjenjaju se naziva asocijacija u entitetu Dokument iz
Dokument2 u PrethodniDokument i Stavka u Stavke, odnosno u entitetu Drzava iz Mjesto u Mjesta.
Također, potrebno je označiti da se prilikom brisanja dokumenta automatski brišu i njegove stavke
(Cascade na poveznici između entiteta Dokument i Stavka).
Dodatno, potrebno je izvršiti podešavanje specijalizacije, pa entitet Partner treba označiti kao
apstraktni razred da ga se ne može nezavisno instancirati. Osoba i Tvrtka nasljeđuju Partnera, pa je
potrebno izbrisati veze Partner-Osoba i Partner-Tvrtka. Svojstvo BaseType tim entitetima se postavlja
na Partner i brišu se svojstva IdOsobe iz Osobe i IdTvrke iz Tvrtke.
100
Slika 42. Primjer podešavanja specijalizacije na primjeru Partner, Osoba, Tvrtka
Desnim klikom na pojedini entitet i odabirom opcije Table Mapping još potrebno je podesiti između
IdTvrtke i IdPartnera, odnosno između IdOsobe i IdPartnera.
Slika 43. Podešavanje preslikavanja kod naslijeđenih entiteta na primjeru Tvrtka → Partner
Nakon promjena, ciljani ogledni model korišten u primjerima koji slijede izgleda kao na sljedećoj slici.
101
Slika 44. Ciljani ogledni EF model
19
Parcijalni razred može se nalaziti u više datoteka u različitim fizičkim mapama, ali je bitno da se u svim
datotekama koristi isti prostor imena i isti naziv razreda.
102
Set i Set<T> - vraćaju DbSet za konkretni tip entiteta, a koristi se ako se želi napisati općeniti
postupak (inače je svaki entitet već sadržan u kontekstu kao svojstvo)
Entry i Entry<T> - služi za dohvat informacije o nekom entitetu u kontekstu i promjenu
njegovog stanja (npr. otkazivanje promjena).
Važnija svojstva i postupci razreda DbSet<T> su:
20
Ključ može biti kompozitni jer Find ima varijabilni broj argumenata, ali se načelno ne preporuča ako će se
entitet koristiti u padajućim listama.
21
Traženje zapisa može se obaviti i korištenjem postupka Where i lambda izraza.
103
Primjer ADO\EF_Firma\MainForm.cs - dodajPromijeniObrisiToolStripMenuItem_Click
104
ObjectResult<T> gdje je T oblika NazivProcedure_Result.22 Rezultat implementira sučelje
IEnumerable<T> pa se može se koristiti unutar foreach petlje, ali bez vraćanja unatrag i ponavljanja.
Primjer poziva pohranjene procedure dan je u sljedećem programskom odsječku. Povratni parametri
se dohvaćaju korištenjem razreda ObjectParameter, a parametri koji su isključivo ulazni mogu se
predati navođenjem vrijednosti.
8.6 Zadaci
Zadatak 1. Kako izgleda priključak na bazu podataka (connection string) ako je instanca SQL
Servera s nazivom SQLEXPRESS instalirana na računalu rppp.fer.hr i želimo se spojiti
na bazu podataka Firma s korisničkim imenom rppp20 i lozinkom test?
Zadatak 2. Koja naredba nad naredbom SqlCommand vraća skup vrijsdnosti, koja samo jednu
vrijednost, a koja ne vraća vrijednost?
Zadatak 3. Što reprezentira sučelje IDbCommand?
Zadatak 4. Poopćiti primjer PopisArtikala korištenjem IDbCommand sučelja.
22
Dozvoljeno je da više procedura koristi isti tip kao povratnu vrijednost što se može podesiti u
postavka procedure (desni klik na modelu \ Model Browser \ Function Imports). Primjerice, npr. tip
procedure ap_ArtikliSkupljiOd postavljen je na Artikl, umjesto generiranog
ap_ArtikliSkupljiOd_Result.
105
9 Povezivanje podataka i složene zaslonske maske
Izvor podataka može biti bilo koji objekt s javnim svojstvima, niz podataka, kolekcija koja
implementira sučelje IList ili složeniji tip podataka (npr. DataSet, DataTable).
Razred CurrencyManager se koristi prilikom povezivanja s kolekcijom objekata na izvoru te vodi
evidenciju o trenutnoj poziciji unutar izvora podataka, pri čemu izvor ne zna koji se element trenutno
prikazuje. Za svaki izvor podataka postoji zasebna instanca razreda CurrencyManager, a za više
kontrola iste forme koje se povezuju na isti izvor kreira se samo jedna instanca razreda
CurrencyManager.
106
Slika 46. Jedna instanca CurrencyManager kontrolira više povezivanja istog zapisa
107
Slika 47. Postavljanje povezivanja u dizajnu
Za tip podatka u dizajnu može se odabrati neki od već prethodno dodanih tipova podataka ili se može
dodati novi tip u listu kroz niz koraka (naredna slika).
Svojstva:
o AllowEdit, AllowNew, AllowRemove – indikatori da li je postupak moguć
o DataSource – skup podataka
o DataMember – tablica skupa koja se povezuje
o Count – broj elemenata u listi podataka
108
o Current - aktualni element izvora (povratna vrijednost tipa object)
o Position - indeks aktualnog elementa
Događaji
o CurrentChanged – promjena Current
o ItemChanged – ažuriran aktualni element List
o PositionChanged – promjena Position
Postupci
o AddNew – dodavanje novog elementa na izvor
o CancelEdit – opoziv uređivanja koje je u tijeku
o EndEdit - dovršetak uređivanja koje je u tijeku, pohrana na izvoru
o Remove, RemoveAt(int index) – brisanje elementa s izvora
o MoveFirst, MoveLast, MoveNext, MovePrevious – navigacija
o ResetBindings, ResetCurrentItem – ručno osvježavanje podataka. Potrebni su ako ne
postoji mogućnost automatskog osvježavanja grafičkog sučelja uslijed promjena
vrijednosti kroz programski kod.
namespace Binding {
public class Podatak
{
public string Prvi { get; set; }
public string Drugi { get; set; }
}
}
Na formi primjera dodane su 3 tablice, kontrole mreže s podacima (o kontroli GridView detaljnije u
jednom od narednih poglavlja) povezane na kolekcije Podataka ili NaprednihPodataka te nekoliko
tekstualni okvira (TextBox) za prikaz vrijednosti svojstava Prvi, Drugi, A i B pojedinačnog, trenutno
aktivnog podatka.
Povezivanje podataka ostvareno je sljedećim koracima
1. Na formu su iz alatne trake dovučene tri kontrole tipa BindingSource s nazivima
podatakBindingSource1, podatakaBindingSource2 i napredniPodatakBindingSource
2. Kontrolama je za vrijednost svojstva DataSource postavljeno redom Binding.Podatak,
Binding.Podatak i Binding.NapredniPodatak
3. Na formu su stavljene tri kontrole tipa GridView i četiri kontrole tipa TextBox (uz
odgovarajuće labele)
4. Kontrolama tipa GridView redom su postavljeni izvori podataka (svojstvo DataSource) na
podatakBindingSource1, podatakaBindingSource2 i napredniPodatakBindingSource
109
5. Kontrolama tipa TextBox povezivanje je postavljeno kao na Slika 50 postavljanjem željenog
izvora i svojstva za svojstvo (DataBindings)\Text.
Slika 49. Forma s različitim mogućnostima osvježavanja ovisno o tipu povezanog podatka
110
Primjer Binding – Form1
podatakBindingSource1.DataSource = list;
podatakBindingSource2.DataSource = bindingList;
napredniPodatakBindingSource.DataSource = napredniBindingList;
Nakon pokretanja forme klikom na pojedini podatak u tablici automatski se ažurira sadržaj tekstovnih
okvira, jer BindingSource ima funkcionalnost i CurrencyManagera i PropertyManagera (poglavlje 9.1).
111
Slika 51. Ponašanje forme prilikom dodavanja podatka direktno na izvorne liste
Sličan efekt može se primijetiti pokuša li se promijeniti lista postavljanjem nekog drugog elementa
umjesto prvog u listi npr. izvršavanjem sljedećeg koda:
Ponašanje forme prikazano je na Slika 52. Promjene su propagirane samo u slučaju kad se koristio
BindingList. Razlog tog ponašanja je što BindingList implementira sučelje IBindingList u kojem je
definiran događaj ListChanged kojim se svim pretplaćenima (u ovom primjeru kontrole GridView su
automatski pretplaćene) šalje obavijest o promjeni liste.
112
Slika 52. Ponašanje forme prilikom promjene sadržaja liste
Kako bi se aktualni sadržaj prikazao na formi pri korištenju kolekcije koja ne podiže događa
ListChanged potrebno je eksplicitno pozvati osvježavanje svih podataka ili trenutno prikazanog
podatka (ResetBindings ili ResetCurrentItem).
113
private void btnOsvjezi_Click(object sender, EventArgs e)
{
podatakBindingSource1.ResetBindings(false);
podatakBindingSource2.ResetBindings(false);
napredniPodatakBindingSource.ResetBindings(false);
}
podatakBindingSource1.Add(p);
podatakBindingSource2.Add(p);
novi podatak bi bio odmah vidljiv na ekranu i automatski bi izvor podataka (povezane liste) bio
ažuriran da sadrži novi podatak.
114
Primjer Binding – NapredniPodatak
private string a;
private string b;
public string A {
get { return a; }
set {
a = value;
if (PropertyChanged != null){
PropertyChanged(this, new PropertyChangedEventArgs("A"));
}
}
}
...
Izvor podataka je postavljen na tip EF_Firma.Artikl dok je za tekstualni okvir povezano svojstvo Text
sa šifrom artikla. Dohvat podataka se vrši učitavanjem svih artikala, nakon čega oni bivaju pohranjeni
u kontekst, a zatim se vrši povezivanje na tako učitani kontekst pretvoren u BindingList.
Primjer ADO\EF_Firma\Artikl
// pripremimo upit
var query = context.Artikl;
await query.LoadAsync(); //dovučemo podatke u kontekst
// prilagodimo podatke
BindingList<Artikl> artikli = context.Artikl.Local.ToBindingList();
// povežemo podatke
artiklBindingSource.DataSource = artikli;
Primjer ADO\EF_Firma\Artikl
textBoxJedMjere.DataBindings.Add("Text", artiklBindingSource,
"JedMjere", true);
textBoxCijArtikla.DataBindings.Add("Text", artiklBindingSource,
"CijArtikla", true);
checkBoxUsluga.DataBindings.Add("Checked", artiklBindingSource,
"ZastUsluga",true);
pictureBoxArtikl.DataBindings.Add("Image", artiklBindingSource,
"SlikaArtikla", true,
System.Windows.Forms.DataSourceUpdateMode.Never);
Složeno povezivanje je povezivanje kontrole koja prikazuje više podataka (npr. tablica, padajuća
lista, …). Osim postavljanja vrijednosti za DataSource ponekad je potrebno postaviti i vrijednosti
svojstava DataMember (ako izvor podataka ima više tablica ili podskupova, pa se ovim svojstvom bira
željena tablica ili podskup) te svojstava DisplayMember i ValueMember ako se radi o kontrolama kod
116
kojih se prikazani tekst treba razlikovati od vrijednosti (primarnog ključa) elementa. Takav primjer su
padajuće liste za odabir vrijednosti stranog ključa ili liste koje pokazuju opise podataka, a za
označavanje je potrebno koristiti neko drugo svojstvo.
Primjer ADO\EF_Firma\ArtiklForm
//u dizajnu...
listBoxArtikli.DataSource = artiklBindingSource;
listBoxArtikli.DisplayMember = "NazArtikla";
117
Primjer postupaka koji manipuliraju podacima, kao što je pomicanje na naredni zapis liste:
Primjer ADO\EF_Firma\ArtiklForm
Aktualizacijom drugog zapisa mijenja se indeks oznake u kontroli prikaza. Stoga u odgovajućem
događaju kotrole pozivamo funkciju koja osvježava informaciju o broju zapisa i statusu označenog
podatka.
private void listBoxArtikli_SelectedIndexChanged(…){
UpdateDisplay();
}
private void UpdateDisplay(){
//ažuriranje statusa na ekranu
if (listBoxArtikli.SelectedIndex != -1 && artiklBindingSource != null){
labelPosition.Text =
((artiklBindingSource.Position + 1).ToString() +
" od " + artiklBindingSource.Count.ToString());
Artikl artikl = (Artikl)artiklBindingSource.Current;
labelRowState.Text = context.Entry<Artikl>(artikl).State.ToString();
}
}
Primjer ADO\EF_Firma\ArtiklForm
Uređivanje zapisa provodi se promjenom sadržaja vezanih kontrola, a podaci se automatski spremaju
u memoriju klikom na neku drugu kontrolu, prelaskom na neki drugi zapis ili pozivom EndEdit() na
izvoru podataka. Kontekst preko kojeg su podaci dohvaćeni vodi evidenciju o promjenama , pa će
tako u primjeru s artiklima izmjenom trenutnog artikla status tog artikla biti Modified, a za nove
artikle će biti Added.
Artikl artikl = (Artikl)artiklBindingSource.Current;
118
Vrijednost context.Entry<Artikl>(artikl).State je Modified ako je redak bio promijenjen.
Trenutni zapis može se obrisati pozivom postupka RemoveCurrent , npr.
artiklBindingSource.RemoveCurrent();
pri čemu se taj element unutar konteksta označava za brisanje (status Deleted).
Za snimanje promjena je potrebno pozvati postupak SaveChanges ili SaveChangesAsync na
kontekstu. Navedenim postupcima snimaju se sve promjene unutar transakcije.
Sve elemente iz konteksta za koje se vodi evidencija o promjenama moguće je dobiti pozivom
postupka context.ChangeTracker.Entries() na konkretnom kontekstu nakon čega treba pronaći
promijenjene, obisane i nove (dodane) zapise. Na primjer,
foreach (var entry in context.ChangeTracker.Entries()) {
if (entry.State == EntityState.Added) {
entry.State = EntityState.Detached;
}
else if (entry.State == EntityState.Deleted ||
entry.State == EntityState.Modified) {
entry.State = EntityState.Unchanged;
}
119
Primjer ADO\EF_Firma\ArtiklForm
U situacijama u kojima se koristi povezivanje podataka na forme bolji i praktičniji način je korištenje
sučelja IDataErrorInfo. Sučelje sadrži
Svojstvo Error – vraća opis pogreške cijelog objekta (vratiti prazan string ako nema
pogreške)
Indekser (Item) – za string koji predstavlja naziv svojstva vratiti opis pogreške za konkretno
svojstvo objekta (vratiti prazan string ako nema pogreške)
Za objekte iz EF modela implementiranje ovog sučelja potrebno je obaviti u zasebnoj datoteci (što je
moguće s obzirom da su generirani razredi parcijalni).
Primjer ADO\EF_Firma\Partial\Artikl.cs
Na kontroli ErrorProvider potrebno je postaviti svojstvo DataSource na izvor koji implementira sučelje
IDataErrorInfo. Kontrola ErrorProvider će automatski pozivati indekser predajući naziv svojstva
povezanog s određenom kontrolom. Za vrijeme rada s formom ErrorProvider će prikazavati pogreške,
ali ne sprječava unos neispravnog podatka. Stoga je prije snimanja potrebno provjeriti postoji li
pogreška na povezanom objektu.
error = ((IDataErrorInfo)artiklBindingSource.Current).Error;
120
9.5 Kontrola DataGridView
Kontrola DataGridView služi za mrežnu (tabličnu) obradu podataka s različitih vrsta izvora. Izvori
mogu biti razne liste (sučelje IList), EF modeli, skupovi podataka (DataSet, DataTable), kontrola
BindingSource, i drugi. Izvor podataka se postavlja u svojstvu DataSource, a ako se radi o složenom
izvoru podataka (koji ima i ugnježđene kolekcije koje mogu biti izvori podataka) za odabir konkretnog
izvora podataka u složenom izvoru koristiti se svojstvo DataMember (vidi primjer s dokumentima i
stavkama u poglavlju 9.7.4).
Uobičajeni način korištenja kontrole DataGridView je takav da se iz alatne trake na formu dodaju
kontrola DataGridView i kontrola BindingSource nakon čega slijedi podešavanja kontrole
BindingSource odabirom tipa podatka koji će služiti kao izvor podataka.
Slika 56. Odabit tipa podatka koji će služiti kao izvor podataka
U slučaju da među postojećim izvorima podataka u projektu nema željenog razreda (primjerice, ako
ga prvi put koristimo u projektu), onda je potrebno odabrati opciju Add Project Data Source i prvo
odabrati vrstu izvora. Za vrstu izvora se može postaviti nekoliko tipova izvora, ali u konkretnom
primjeru bit će odabran tip Object, nakon čega slijedi odabir konkretnog tipa podatka koji će biti u
izvoru podataka.
121
Slika 57. Odabir vrste izvora i konkretnog tipa podatka
Prethodnim koracima definirana je vrsta izvora podatka i podešeni su stupci u kontroli DataGridView.
Konkretni podaci se pridružuju izvoru podataka (kontroli tipa BindingSource) prilikom učitavanja
forme. Ako je moguće, poželjno je koristiti async i await da se ne blokira glavnu nit. Podaci se
željenim upitom učitaju u trenutni kontekst Entity Frameworka, a zatim se tako lokalno pohranjeni
podaci pretvore u BindingList i postave kao izvor podataka.
23
Napomena: Postupak se može skratiti tako da se kod odabira izvora za DataGridView odmah ide na Add
Project Data Source što automatski doda novi BindingSource.
122
9.6 Kontrola BindingNavigator
Kontrola BindingNavigator je komponenta grafičkog sučelja za navigaciju i rukovanje povezanim
podacima koja je pozicionirana na vrhu kontrole i nudi već unaprijed gotovu funkcionalnost
navigacije podacima u povezanom izvoru podataka.
Izvor podataka se postavlja u svojstvu BindingSource. Na kontrolu je moguće dodati vlastite gumbe,
ukloniti postojeće i definirati obrade događaja za svaki gumb. Funkcionalnost ugrađenih gumba
ostvaruje se time što kontrola BindingNavigator incijalno ima već postavljena svojstva MoveFirstItem,
MoveLastItem, MoveNextItem, MovePreviousItem, PositionItem, AddNewItem i DeleteItem na
ugrađene gumbe što je po potrebi moguće promijeniti.
123
veze nije pogodan za povezivanje detalja. U konstruktoru razreda Dokument (Firma.edmx -> Firma.tt
-> Dokument.cs) treba promijeniti naredbu this.Stavke = new HashSet<Stavka>(); u
this.Stavke = new BindingList<Stavka>(); te public virtual
ICollection<Stavka> Stavke { get; set; } promijeniti u public virtual
BindingList<Stavka> Stavke { get; set; }.
124
Slika 62. Pridruživanje izvora podataka padajućoj listi
Padajućoj listi se kao izvor podataka pridružuje tako definirana kontrola BindingSource (u primjeru sa
slike kontrola ima naziv partnerBindingSource) te se odabire svojstvo za prikaz (postavlja se pod
DisplayMember), za vrijednost (ValueMember) te svojstvo koje predstavlja naziv stranog ključa
(SelectedValue). U primjeru sa slike vrijednosti ovih svojstva su>
Na sličan način realizirana je i padajuća lista za odabir prethodnog dokumenta. Potrebno je dodati
novi izvor podataka, jer kad bi se koristiti isti izvor kao za osnovne podatke izbor bi bio ograničen
samo na trenutno dohvaćene i povezane podatke.
125
Za odabir prethodnog dokumenta vrijednosti svojstava padajuće liste su:
U konkretnom primjeru za izvor podataka u zaglavlju se koristi kontrola tipa BindingSource imena
dokumentBindingSource koja za tip podatka ima postavljen Dokument iz EF modela, a za stavke se
koristi novi izvor podataka čiji tip podatka nije Stavka iz EF modela, već dokumentBindingSource koji
je složeni izvor podataka (tip podatka Dokument) koji u sebi sadrži kolekciju Stavke (vidi poglavlje
9.7.1).
126
Slika 65. Postavljanje padajuće liste za odabir artikla u stavkama
Specifičnost funkcioniranja DataGridViewa kod dodavanja stavke uzrokuje stvaranje stavke s praznim
(null), odnosno pretpostavljenim vrijednostima. Problem nastaje kad referentna vrijednost za
padajuću listu ne može biti null, odnosno ako nema elementa s pretpostavljenom vrijednošću, što
uzrokuje pogrešku s porukuom „datagridviewcomboboxcell value is not valid“. Rješenje problema je
dodati element s pretpostavljenom vrijednosti za određeni tip. Konkretno za artikle, potrebno je
dodati artikl sa šifrom 0, što je vrijednost od default(int).
Promjenom artikla u padajućoj listi potrebno je ažurirati stupac s jediničnom cijenom artikla te iznos
dokumenta. Navedeno se obavlja prilikom obrade događaja promjene ćelije u kontroli DataGridView
pri čemu treba provjeriti koji je stupac izazvao događaj.
127
Primjer ADO \ EF_Firma \ DokumentStavkaForm
...
Slika 66. Gumb u navigacijskoj traci koji dodaje novi element u izvor podataka
Dodatno, moguće je postaviti predviđeni (engl. default) broj dokumenta i ažurirati prikaz navigatora
tako da onemogućimo sve kontrole osim gumba za snimanje i odustajanje od dodavanja novog
elementa.
24
Prihvaćanje promjena bi se automatski dogodilo prelaskom na drugu kontrolu i gubitkom fokusa s kontrole u
kojoj se vršilo ažuriranje, ali klikom na gumb (na navigacijskoj traci) ne dolazi do prelaska na drugu kontrolu.
128
svojstvama čime bi se automatski mogao pokrenuti izračun cijene dokumenta, cijenu je potrebno
eksplicitno izračunati. Prije snimanja potrebno je provjeriti ima li pogrešaka na dokumentu za što se
koristi svojstvo Error iz sučelja IDataErrorInfo. Promjene u kontekstu se spremaju pozivom postupka
SaveChanges ili SaveChangesAsync.
129
Primjer ADO \ EF_Firma \ DokumentStavkaForm
Stavke za brisanje su prvo kopirane u pomoćnu listu, pa tek onda brisane, jer bi brisanje stavke
unutar prve petlje uzrokovalu promjenu vrijednosti broja označenih redaka i potencijalno promijenilo
indekse stavki koje treba obrisati. Nakon što se stavke eksplicitno obrišu, potrebno je postaviti
svojstvo Cancel drugog argumenta obrade događaja na false kako bi se otkazalo normalno izvođenje
događaja (postavljanje stranog ključa na null).
9.8 Zadaci
Zadatak 1. U tablicu Artikl u bazi podataka dodati sve artikle iz neke Excel datoteke. Za dodane
zapise provjeriti ima li jedinicu mjere iz skupa { "h", "kom", "kg", "l", "pak" } . Ukoliko
nema, ažurirati jedinicu mjere vrijednošću "---". Ažuriranje provesti kreiranjem
odgovarajuće SQL naredbe za svaki zapis koji treba mijenjati.
Zadatak 2. Doraditi Artikl dodavanjem tablice JedinicaMjere i veze s artiklom.
130
Zadatak 3. Ugraditi sortiranje i filtriranje podataka u Drzava.
Zadatak 4. Ugraditi sortiranje i filtriranje podataka u Artikl.
Zadatak 5. Napisati program koji će ažurirati tablicu Artikl tako da obradi sadržaj mape u kojoj se
nalaze slike naziva oblika <IdArtikla>.jpg
Zadatak 6. U formi DokumentStavke u DataGridView za prikaz stavki dodati stupac za šifru
artikla te je povezati na isti izvor kao i naziv artikla.
Zadatak 7. Implementirati validaciju za primjer DokumentStavke.
Zadatak 8. Što sve može biti izvor podataka za povezivanje na kontrolu na formi?
Zadatak 9. Što je jednostavno (Simple Binding) a što složeno povezivanje (Complex Binding) na
bazu podataka?
Zadatak 10. Koja je razlika između CodeFirst i ModelFirst tehnike izrade EF modela?
131
10 Korisničko sučelje i dijalozi
Sučelja aplikacije dijele se na korisničko sučelje (engl. user interface) koje definira interakciju s
krajnjim korisnikom te na sučelje sustava (sistemsko sučelje, engl. system interface) koje određuje
način razmjene informacija s drugim sustavima.
Osnovni mehanizmi korisničkih sučelja su
navigacijski mehanizam – osigurava način na koji korisnici određuju što žele napraviti
ulazni mehanizam – određuje način prihvata informacija
izlazni mehanizam – određuje način pružanja informacija korisnicima ili drugim sustavima
10.1.3 Estetika
Pri izradi korisničkog sučelja treba voditi računa o preglednosti podataka i estetici (engl. aesthetics).
Stoga je poželjno izbjegavati sažimanje kontrola na uskom prostoru te minimizirati neiskorišten
prostor i prekrivanje npr. u slučaju više prikazanih „prozora“.
132
Dodatno se estetika poboljšava pravilnom upotrebom pisma i boja. Obično se preporuča koristiti
maksimalno 4 različite veličine slova na ekranu (uz opasku da web može biti „šareniji“) i do 3 vrste
fonta na jednom ekranu uz korištenje kombinacije velikih i malih slova (izbjegavati kapitalizaciju). Pri
korištenju boja potrebno je paziti na kontrast i npr. koristiti tamni tekst na svijetloj podlozi i obrnuto
uz korištenje najviše 4 različite boje na ekranu. Određene boje nisu preporučljive za prikaz teksta,
npr. plava koja se teško čita i uobičajena je za poveznice).
Neaktivne kontrole je bolje posebno obojati (npr. u sivo), nego ih skrivati.
10.1.5 Dosljednost
Za ostvarivanje dosljednosti (engl. consistency) korisničkog sučelja potrebno je kontrole istog tipa
svuda postavljati tako da jednako izgledaju i da se jednako ponašaju te se trebaju nalaziti na
uobičajenim/očekivanim mjestima (gumbi, status, …).
Dosljednost je najvažniji faktor za pojednostavljivanje načina korištenja sustava. Dosljednost skraćuje
krivulju učenja i omogućuje korisnicima predviđanje što će se dogoditi u pojedinom trenutku. Nakon
što svladaju interakciju s jednim dijelom sustava, korisnici će se znati služiti i drugim dijelovima
sustava.
Kao i kod standarda kodiranja potrebno je postaviti i pridržavati se standarda izgleda (veličina, omjer,
oblik, boja), naslova i ponašanja kontrola i standardizacije značenja tipki (npr. CTRL+C).
133
Općenito, preporuča se poštovati pravilo tri klika (engl. three clicks rule) koje propisuje da se treba
omogućiti pristup od izbornika do podatka u najviše tri koraka (klika mišem ili tipkovničkih
kombinacija).
10.5 Zadaci
Zadatak 1. Kojim načelima oblikovanja sustava pripadaju sljedeći opisi:
a) Poželjno je koristiti najviše 3 različite vrste pisma na ekranu.
b) Objekti sučelja trebaju oponašati izgled i ponašanje stvarnih objekata koje prikazuju.
c) Poželjno je elemente zaslonske maske grupirati u spremnike (container) ili panele.
Zadatak 2. Koju kontrolu grafičkog sučelja odabrati za unos pozitivne cijelobrojčane vrijednosti
(uz pretpostavku da neće biti potrebno unijeti broj veći od 10)? Koju kontrolu
odabrati ako se očekuje unos većih brojčanih vrijednosti?
135
11 Dizajn sustava
136
Specifikacija računalne opreme (hardvera) i programske podrške (softvera) služi kao podloga (popis
stavki) za nabavku ili izradu informacijskog sustava.
Nadgradnja se može izvršiti zamjenom znakovnog sučelja grafičkim koje se izbodi na PC što
produljuje vijek aplikacija, ali se funkcionalnost ne može značajno poboljšati.
137
11.4.2 Dvoslojna arhitektura klijent-poslužitelj (client-server)
Klijent je jednokorisničko računalo (PC), na kojem se nalazi sučelje aplikacije i programska podrška za
obradu i pristup podacima. Klijent je spojen na mrežu te se može povezati na poslužitelje i druge
klijente.
Poslužitelj je višekorisničko računalo, na kojem se nalazi baza podataka i programska podrška koja
omogućuje pristup bazi podataka i u njoj smještenim podacima. Poslužitelj omogućuje povezivanje
klijentima i drugim poslužiteljima (npr. za potrebe replikacije podataka).
Korisnicima na klijentu izgleda kao da njihovo osobno računalo obavlja cijeli posao. Usput, to čak i
može biti tako ukoliko se na osobno računalo instalira poslužitelj baza podataka, kao što programeri
često čine tijekom razvoja.
U ovisnosti o rasporedu pojedinih komponenti na klijentskom računalu u odnosu na poslužitelj,
razlikujemo dvije varijante dvoslojne arhitekture kako je prikazano na sljedećim slikama.
Prednosti:
moguć je brzi početni razvoj aplikacije
veća je samostalnost klijenta
rasterećenje glavnog računala (poslužitelja).
Nedostaci
poslovna logika integrirana je u klijenta
promjena logike zahtijeva instaliranje nove verzije na svim klijentima, to jest korisničkim
računalima, kojih može biti mnogo
razvoj velike aplikacije s vremenom postaje vrlo složen
potreban je veći broj klijentskih računala dovoljne procesne moći.
138
Dvoslojna arhitektura s tankim klijentom
Podatkovna logika, a ponekad i većina elemenata obrade, se nalazi na poslužitelju. Osnovna namjena
tankog klijenta (thin client) je prikaz podataka, koji doduše može imati neku popratnu aplikacijsku
logiku za kontrolu korisničkog sučelja. Tipični primjer tankog klijenta je web preglednik, koji prikazuje
HTML stranicu „iza“ koje se nalazi korisniku nevidljiv pozadinski kod napisan u nekom od skriptnih
jezika (npr. Java script).
Prednosti su:
139
informacija o svim partnerima treba sadržavati uniju upita koji vraća fizičke osobe i upita koji vraća
pravne osobe, a koji imaju različite strukture podataka. S druge strane postavlja se pitanje kako
povezati tu uniju s odgovarajućim dokumentima?
Primjer: Arhitekture\Tanki
dataGridViewPromet.DataSource =
context.ap_PrometPartnera();
Već i ovaj relativno jednostavan primjer dobro pokazuje zašto je klijent tanak.
Poslužitelj baza podataka zadržava upravljanje podacima. Poslužitelj aplikacija preuzima upravljanje
transakcijama, "preuzeto" s podatkovnog poslužitelja, te dio ili čitavu poslovnu logiku, "preuzetu" s
klijenta. Klijent zadržava korisničko sučelje i dio poslovne logike - onaj koji se ne mijenja ili je osobnog
karaktera.
Prednosti:
bolja raspodjela opterećenja
veća skalabilnost - mogućnost prilagodbe povećanju opterećenja bez preopterećenja ili
promjene procedura, uslijed npr. povećanja broja korisnika ili povećanja količine podataka
Nedostaci:
vrlo složen dizajn i razvoj
problem raspodjele podataka, procesa, sučelja
veće opterećenje mreže
141
Slika 71. Višeslojna arhitektura
U općem slučaju može naravno biti i više slojeva, što se najčešće postiže umetanjem dodatnih
aplikcijskih poslužitelja. Napomena: povećanje broja slojeva povećava skalabilnost, ali i složenost te
latenciju (kašnjenje, sporost odziva).
142
Slika 72. Primjer podjele po slojevima u višeslojnoj aplikaciji
Prezentacijski sloj (PL – Presentation Layer) uobičajeno predstavlja grafičko sučelje (GUI) windows,
web ili mobilne aplikacije, no može biti i skup javnih servisa koje druge aplikacije mogu koristiti.
Poslovni sloj (BL – Business Layer) je sloj poslovne logike (BLL – Business Logic Layer) koja sadržni
poslovne klase koje se sastoje ne samo od podataka nego i od odgovarajućeg ponašanja i validacije.
Podatkovni sloj (DL -Data Layer) je sloj za pristup podacima (DAL – Data Acess Layer) koji može biti
npr. izveden korištenjem ADO.NET-a, Entity Frameworka i slično.
Spremišta podataka - Podaci mogu biti pohranjeni u različitim spremištima (Data Storage) te ako se
radi o bazi podataka, taj sloj nože dodatno imati programski kod specifičan za bazu podataka
(pohranjene procedure, pogledi, …).
Napomena: Ovisno o modelu arhitekture moguće je imati i aplikacije koje imaju više slojeva, u kojima
se jedan od navedenih slojeva dodatno razrađuje, odnosno uslojava, pri čemu treba razlikovati
pojmove fizičkog i logičkog sloja. Štoviše, moguće su situacije u kojoj se isti logički sloj (npr. poslovni
sloj) nalazi na dva fizička sloja radi povećanja performansi.
labava (engl. loose) u kojoj neki sloj može komunicirati s bilo kojim slojem ispod čime se
povećavaju peformanse, ali i ovisnost slojeva i
143
stroga (eng. strict) u kojem sloj smije komunicirati samo sa slojem koji je neposredno ispod.
Prednost stroge interakcije je da npr. promjena načina pristupa podacima ne mijenja ništa u
prezentacijskom sloju i izaziva minimalne promjene u poslovnom sloju.
Osim hijerarhijski uslojenih slojeva moguće je imati i poprečne komponente (engl. crosscutting
concerns) zajedničke za sve slojeve u svrhu obrade iznimki, praćenja traga izvršenja programa, raznih
zajedničkih biblioteka itd.
Provjeru podataka potrebno je uvijek napraviti na poslovnom sloju. Iako je validaciju na
prezentacijskom sloju poželjno izvesti zbog brzine aplikacije ne smije se vjerojavati podacima
pristiglim iz prezentacijskog sloja. Ti podaci mogu biti neispravni uslijed programske pogreške,
pogreške u komunikaciji ili zbog zle namjere korisnika.
Jedno od uobičajenih pitanja vezanih za validaciju je zašto treba raditi validaciju ako baza podataka
čuva integritet podataka. Jednom uočen neispravan podatak ne bi trebalo propuštati u niže slojeve, a
dodatno se postavlja i problem oblikovanja složenijih pravila i potencijalnog problema u slučaju
promjene (tipa) spremišta.
144
U primjerima koji slijede validacija se provodi korištenjem sučelja IDataErrorInfo.
Primjer: Viseslojna\BLL\Artikl.cs
Napomena:
Nekoliko uobičajenih pitanja je vezano za razne ORM alate kao što su Entity Framework (EF) ili
nHibernate. Ako bi se EF model generiran u podatkovnom sloju koristio direktno iz prezentacijskog
modela to bi uzrokovalo labavu interakciju između slojeva što nije poželjno u složenim, višeslojnim
aplikacijama i de facto, radi se o debelom klijentu koji ima dodatno razrađen podatkovni sloj.
Korištenjem tehnike Code First, koja temeljem programskih razreda generira razrede podataka, bi se
mogao definirati poslovni model, nakon čega bi preslikavanje u podatkovni sloj slijedilo automatski ili
uz skup definiranih pravila. Problem ovog pristupa je nemogućnost oblikovanja boljeg objektnog
modela koji ne mora biti samo čisto objektno-relacijsko preslikavanje između programa i podataka
(1:1) i nemogućnost oblikovanja složenih pravila. Dodatno, problem bude još veći ako izvor podataka
ne podržava EF ili nHibernate (što npr. ako je izvor podataka SharePoint ili web servis?).
145
ArtiklForm ArtiklBLL BindingList<Artikl> ArtiklDAL Artikl
new
FetchAll
new
new
FetchAll
DalCollection
new
LoadFromDB(item)
Add(Artikl)
For each item in
DalCollection
BindingList<Artikl>
PL BL DL BL
Pri pozivu sa sučelja BLLProvider će stvoriti novu kolekciju artiklala (BindingList<Artikl>) i napuniti je
podacima na osnovu rezultata poziva u razredu koji je zadužen za pristup podacima
(ArtiklDALProvider).
Sučelju će biti vraćena kolekcija poslovnih objekata (podaci + poslovna logika). Kad bi se umjesto
poslovnog objekta sučelju prenosio XML ili neki drugi oblik koji sadrži isključivo podatke prednost bi
bila općenitost i neovisnost, ali bi puno više do izražaja došli nedostatci: otežana validacija, moguće
nekonzistentni podaci, poslovna logika i validacija na raznim mjestima te bi se problem sveo na
problem diskutiran u 11.5.2.
U dizajnu tip podatka za izvor se postavlja na razred definiran u poslovnom sloju, npr. Artikl
146
Slika 74. Postavljanje izvora podataka u dizajnu
Na ovaj način PL (forma) ne zna ništa o načinu pohrane, to jest ne ovisi o podatkovnom sloju.
147
Object - DTO) ili pisanjem tzv. factory metoda u posebnom projektu koji bi bio zadužen samo za
preslikavanje podataka među slojevima, a ovisnost bi riješavao korištenjem tehnike Dependency
Injection.
U primjerima koji slijede, punjenje podataka je izvedeno u metodama poslovnog objekta, izdvojenim
u posebnu datoteku istog imena kao i datoteke gdje je originalna definicija poslovnog objekta, ali u
podmapi DALSpecific.
BLL sadrži referencu na DAL sloj, te uzima objekt iz DAL-a, iterira po njemu, za svaki redak stvara novi
poslovni objekt (u primjeru Artikl), ali učitavanje pojedinačnog podatka prepušta samom poslovnom
objektu pozivom vlastitog internal postupka LoadFromDB. Postupak u poslovnom sloju vraća
kolekciju poslovnih objekata.
Poslovni objekt Artikl je definiran kao parcijalni razred, čime je ostvarena zadovoljavajuća neovisnost
o podatkovnom sloju (jer je potpuno teško ili nemoguće ostvariti). Umjesto pisanja kôda kojim se
kopira stupac po stupac iz rezultata moguće je napisati općeniti kôd koji bi korištenjem refleksije bilo
moguće upariti svojstva nekog objekta s istoimenim nazivi stupaca u IDataReaderu.
148
Primjer: Viseslojna \ BLL \ DALSpecific \ Artikl.cs
149
Primjer: Viseslojna \ BLL \ BLLProviders \ ArtiklBLL.cs
11.6 Zadaci
Zadatak 1. Koje su osnovne funkcije sustava?
Zadatak 2. Koje funkcije obavlja poslužitelj u dvoslojnoj arhitekturi klijent-poslužitelj?
Zadatak 3. Koje su prednosti i nedostatci debelog odnosno tankog klijenta?
Zadatak 4. Gdje se u višeslojnoj aplikaciji, savjetuje stvarati poslovni objekt, a gdje provjeriti
valjanost podataka?
Zadatak 5. Je li potrebno raditi validaciju u aplikaciji ako baza podataka čuva integritet
podataka?
Zadatak 6. Koji su nedostatci predstavljenog višeslojnog rješenja?
Zadatak 7. Proučiti predložak \Prilozi\SpecifikacijaDizajna.dot i primjer \Prilozi\Firma-
Dizajn.doc. Komentirati prijedlog s obzirom na općenite modele arhitekture.
151
12 Primjer višeslojne aplikacije – aplikacija FirmaWin
Firma.Framework predstavlja skup temeljnih razreda i sučelja za izradu poslovnih objekata koji se
nalaze u projektu Firma.BLL. Kao dio projekta Firma.BLL nalazi se mapa BusinessEntities\DALSpecific
koja predstavlja postupke koji direktno ovise o implementaciji podatkovnog sloja (nije prikazano na
slici).
152
Slojevi aplikacije za primjer Artikla se mogu detaljnije vidjeti na sljedećoj slici.
12.3 Firma.Framework
Komponenta Firma.Framework sadrži sljedeće temeljne razreda i sučelja za izradu poslovnih objekata
IBllProvider – sučelje objekta iz poslovnog sloja zaduženog za rad s podacima (sučelje sadrži
postupke za snimanje i validaciju)
IBusinessObject – sučelje poslovnog objekta
BusinessBase – apstraktni razred s osnovnom implementacijom poslovnog objekta
IBusinessObjectList – sučelje liste poslovnih objekata (postupci za dohvat promjena i
otkazivanje novo dodanih u listu)
BusinessBaseList – razred s osnovnom implementacijom liste poslovnih objekata
BusinessObjectState – enumeracija s mogućim stanjima objekta
GenericFormAtributte – vlastiti atributi koji će se dodavati poslovnim objektima u svrhu
automatskog generiranja formi
ValidationException – vlastiti razred za iznimke.
Međusobne ovisnosti prikazane su na sljedećoj slici, a pojedini razred ili sučelje opisano je u
poglavljima koja slijede.
153
Slika 77. Razredi i sučelja projekta Firma.Framework
154
osnovo nekog DTO objekta, a prilikom pohrane pretvara se u odgovarajući razred iz DAL sloja
postupkom ToDtoObject.
25
InEdit provjerava li je objekt trenutno u stanju između BeginEdit i EndEdit/CancelEdit. Za razliku od InEdit,
InEditMode provjerava da li je objekt u takvom stanju da se može ažurirati i aktivira se s Edit(), pa se može reći
da je InEditMode "jači" od InEdit.
155
12.4 Dohvat liste artikala
Rad prethodno opisanih razreda može se ilustrirati na primjeru dohvata liste artikala. Slijed
izvršavanja prikazan je na sljedećoj slici.
new
FetchAll
new
FetchAll
IEnumerable<DTO>
CreateNew(IEnumerable<DTO> ...)
CreateNew<Artikl>
new
Load(DTO)
Add(Artikl)
BusinessBaseList<Artikl>
BusinessBaseList<Artikl>
Normalna interakcija
Forma prezentacijskog sučelja ima referencu na objekt iz poslovnog sloja preko kojeg vrši dohvat
podataka (BllProvider) i zahtijeva dohvat svih elemenata.
Odgovarajući BLL provider vrši upit prema DAL sloju i kao rezultat dobiva kolekciju DTO objekata i
statičkim postupkom CreateNew stvara lista konkretnih poslovnih objekata (u ovom primjeru
BusinessBaseList<Artikl>).
156
Primjer: FirmaWin \ Firma.BLL \ ArtiklBllProvider.cs
U postupku CreateNew stvara se lista poslovnih objekata te se vrši iteriranje po kolekciji DTO
objekata. DTO objekti mogu biti različiti, ali im je zajedničko da implementiraju prazno sučelje
IDTOObject koje služi kao zajednički nazivnnik svih DTO objekata. Za stvaranje pojedinačnog
poslovnog objekt koristi se statički postupak CreateNew u razredu BusinessBase. Razred
BusinessBaseList i postupak CreateNew su parametrizirani su postavljenja ograničenja da tip T po
kojem se vrši parametrizacija mora imati prazni konstruktor (uvjetovano postupkom CreateNew iz
BusinessBase) te da T mora biti poslovni objekt, to jest implementirai sučelje IBusinessObject.
Pojedinačni objekt se stvara pozivom praznog konstruktora i pozivom postupka Load koji će pozvati
apstraktni postupak DoLoad kojeg svaki konkretni poslovni objekt mora implementirati.
Postupak DoLoad prima DTO objekt koji služi za komunikaciju s DAL slojem. Prilikom kreiranja liste
poslovnih objekata i stvaranja pojedinačnih objekata potpuno je nebitan tip DTO objekta te se on
proslijeđuje kakakv jest. Konkretni tip DTO objekta je bitan samo kod konkretnog učitavanja u
postupku DoLoad i kopiranju podataka iz DTO objekta u poslovni objekt. Na ovaj način izoliran je dio
157
koji ovisi o konkretnom tipu DTO objekta, a dodatno je taj postupak stavljen u zasebnu datoteku
parcijalnog razreda. Napomena: korištenjem refleksije bilo bi moguće i ovaj dio ovisnosti ukloniti.
158
Primjer: FirmaWin \ Firma.EF \ AbstractDALProvider.cs
Za spremanje podataka potrebno je pripremiti tri kolekcije podataka: nove, izmijenjene i označene za
brisanje te korištenjem odgovarajućih postupaka u EF-u dodati iz u kontekst i pohraniti promjene.
159
Primjer: Firma.BLL \ BusinessEntities \ Dokument.cs
160
BusinessBaseList<Stavka>
DokumentForm DokumentBllProvider DokumentDalProvider DokumentList Dokument BusinessBase
new
FetchAll
new
FetchAll
IEnumerable<IDTOObject>
CreateNew(dtos, fetchStavkeDelegate)
CreateNew(dto, fetchStavkeDelegate)
Load
fetchStavkeDelegate
IEnumerable<IDTOObject>
CreateNew(dtos)
CreateNew<Stavka>
Stavka
Add(Stavka)
BusinessBaseList<Stavka>
Dokument
DokumentList Add(Dokument)
Normalna interakcija
Framework Framework
PL BLL DAL BLL BLL
Stavke nemaju vlastiti DAL provider te se, kako bi se izbjegla ovisnost o konkretnom DAL provideru
dokumenta, umjesto reference na provider koristi delegat koji se definira postupak koja na osnovu id
dokumenta može dohvatiti njegove stavke. Delegat je tipa Func<int, BusinessBaseList<Stavka>>, a
postupak je napisan u istom razredu gdje se vrši zahtjev za punjenjem liste i koristi isti DAL provider.
...
public DokumentList FetchAll(){
var dalRecord = dal.FetchAll();
return DokumentList.CreateNew(dalRecord, FetchStavke);
}
public BusinessBaseList<Stavka> FetchStavke(int idDokumenta){
var dalRecord = dal.FetchStavke (idDokumenta);
return BusinessBaseList<Stavka>.CreateNew(dalRecord);
}
Stvaranje liste vrši se na isti način kao i kod liste jednostavnih objekata.
161
Primjer: FirmaWin \ Firma.BLL \ BusinessEntities \ DokumentList.cs
Razlika se pojavljuje prilikom učitavanja poslovnog objekta iz DTO objekta time što se osim postupak
Load poziva i postupak u kojem se dohvaća stavke (koji interno opet prolazi sličan postupak dohvata
kolekcije DTO objekata za stavke te kreiranja i punjenja pojedine stavke podacima).
U DAL sloju dohvat stavki nekog dokumenta realiziran je korištenjem pohranjene procedure i
uključivanjem procedure u Entity Framework model.
162
Primjer: FirmaWin \ Firma.EF \ DokumentDalProvider.cs
Primjer:
CREATE PROCEDURE [dbo].[ap_StavkaList_R]
@IdDokumenta int
AS BEGIN
SELECT S.*, A.NazArtikla, A.JedMjere AS JedMjereArtikla
FROM Stavka S
INNER JOIN Artikl A ON S.SifArtikla = A.SifArtikla
WHERE IdDokumenta = @IdDokumenta;
END
Ažuriranim dokumentima svojstva se mijenjaju tako da se iz baze podataka u kontekst dohvati traženi
dokument te mu se sa SetValues postave nove vrijednosti. Isto je potrebno napraviti i za sve one
stavke koje neće biti obrisane, odnosno za stavke koje nisu nove. Stavke iz dohvaćenog dokumenta iz
baze podataka kojih više nema u dokumentu iz poslobvog sloja treba označiti za brisanje, a nove
stavke kojih dosad nije bilo u bazi podataka treba dodati u kontekst na način da se dodaju
dohvaćenom dokumentu.
163
Primjer: Firma.BLL \ Firma.EF \ DokumentDalProvider.cs
164
otkrivanje tipa podatka i pristup informacijama o učitanim asemblijima i tipovima definiranim
unutar njih
dinamičko instanciranje objekata na temelju otkrivenog tipa (engl. dynamic invocation),
pozive postupaka tako stvorenih objekata te dohvat i izmjenu svojstava
stvaranje i korištenje novih tipova za vrijeme izvršavanja programa.
Uobičejeno, refleksija se koristi za razvoj aplikacija za reverzno inženjerstvo, razvoj preglednika
razreda i razvoj editora svojstava razreda (primjer: prozor Properties). Prostor imena u kojima se
nalaze postupci za refleksiju je System.Reflection, a najznačajniji razredi su System.Type u kojem su
sadržane informacije o tipu podatka. Objekt tip System.Type moguće je dobiti na nekoliko načina u
ovisnosti da li je razred o kojem se žele dobiti informacije dostupan (referenciran) u trenutku
kompilacije.
Ako je ciljani razred referenciran u trenutku kompilacije, objekt tipa Type može se dobiti na jedan od
sljedeća tri načina:
Type t = Type.GetType("NazivProstoraImena.NazivRazreda,
NazivAsemblija");
Ako je razred generički, to jest, parametriziran po jednom ili više tipova, tada se iza naziva imena
dodaje znak ` i broj tipova s kojima je razred parametriziran, npr.
Type.GetType("System.Collection.Generic.Dictionary`2");
Postupak GetType je preopterećen te po želji omogućuje ignoriranje velikih i malih slova. Za slučajeve
u kojima je ciljani razred definiran u nekom drugom asembliju, asemblij prethodno treba učitati
postupkom Assembly.Load ili Assembly.LoadFrom ovisno je li asemblij u istoj mapi kao i izvršni
program ili se navodi puna putanja do asemblija.
165
Primjer: Refleksija\Refleksija\Program.cs
//...prikaz informacija
U prethodnom primjeru naziv razreda i naziv postupka su bili tvrdo kodiran, pa nije jasna prednost
ovog pristupa. Praktična korist dinamičkog povezivanja dolazi do izražaja kod izrade raznih proširenja
(engl. plug-in). U tom slučaju je dovoljno definirati sučelje, a korisniku prilikom izvršavanja programa
dopustiti odabir asemblija s konkretnom implementacijom. Refleksijom se tada može pronaći razred
koji implementira traženo sučelje, stvoriti novi objekt i pretvoriti ga cast operatorom u prethodno
definirano sučelje i koristiti kao i svaki drugi objekt.
Druga praktična korist dinamičkog instanciranja je kod implementacije razreda BusinessBase u
trenutku u kojem se potrebno napraviti kopiju objekta, pa se na ovaj način jednostavno može stvoriti
novi objekt, a zatim kopirati svojstva iz jednog objekta, u drugi.
12.7.2 Atributi
Atributi su nadodane oznake tipovima, poljima, postupcima i svojstvima. Atributi se dodaju u uglatim
zagradama [ ] prije deklaracije entiteta koji opisuju te su dostupni programski tijekom izvođenja
programa. Atributi ne mijenjaju razred ili svojstvo sami po sebi, ali je moguće da se u trenutku
izvršavanja neki program koji koristi „ukrašene“ razrede drugačije ponaša u ovisnosti postoji li neki
atribut ili ne. Primjeri preddefiniranih atributa su:
Browsable – postavlja vidljivost svojstva ili događaja u prozoru Properties
Category – kategorija u kojoj se svojstvo ili događaj prikazuje u Properties. Neke
preddefiniranie kategorije su Data, Behavior, Design, Action, Misc te je moguće definirati i
vlastite kategorije
Description - opisuje svojstvo ili događaj te se taj opis prikazuje prilikom prikaza svojstava u
dizajnu
Obsolete – označava da je neki postupak zastario i uzrokuje upozorenje pri kompilaciji s
opisom koji je naveden uz atribut
Novi atribut se definira definiranjem novog razreda izvedenim iz razreda System.Attribute i
definiranjem svojstava atributa. Uobičajeno je da naziv razreda završava s Attribute, dok se kod
korištenja taj sufiks može izostaviti kao što je prikazano u sljedećem primjeru.
166
public class PrviAttribute : System.Attribute{
public string Naziv { get; set; }
public int Broj { get; set; }
}
public class DrugiAttribute : System.Attribute{
public string X { get; set; }
}
[Prvi(Broj=5, Naziv="Test")]
[DrugiAttribute(X = "Proba")]
public class MojRazred{...}
Popis svih vlastitih atributa može se dobiti postupkom GetCustomAttributes na nekom tipu, a primjer
provjere postojanje nekog atributa na nekom članu razreda prikazan je u poglavlju 12.7.3.
Slika 81. Izgled generičke forme i konkretne forme izvedene iz generičke forme
Umjesto kreiranja i instanciranja namjenski oblikovane forme koja bi bila dizajnirana za pojedini tip
podatka (npr. Artikl) kreira se općenita forma koja se prilagođava predanom skupu podataka i
odgovarajućem tipu podatka. Prilikom instanciranja generičkoj formi je potrebno predati informaciju
o naslovu forme, tipu podatka koji se pokazuje na formi, referencu na objekt iz poslovnog sloja koji
može vršiti validaciju i izmjenu podataka te kolekciju podataka koja treba služiti kao izvor podataka.
167
Primjer: FirmaWin – MainForm - Šifrarnici
Generička forma tada provjerava metapodatke poslovnog objekta i na osnovu vlastito definiranih
atributa dinamički stvara odgovarajuće kontrole za unos i izmjenu podatka (Textbox, Checkbox, …) i
natpise ispred kontrola.
[AttributeUsage(AttributeTargets.Property)]
public sealed class GenericFormAttribute : Attribute {
private string displayName = string.Empty;
private string displayFormat = string.Empty;
private HorizontalAlignment ha = HorizontalAlignment.Left;
...
public GenericFormAttribute(string displayName) {
Primjer korištenja vlastitog atributa na poslovnom objektu Artikl dan je sljedećim primjerom.
168
Primjer: FirmaWin \ Firma.BLL \ BusinessEntities \ Artikl.cs
[GenericForm("Šifra")]
public int? SifArtikla {
get { return sifArtikla; }
set { ... }
}
...
GenericForm("Cijena", "N2",
HorizontalAlignment.Right)]
public decimal? CijArtikla {
get { return cijArtikla; }
set { ... }
}
Prilikom pokretanja generička forma vrši obradu atributa refleksijom te za pojedino svojstvo dodaje
prikladnu kontrola na formu. Dohvat svih javnih svojstava danog poslovnog objekta vrši se pomoću
postupka GetProperties iz razreda Type pri čemu se odabiru samo javna svojstva definirana na razini
objekta (ne-statička svojstva). Na formu se dodaju samo ona svojstva koja imaju definiran vlastiti
atribut za prikaz na univerzalnoj formi.
169
Primjer: FirmaWin \ Firma \ Core \ GenericForm (SetupForm)
c.Width = 300;
this.Controls.Add(c);
c.Location = controlPos;
controlPos.Y += 26;
l.SendToBack();
c.Enter += new EventHandler(ControlEnter);
c.Leave += new EventHandler(ControlLeave);
}
...
}
Dodatni primjer refleksije je dohvat ili postavljanje vrijednosti nekom svojstvom, konkretno u
sljedećem primjeru postavljanje vrijednosti kontroli povezanoj na neki izvor podataka na prazni string
ili null u ovisnosti o kojem tipu podatka se radi.
170
Primjer: FirmaWin \ Firma \ Core \ GenericForm (ControlLeave)
if (p.PropertyType.Equals(typeof(string))) {
p.SetValue(businessObject, string.Empty, null);
}
else {
p.SetValue(businessObject, null, null);
}
12.8 Zadaci
Zadatak 1. Što je poslovni objekt, gdje se i kako koristi?
Zadatak 2. Što je Data Transfer Object? Gdje se i kako koristi?
Zadatak 3. Što je refleksija i kako se koristi?
171
13 Web aplikacije - ASP.NET Web Forms
Web aplikacija je programska aplikacija kojoj se pristupa preko internetskog preglednika ili drugog
programa koji implementira HTTP (Hyper Text Transfer Protocol). Svaki skup web stranica nije ujedno
i web aplikacija. Aplikacija koristi programsku logiku da bi prikazala sadržaj korisniku te se obično
izvršava neki programski kod na serveru, pa tako primjerice statički cjenik nije aplikacija, a dinamički
cjenik je aplikacija. Kao primjer jedne web aplikacija može se uzeti Ahyco (http://ahyco.fer.hr) koji
uključuje funkcije identifikacije (autorizacije) korisnika, pisanja provjere, pregleda rezultata, a sastoji
se od baze podataka i programske logike za generiranje web stranica.
Elemente web stranice čine:
HTML (HyperText Markup Language) elementi: osnovni jezik za definiranje web stranica
JavaScript: jezik za klijentske skripte koje izvodi preglednik
kod u nekom drugom programskom jeziku(npr. C#, Java, PHP, …) koji se izvodi na poslužitelju
Aplikacija se izvršava i na poslužitelju i na klijentu, pri čemu klijentski dio mora biti napisan u nekom
od jezika koji Web preglednik podržava (HTML, JavaScript), a pristup resursima na strani klijenta bude
ograničen (npr. JavaScript koji se izvršava unutar preglednika ne može čitati s korisnikovog diska).
Prednost web aplikacije u odnosu na klasičnu aplikaciju je veći broj korisnika (bilo tko s pristupom
Internetu26, na bilo kojem operacijskom sustavu koji ima internetski preglednik), jednostavno
(centralizirano) održavanje i nadogradnja na novu verziju (nema potrebe za instalacijskom
procedurom kod korisnika).
Nedostaci web aplikacije su složenija izrada u odnosu na samostojne klijentske aplikacije, potreba za
posebno dizajniranim sučeljem, mogući problemi pri prikazu u različitim preglednicima, potrebna
prilagodba regionalnim posebnostima različitih korisnika te sigurnosni problemi kao što su
neovlašten pristup aplikaciji i poslužitelju te zatrpavanje prometom.
26
Teoretski bilo tko, praktično ovisi o dizajnu sučelja i klijentskom dijelu aplikacije
172
Slika 83. Skup serverskih konstrola za ASP.NET Web Forms
173
Slika 84. Prevođenje i prikaz web stranica
Web aplikacija
Korištenjem varijante ASP.NET Web Application kreira se rješenje i odgovarajući projekt u kojem je
svaka dinamička stranica sastavljena iz 3 dijela:
27
Ova dvostruka mogućnost nastala je promjenama razmišljanja u razvoju ASP.NET-a u ranijim verzijima Visual
Studia te se zadržala do danas.
28
Stvaranje uobičajenog projekta tipa WebForms stvorilo bi predložak aplikacije koja uključuje provjeru
autentičnosti, predložak glavne stranice, uobičajene JavaScript biblioteke itd., što može biti suvišno za primjere
koji se izrađuju u okviru kolegija, a zauzimaju značajno količinu prostora i usporavaju kompilaciju na serveru.
174
Slika 85. Stvaranje nove web aplikacije
Web mjesto
U varijanti s web mjestom nije potreban projekt, odnosno rješenje, jer su sve datoteke unutar web
mjesta automatski dio „projekta“. Svaka dinamička stranica sastoji se od 2 dijela:
175
13.2 Uobičajeni postupak izrade web stranica
Svaka stranica je predstavljena razredom izveden iz System.Web.UI.Page pri čemu se, slično
kao kod Windows Forms aplikacija, na svaku stranicu dodaju Web Forms kontrole izvedene iz
System.Web.UI.Control. Za svaku kontrolu postoji zasebni razred što pridonosi konzistenciji
objektnog modela i omogućuje bolju provjeru tipova pri prevođenju.
Obrada događaja standardno se obavlja na poslužitelju. ASP.NET Framework vrši transformaciju
kontrola u HTML proširujući mogućnosti HTML kontrola dodatnom funkcionalnošću kao što su
validacija, dodatni postupci, automatski PostBack pri promjeni sadržaja kontrole i slično.
Pojam PostBack predstavlja proces slanja sadržaja stranice poslužitelju na obradu. Promjene na
stranici šalju se poslužitelju koji obrađenu stranicu vraća pregledniku. Da bi se očuvao sadržaj
stranice, podaci se prenose zajedno sa stranicom, a za rekonstrukciju sadržaja koriste se skrivena
polja (__VIEWSTATE).
Uobičajeni postupak izrade web stranice sastoji se od 4 koraka: izbor željenih kontrola (Label,
DropDownList, GridView, ….), imenovanje kontrola koje referenciramo u kodu, dizajn forme -
razmještaj kontrola i postavljanje svojstava te programiranje događaja na poslužitelju.
Uobičajeni redoslijed događaja prilikom korištenja web stranice obuhvaća sljedeće korake:
1. Klijent šalje poslužitelju zahtjev za stranicom (prvi dolazak na stranicu, vrsta zahtjeva je GET)
2. Izvršava se kod metode Page_Load (svojstvo IsPostBack je false)
3. Poslužitelj dinamički kreira web stranicu i šalje je klijentu
4. Korisniku se prikazuje web stranica u pregledniku
5. Korisnik upisuje tekst u neku od kontrola (npr. imena TextBox1) te klikom na gumb (npr.
Button1) aktivira slanje podataka na server
6. Zahtjev i podaci se šalju poslužitelju (vrsta zahtjeva je POST)
7. Izvršava se kod metode Page_Load (svojstvo IsPostBack je sada true)
8. Izvršavaju se kodovi obrade događaja kontrole (npr. Textbox1_Changed, Button1_Click)
9. Nova stranica se šalje klijentu
10. Klijentu se prikazuje osvježena web stranica u pregledniku, pri čemu se može rekonstruirati
prethodni sadržaj (npr. što je bilo upisano u TextBox1)
176
App_WebReferences: mapa za sheme i kosture razreda za rad s pojedinim web servisom
Bin: sadrži dll datoteke, pri čemu je sadržaj ove mape automatski je referenciran unutar
projekta
Mape se mogu se dodati u aplikaciju desnim klikom na projekt i odabirom opcije Add ASP.NET Folder.
Primjer:
Obrada događaja obnavlja se pozadinskim kodom u kojem se mogu programski postavljati svojstva
kontrola (npr. Textbox1.Text = "ABC")
177
Slika 86. aspx stranica (izvorni kod prezentacijskog dijela)
Slika 86 prikazuje primjer jedne aspx stranice - Default.aspx . Pozadinski kod se nalazi u datotekama
Default.aspx.cs te Default.aspx.designer.cs za dio koji nastaje automatski, a predstavlja povezivanje
kontrola i metoda za obradu događaja nad kontrolama.
Primjer: Default.aspx.cs
Događaj Značenje
Stvaranje kontrola, primjena tema, uspostava glavne (master) stranice,
PreInit
postavljanje korisničkih profila (jezik, …)
Inicijaliziranje vrijednosti svojstava kontrola na osnovu poslanih podataka ili
Init
podataka iz ViewStatea
U ovom trenutku sve kontrole su inicijalizirane i vrijednosti povezane => piše
Load
se kod po želji
Obrada događaja Obrada konkretnog događaja koji je uzrokovao Postback (npr. klik na gumb,
promjena označene vrijednosti u listi…)
Iscrtavanje/ispisivanje pojedine kontrole na izlazni tok (HTTP response)
PreRender
Uništavanje objekata
Unload
Događaj se može dogoditi bilo kada tijekom životnog ciklusa
Error
178
Presretanje, tj. obrada pojedinog događaja može se obaviti pisanje postupka oblika Page_Događaj,
npr. Page_Init(object sender, EventArgs e)
Session – sadrži podatke o sjednici (posjetima Web aplikaciji od strane istog korisnika u
nekom vremenskom intervalu) u koju se mogu pohranjivati parovi (ključ, vrijednost) koji se
vežu za korisnika, a imaju vijek trajanja jednak trajanju sjednice (primjer dohvata vrijednosti
za neki ključ: Session["ključ"])
Application – služi za pohranu stanja Web aplikacije slično podacima iz sjednice, ali
dostupno za sve korisnike i vijekom trajanja dok je aplikacija aktivna (npr.
Application["Naslov"])
Request – objekt koji rukuje s podacima o zahtjevu za stranicom
Response – objekt za odgovor na HTTP zahtjev (npr. Response.Write(“<br>”) )
Server – objekt koji sadrži informacije o poslužitelju
User – objekt koji sadrži podatke o trenutnom korisniku
Web aplikacija može imati više master stranica, a za pojedinu stranicu se navodi koja će se glavna
stranica koristiti. Stranica koja ima evidentiranu glavnu stranicu, vlastiti sadržaj dodaje samo unutar
okvira definiranih u glavnoj stranici, tj. nije dopušten nikakav sadržaj izvan oznake asp:Content.
179
Primjer: FirmaWebForms \ Artikli.aspx
Glavna stranica odnosno stranica koja koristi glavnu stranicu se može dodati iz izbornika Add New
Item Web Forms Master Page, odnosno Web Form with Master Page.
13.6.2 Izbornici
Svaki izbornik je skup poveznica na određenu stranicu. Izbornik je moguće prikazati u obliku stabla
(kontrola TreeView) ili slično kao kod Windows aplikacija gdje se opcije dinamički prikazuju iz korijena
izbornika (kontrola Menu).
Elementi izbornika mogu se navoditi direktno unutar kontrole za navigaciju ili definiranjem izvora
podataka koji se veže na određenu mapu web sjedišta. Trenutni položaj određene stranice i veza
prema nadređenim stranicama može se prikazati kontrolom SiteMapPath pri čemu je za korištenje
kontrole SiteMapPath potrebno imati definiran izvor podataka za navigaciju, odnosno mapu web
sjedišta.
Mapa web sjedišta je datoteka s ekstenzijom .sitemap i sadrži hijerarhijski popis stranica uključenih u
izbornik navigacije. Nova mapa se može dodati opcijom Add New Item Site Map. Pretpostavljeni
naziv mape web aplikacije je Web.sitemap.
Slika 87. Kreiranje izbornika pomoću kontrole Menu navođenjem vrijednosti opcija
Slika 88. Kreiranje izbornika pomoću kontrole TreeView navođenjem izvora podataka
180
Slika 87 i Slika 88 prikazuju dvije kontrole za kreiranje izbornika (Menu i TreeView) pri čemu se
elementi mogu definirati na razini kontrole punjenjem svojstva Items ili se kontrola za izbornik može
pridružiti neki izvor podataka povezan s mapom web aplikacije. Dodatno, moguće je postaviti ostala
svojstva izbornika kao što su orijentacija prikaza prvog nivoa izbornika (svojstvo Orientation), stil i
slično.
<siteMap xmlns=...>
<siteMapNode url="" title="Izbornik">
<siteMapNode url="~/Artikli.aspx" title="Artikli" >
<siteMapNode url="~/UnosArtikla.aspx"
title="Unos novog artikla" />
</siteMapNode>
<siteMapNode url="~/DokumentStavka.aspx"
title="Dokumenti" />
...
</siteMapNode>
</siteMap>
Primjer: FirmaWebForms \ ?
Web sjedište može imati više mapa, pri čemu nije nužno imati mapu u datoteci web.sitemap, već je
moguće u datoteci web.config definirati parametre za mape
<system.web>
<siteMap defaultProvider="GlavniIzbornik">
<providers>
<add name="GlavniIzbornik"
type="System.Web.XmlSiteMapProvider"
siteMapFile="~/Navigacija/glavni.sitemap"/>
<add name="Izbornik2"
type="System.Web.XmlSiteMapProvider"
siteMapFile="~/Navigacija/izbornik2.sitemap"/>
</providers>
</siteMap>
...
181
Prilikom definiranja i izvora podataka za mapu potrebno je navesti pružatelja usluge za mapu web
sjedišta.
Primjer: FirmaWebForms \ ?
<asp:SiteMapDataSource
ID="Izbornik2SiteMapDataSource"
runat="server"
SiteMapProvider="Izbornik2" />
Primjer: FirmaWebForms \ ?
Ili, expression može biti vezan izraz vezan za neki izvor podataka pri čemu se koriste oblici
<%# Bind(…) %> i <%# Eval(…) %>
182
InsertMethod – naziv postupka za dodavanje novog podatka
UpdateMethod – naziv postupka za ažuriranje podatka
DeleteMehod – naziv postupka za brisanje podatka
SelectCountMethod – naziv postupka koji vraća ukupni broj elemenata u izvoru podataka.
Ako ovaj postupak nije definiran vrši se dohvat svih (SelectMethod)
SortParamName – naziv argumenta u postupku dohvata (SelectMethod) koji određuje
redoslijed sortiranja. Nazivu svojstva se pridodaje sufiks DESC za silazno sortiranje, a naziv
može biti prazan ako izvor ne podržava sortiranje
EnablePaging – označava podržava li SelectMethod straničenje. Ako da, svojstvo
StartRowIndexParameterName služi za definiranje naziva argumenta za poziciju početnog
elementa (pretpostavljeno startRowIndex), a svojstvo MaximumRowsParameterName sadrži
naziv argumenta za broj podataka koje treba dohvatiti (pretpostavljeno maximumRows)
Parametar u postupcima za dohvat, dodavanje, ažuriranje i brisanje imaju iste nazive kao što su nazivi
pojedinih stupaca ili postoji jedan parametar jednak tipu navedenom pod svojstvom
DataObjectTypeName. U primjeru su implementirani pomoćni razredi (s navedenim postupcima) za
rad s poslovnim objektima iz Firma.BLL, pa je u projekt bilo potrebno uključiti datoteke Firma.BLL.dll,
Firma.EF.dll i Firma.Framework.dll, a u datoteku Web.config dodati connection stringom pod nazivom
FirmaEntities.
183
Primjer: FirmaWebForms \ DataControllers \ ArtiklController.cs
[DataObject]
public class ArtiklController{
[DataObjectMethod(DataObjectMethodType.Select, true)]
public BusinessBaseList<Artikl> DohvatiSveArtikle(){
ArtiklBllProvider bll = new ArtiklBllProvider();
return bll.FetchAll();
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public BusinessBaseList<Artikl> DohvatiArtikle(int startRowIndex,
int maximumRows) { ... }
Čarobnjak za povezivanje izvora podataka i metoda za rad s podacima bit će jednostavniji ukoliko se
iznad postupka stavi posebni atribut DataObjectMethod koji sugerira što postupak radi (Delete, Fill,
Insert, Select, Update) te ako se iznad razreda stavi atribut DataObject.
Za prethodno definiran pomoćni razred povezivanje u aspx stranici može se ostvariti na dva načina:
1. dohvatom svih podataka
2. Ili (bolje) dohvatom samo potrebnih podataka za trenutnu stranicu. U tom slučaju treba
implementirati vlastito straničenje i sortiranje. Za straničenje treba definirati postupak koji
će biti pridružen svojstvu SelectCountMethod (u primjeru je to ArtiklCount). Slično, za
sortiranje treba deinirati SortParameterName (sortParam u primjeru DrzavaController)
184
Primjer: FirmaWebForms \ Artikli.aspx
Slika 90 prikazuje različite moguće vrste izvora podataka za kontrolu GridView kao što su: baza
podataka podržana kroz ADO.NET, Entitity Framework ili LINQ model, poslovni objekt, mapa web-
sjedišta, XML datoteka i baza podataka u Accesu.
Izvor podataka se može definirati u dizajnu pridruživanjem izvora podataka svojstvu DataSourceId ili
programski (tijekom izvođenja) pridruživanjem konkretnog izvora svojstvo DataSource nakon čega
slijedi poziv metode DataBind29.
Mreža s podacima se može grafički urediti kroz Visual Studio odabirom opcija AutoFormat (odabir
između nekoliko unaprijed definiranih izgleda mreže) i EditColumns (grafičko sučelje za definiranje
stupaca mreže) ili korištenjem CSS stilova (CSS - Cascading Style Sheets). Izgled mreže je u primjeru
odvojen od koda korištenjem CSS datoteka i pridruživanjem stila svojstvu CssClass.
29
DataBind nije potreban ukoliko je unutar aspx stranice definiran DataSourceId.
185
Primjer: Web \ Firma.WebForms \ Content \ Site.css
.zebra
{
border: thin solid black;
padding: 2px;
border-spacing : 0px;
margin: 0px;
text-align: left;
}
.zebra tbody tr th {
background-color: tan;
}
186
DataBound – nastaje nakon što su podaci povezani s mrežom
PageIndexChanged – nastaje nakon što je mreža s podacima obradila zahtjev za promjenu
stranice
PageIndexChanging – nastaje nakon klika na gumb za promjenu trenutne stranice unutar
mreže s podacima, a prije nego mreža s podacima sama obradi događaj
RowCancelingEdit – nastaje pri ažuriranju retka nakon klika na gumb Cancel, a prije nego se
izađe iz načina rada koji omogućava ažuriranje
RowCommand – nastaje nakon klika na gumb koji se nalazi unutar mreže s podacima
RowCreated – nastaje nakon što se stvori pojedini redak u mreži
RowDataBound – nastaje nakon što se pojedini redak poveže s podacima iz izvora
RowDeleted – nastaje nakon brisanja pojedinog retka
RowDeleting – nastaje pri brisanju retka, nakon klika na gumb Delete, a prije samog brisanja
RowEditing – nastaje pri zahtjevu za ažuriranje retka mreže nakon klika na gumb Edit, a prije
nego samog ulaza u način rada za ažuriranje
RowUpdated – nastaje nakon ažuriranje pojedinog retka
RowUpdating – nastaje nakon klika na gumb Update, ali prije samog ažuriranja
SelectedIndexChanged – nastaje pri promjeni označenog retka
SelectedIndexChanging – nastaje nakon klika na gumb Select, prije promjene označenog
retka
Sorted – nastaje nakon što je mreža s podacima sortirana po određenom stupcu
Sorting – nastaje klikom na stupca po kojem se želi sortirati, a prije samog sortiranja
DataBinding,Disposed, Init, Load, Unload, PreRender – naslijeđeno iz razreda Control
187
Slika 91. Primjer dodavanja izvora podataka za GridView
188
Primjer: Web \ Firma.WebForms \ Artikli.aspx
Inicijalno su svi stupci vezani (BoundField) za određeno polje iz baze (DataField). Zbog ograničene
funkcionalnosti i mogućnosti prikaza vezane stupce je ponekad potrebno pretvorititi u stupce
dizajnirane predloškom što se može obaviti u dizajnu klikom na gornji desni rub mreže s podacima i
odabirom opcije Edit Columns → klik na stupac → "Convert this field into a TemplateField".
Predloškom je moguće definirati izgled zaglavlja stupca (HeaderTemplate), izgled podnožja stupca
(FooterTemplate), izgled pojedinog retka (ItemTemplate), izgled svakog drugog retka
(AlternatingItemTemplate), izgled retka prilikom ažuriranja (EditItemTemplate) i izgled novog retka u
mreži (InsertItemTemplate).
Kod stupaca definiranih preko predložaka potrebno je eksplicitno povezati element stupca mreže sa
stupcem u izvoru postupcima Eval i/ili Bind. Od verzije 4.5. umjesto Eval i Bind mogu se koristiti Item i
BindItem koji predstavljaju „strongly typed“ varijantu postupaka pri čemu je prethodno potrebno
postaviti svojstvo ItemType na kontroli GridView.
Eval i Bind su statičke metode razreda DataBinder i služe za jednosmjerno odnosno dvosmjerno
povezivanje, a ujedno se može i navesti format prikaza, npr. <%# Bind("Cijena",
"{0:N2}") %>. Kod dvosmjernog povezivanja vrijednost koja je vezana za neku kontrolu s Bind
prenosi se na poslužitelj prilikom postbacka.
Osim s Eval, podacima se može pristupati i drugačije u ovisnosti o tipu podataka koji se prikazuju
pomoću mreže, npr.
za DataTable: <%# ((DataRow)Container.DataItem)["FieldName"] %>,
za List<string>: <%# ((string)Container.DataItem %>
189
Kada je izvor podataka EntityFramework nije potrebno postavljati dodatne postavke, jer je
automatski implementirano rukovanje podacima na izvoru podataka.
Kada je izvor podataka neki poslovni objekt, potrebno je definirati postupke za dohvat
(SelectMethod), dodavanje (InsertMethod), ažuriranje (UpdateMethod), brisanje (DeleteMethod).
Vezani stupci i kontrole koje povezivanje ostvaruju s Bind ili BindItem automatski povezuju vrijednosti
i te vrijednosti šalju kao parametre metodama za rukovanje podacima.
<Columns>
...
<asp:TemplateField>
<EditItemTemplate>
<asp:CheckBox ID="cbObrisiSliku" runat="server"
Text="Obrisati sliku?" />
<asp:FileUpload ID="UploadSlike" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Image ID="Image1" runat="server"
Width="80px" Height="50px"
ImageUrl='<%# Eval("SifArtikla",
"SlikaArtikla.aspx?SifArtikla={0}") %>' />
</ItemTemplate>
</asp:TemplateField>
...</Columns>
Bolje, ali složenije rješenje je koristiti rukovatelj (tzv. handler), razred koji implementira IHttpHandler
i zahtijeva dodatno podešavanje u web.configu.
190
13.8.7 Prijenos argumenata stranici
U prethodnom primjeru za dohvat slike korišten je parametar koji je dodan na adresu stranice.
Standardno URL neke stranice je oblika
http://server/putanja/stranica.aspx?naziv1=vrijednost1&naziv2=vrijednost2,
a parametri iza upitnika čine tzv. QueryString. Vrijednost pojedinog parametra iz QueryStringa može
se dobiti pomoću Request["Naziv parametra"].
Neka od važnijih svojstava klase Request su:
191
Primjer: Web \ Firma.WebForms \ Artikli.aspx
<Columns>
...
<EditItemTemplate>
<asp:TextBox ID="tbCijena" runat="server" Text='<%#
Eval("CijArtikla", "{0:N2}") %>'></asp:TextBox>
</EditItemTemplate>
192
Provjera na serveru (nakon postbacka) može se obaviti provjerom svojstva Page.IsValid, a dodatno se
mogu napisati vlastite validacijske kontrole za postupke koji se trebaju izvesti na serveru u metodi
pridruženoj događaju onservervalidate.
<asp:RegularExpressionValidator ...
ErrorMessage="Cijena artikla mora biti decimalni broj s maksimalno dvije
decimale"
ValidationExpression="\d*(\,\d{1,2})?"
ControlToValidate="tbCijenaArtikla" />
Za realizaciju ovog primjera korištena je kontrola ObjectDataSource koja služi za definiranje izvora
podataka na koji se neka složena kontrola povezuje. U ovom primjeru definirano je 5 izvora
podataka:
193
StavkeDataSource: izvor podataka za stavke pojedinačnog dokumenta korištenjem
postupaka iz DokumentControler.cs
ArtiklDataSource: izvor podataka za odabir artikla iz padajuće liste za pojedinu stavku
dokumenta korištenjem postupka iz ArtiklLookupController.cs za dohvat artikala
PrethodniDokumentDataSource: izvor podataka za padajuću listu za odabir prethodnog
dokumenta korištenjem postupka FetchLookup iz DokumentBllProvidera iz primjera
Firma.Win
PartnerDataSource: izvor podataka za padajuću listu za odabir partnera korištenjem
postupka FetchLookup iz PartnerBllProvidera iz primjera Firma.Win.
Kontrola FormView ima 3 načina prikaza (ReadOnly, Insert, Edit) te se za svaki od njih dizajnira
posebni predložak kao primjerice na Slika 93 i Slika 94.
Slika 94. Primjer predloška za unos novog podatka korištenjem kontrole FormView
[DataObject]
public class DokumentController {
[DataObjectMethod(DataObjectMethodType.Select, true)]
public DokumentList DohvatiDokumente() {
var bll = new DokumentBllProvider();
var list = bll.FetchLazy();
return list;
}
...
Na dnu predloška dodani su gumbi za prelazak u neki od drugih načina prikaza (naredbe Edit i New) i
gumb za brisanje pojedinog dokumenta (naredba Delete). Nijedan od gumba ne izaziva validaciju
(CausesValidation=false) što je bitno u slučaju da se na stranici neki drugi podatak nalazi u stanju
ažuriranja, jer bi neuspješna validacija tog drugog podatka onemogućila promjenu stanja kontrole
195
FormView. Gumbu za brisanje pri inicijalizaciji (obrada događaja Init) se dodaje Javascript kod za
potvrdu brisanja (pogledati postupak DeleteButton_Init)
Na dnu predloška dodan gumb za spremanje (naredba Update) i gumb za odustajanje (naredba
Cancel). Za sve kontrole za unos potrebno je dodati validacijske kontrole i postaviti svojstvo
ValidationGroup na vrijednost jednako kao i kod gumba za spremanje promjena.
30
Iznimno, zbog performansi padajuća lista za artikle je spremljena u memoriju, pa se koristi pomoćni razred
DataControllers\ArtiklLookupController.cs
196
a za prikaz teksta u padajućoj listi korišteno svojstvo Text iz LookupData. Odabrani element se veže
na konkretno svojstvo iz Dokumenta (npr. na IdPartnera).
U padajućim listama moguće je kombinirati fiksne vrijednosti i vrijednosti iz izvora podataka na način
da se svojstvo AppendDataBoundItems postavi na true, a fiksne vrijednosti se navode kao elementi
tipa ListItem s atributima Text31 i Value
31
Umjesto atributa Text može se navesti tekst između otvorene i zatvorene oznake ListItem
197
Primjer: Web \ Firma.WebForms \ DokumentStavka.aspx
Gumb s naredbom Insert aktivira postupak pridružen svojstvo pridružen InsertMethod na izvoru
podataka nakon čega se vrijednosti povezanih podataka šalju pridruženom postupku.
<asp:ObjectDataSource ID="DokumentDataSource" …
TypeName="DokumentController" InsertMethod="InsertDokument"
…
Specifičnost kod dodavanja je potreba skrivanja stavki u načinu za dodavanje novog elementa, jer
novi element nema stavke, pa bi eventualno bile vidljive stavke prethodno prikaznog dokumenta.
Rješenje problema je obrada događaja ItemCreated na kontroli FormView. Događaj se pojavljuje
nakon što se kontrole iz predloška stvore, a prije povezivanja podataka. S obzirom da događaj
ItemCreated nije nužno vezan samo za dodavanje, mora se provjeriti koji je način prikaza trenutno
aktivan.
Osim skrivanja stavki kod dodavanja, potrebno je obratiti pažnju i na situaciju u kojoj je kontrola
FormView u način prikaza podataka, ali ne postoji niti jedan dokument, pa je kontrolu FormView
potrebno odmah prebaciti u način za dodavanje. Svaka kontrola iz predloška se može dohvatiti
postupkom FindControl, npr. FormViewDokument.FindControl("NazivKontrole").
Dodatno, prije početka dodavanja postavljaju se inicijalne vrijednosti za datum i broj dokumenta.
198
Primjer: Web \ Firma.WebForms \ DokumentStavka.aspx
32
Navedeno ponašanje nije dokumentirano, već se pokazuje u praksi
199
Primjer: Web \ Firma.WebForms \ DokumentStavka.aspx.cs
Slika 97. Parametrizacija izvora podataka za stavke vrijednošću primarnog ključa prikazanog dokumenta
200
Slika 97 prikazuje način postavljanja parametra kroz dizajn tako da se iz trenutnog dokumenta u
FormViewu uzme primarni ključ (svojstvo SelectedValue) i pridruži parametru upita. Postupak za
dohvat mora primati navedene parametre. Postavljanje parametara može se postaviti kroz dizajn ili
ručnim dopisivanjem unutar kontrole ObjectDataSource i elementa SelectParameters.
GridViewStavke.FooterRow.FindControl("ddlSifArtikla");
Ako se stavka dodaje iz predloška za praznu mrežu tada se koristi specifičan način dohvata pojedine
kontrole:
201
Primjer: Web \ Firma.WebForms \ DokumentStavka.aspx.cs
GridViewStavke.Controls[0].Controls[0].FindControl("ddlSifArtikla");
Stvorenu stavku potrebno je nakon toga dodati u konkretni dokument i snimiti promjene.
GridViewStavke.DataBind();
FormViewDokument.DataBind();
13.10 Zadaci
Zadatak 1. Koje su osnovne funkcije sustava?
Zadatak 2. Koje funkcije obavlja poslužitelj u dvoslojnoj arhitekturi klijent-poslužitelj?
Zadatak 3. Koje su prednosti i nedostatci debelog odnosno tankog klijenta?
202
14 ASP.NET MVC
ASP.NET MVC (Model-View-Controller) je ASP.NET realizacija općenitog arhitekturnog obrasca MVC,
koja omogućuje detaljnu razradu prezentacijskog sloja u 3 komponente: model, pogled i upravljač.
Slika 98 prikazuje ovisnosti između ovih komponenti.
Pogled definira izgled korisničkog sučelja i ovisi samo o modelu, tj. određuje izgled prikaza nekog
objekta modela.
Upravljač predstavlja prezentacijsku (aplikacijsku) logiku. Prima ulaz iz pogleda, obrađuje ga, puni i/ili
dohvaća model, poziva niže slojeve i određuje redoslijed prikaza pogleda.
U jednostavnim aplikacijama isti model može objedinjavati i poslovnu logiku i sloj pristupa podacima
i ujedno biti korišten u pogledima. Međutim, u složenijim se aplikacijama kao model koristi „pravi“
poslovni model, a eventualni model unutar projekta služi za definiranje pomoćnih modela za lakši
prikaz podataka (npr. agregirane podatke iz poslovnog modela) što predstavlja „prezentacijski
model“, a ne model u smislu poslovnog objekta. Odvajanjem poslovnog modela u zasebni projekt
naglašava se neovisnost modela i ujedno sprječava postojanje ovisnoti modela o implementaciji
korisničkog sučelja koje bi koristilo taj model.
203
korištenje ugrađenih kontrola ograničava kontrolu nad HTML-om koji nastaje pretvorbu tih
kontrola u HTML
slaba mogućnost testiranja, jer dolazi do čestog miješanja prezentacijske i aplikacijske logike
što rezultira i prevelikim *.cs datotekama.
ASP.NET MVC ove probleme rješava objedinjujući iskustva MVC implementacija u drugim jezicima.
Sam MVC kao koncept nastavo je u kasnim sedamdesetim godinama prošlog stoljeća kao Smalltalk
projekt unutar Xeroxa.
Prednost MVC-a nad web formama očituje se u smanjenju složenosti podjelom aplikacije u model,
pogled i upravljač, a što omogućava razvoj vođen testiranjem (engl. test-driven development).
Odvajanje pogleda predstavlja dobar radni okvir za veće razvojne timove i dizajnere, jer izgled
aplikacije nije isprepleten kodom. MVC ne koristi ViewState ni serverske kontrole čime je omogućena
potpuna kontrola ponašanja aplikacije. Svi zahtjevi su centralizirani na jedan upravljač, što se
označava pojmom Front Controller pattern, uz bogatu podršku za intepretiranje i usmjeravanje
zahtjeva.
Prednost web formi nad MVC-om dolazi do izražaja u situacijama kad je veći naglasak na održavanju
stanja web aplikacija, a količina podataka nije od presudne važnosti (primjerice kod intranet
aplikacija). Dodatno web forme podržavanju velik broj serverskih kontrola i uobičajenih događaja
nalik Windows formama, što (početni) razvoj čini lakšim zbog manje količine koda i može biti
prikladno kod manjih projekata kod kojih se zahtijeva jednostavan, brz i jeftin razvoj. Web forme
koriste tzv. Page Controller pattern u kojem je funkcionalnost vezana uz pojedinu stranicu.
205
Primjer: FirmaMVC \ Global.asax.cs
namespace FirmaMvc {
public class MvcApplication : System.Web.HttpApplication {
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(
GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
...
bundles.Add(new StyleBundle("~/Content/css").Include(
...,
"~/Content/Site.css"));
}
Prilikom korištenjem paketa unutar nekog pogleda navodi se ime paketa kako je definirano prilikom
kreiranja, primjerice za gornje stvaranje paketa primjer poziva bi mogao biti sljedeći
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")
206
Primjer: FirmaMVC \ RouteConfig.cs
207
HttpUnauthorizedResult Vraća HTTP kod 401 -
HttpNotFoundResult Vraća HTTP kod 404 HttpNotFound
HttpStatusCodeResult Vraća određeni HTTP kod -
EmptyResult Bez povratne vrijednosti -
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Sadržaj pogleda koji koristi glavnu stranicu dinamički će se ugraditi u sadržaj glavne stranice na
mejsto na kojem se nalazi naredba RenderBody. Glavna stranica za primjer FirmaMVC izgleda kao u
sljedećem odsječku
208
Primjer: FirmaMVC \ Views \ _ViewStart.cshtml
<!DOCTYPE html>
<html lang="hr_HR" xml:lang="hr_HR"…>
<head>
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")
</head>
<body>
<div id="header">
<div class="title">RPPP - Firma.MVC</div>
</div>
<div id="navigation">
@{Html.RenderAction("Navigation", "Home");}33
</div>
<div id="content">@RenderBody()</div>
@RenderSection("scripts", false)
<script src="@Url.Content("~/Scripts/firma.js")"
type="text/javascript"></script>
</body>
</html>
@using FirmaMvc.HtmlHelpers
@model FirmaMvc.Models.MjestoListViewModel
@{
ViewBag.Title = "Poštanski brojevi";
}
33
U ovom retku između znaka @ i konkretne naredbe se nalaze vitičaste zagrade jer RenderAction ne vraća
string koji bi se ugradio u stranicu, već RenderAction direktno piše na izlaz. Umjesto ovoga bi moglo npr.
@Html.Action("Navigation", "Home"),
209
Tekst koji treba biti u konačnom HTML-u, a nije već dio neke HTML oznake (engl. tag) prefiksira se s
@: ili se stavlja oznaka <text>. Vlastiti prostori imena uključuju se u pojedinom pogledu s @using.
Alternativno mogu se uključiti za sve poglede u web.configu.
210
samo …/Mjesto, jer je Index pretpostavljena akcija. Opcionalno se predaje broj stranice i redoslijed
sortiranja, pa primjer takvog poziva može biti npr. /Mjesto/Page27?sort=4.
Model za prikaz mjesta sadrži popis mjesta (dovoljno je da je IEnumerable) i podatke o trenutnoj
stranici, ukupnom broju stranica i redoslijedu sortiranja (svojstva u razredu PagingInfo). Za mjesto se
koristi poslovni objekt razreda Mjesto iz Firma.BLL.
Za svako mjesto definiran je jedan redak tablice s podacima o mjestu. Izgled retka definiran je
korištenjem css klasa iz datoteke Content/Site.css. Vrijednost modela može se dohvatiti preko
svojstva Model koju svaki pogled ima.
Kako bi se omogućilo sortiranje i straničenje zaglavlje tablice s podacima sadrži poveznice na akciju
Index na trenutnom upravljaču s vrijednostima za broj stranice i redoslijed sortiranja. Poveznice koje
koriste GET zahtjev stvaraju se postupkom Html.ActionLink.
211
Primjer: FirmaMVC \ Views \ Mjesto \ Index.cshtml
@model FirmaMvc.Models.MjestoListViewModel
...
<table class="zebra">
<thead>
<tr>
<th>@Html.ActionLink("Poštanski broj", "Index",
new { sort = 1, page = Model.PagingInfo.CurrentPage})</th>
<th>@Html.ActionLink("Naziv mjesta", "Index",
new { sort = 2, page = Model.PagingInfo.CurrentPage})</th>
...
...
@foreach (var item in Model.MjestoList)
{
<tr>
<td>@item.PostBrMjesta</td>
<td>@item.NazMjesta</td>
<td>@item.PostNazMjesta</td>
<td>@item.OznDrzave</td>
...
<td>@Html.ActionLink("Ažuriraj", "Edit",
new { id = item.IdMjesta})</td>
...
}
...
</table>
[HttpGet]
public ActionResult Edit(int id) {
…
}
[HttpPost]
public ActionResult Edit(Mjesto mjesto) {
…
}
212
sam procjenjuje koju HTML kontrolu napraviti na osnovu tipa svojstva. Html.HiddenFor služi za
vrijednosti koje treba sačuvati, a ne smiju se mijenjati i korisnik ih ne vidi na ekranu. Ime html
kontrole u generiranom HTML-u određeno je imenom svojstva.
Primjerice, odsječak
@using (Html.BeginForm()) {
…
@Html.HiddenFor(m => m.IdMjesta)
@Html.EditorFor(m => m.PostBrMjesta)
Alternativno, mogu se koristiti varijante navedenih postupaka bez sufiksa For pri čemu je potrebno
navesti željeno ime za kontrolu u generiranom HTML-u.
Prilikom korištenja svojstva ViewBag i ViewData nema sintaksne promjene te je potrebno obaviti
ukalupljivanje (engl. cast) u (autoru) poznati tip. U prethodnom primjeru u upravljaču je unutar
ViewBaga dostavljen popis država (tip podatka DrzavaList). U pogledu je potrebno stvoriti padajuću
listu na osnovu država koje su predane pogledu i postaviti da u padajućoj lisit bude odabrana država
kojoj prikazano mjesto pripada. Za navedeni zadatak koristi se jedna od inačica postupka
Html.DropDownListFor i lambda izraz za svojstvo koje se želi povezati. Za elemente liste koristi se
kolekcija SelectListItem.
213
Primjer: FirmaMVC \ Views \ Mjesto \ Edit.cshtml
14.5.5 Validacija
Za prikaz validacijskih pogrešaka unutar pogleda koriste se Html.ValidationSummary za pogreške na
razini modela i Html.ValidationMessageFor za pogreške na razini svojstva. Validacija se može
provoditi na jedan od načina:
automatski na osnovu metapodataka modela ako model ima definirane atribute iz prostora
imena System.ComponentModel.DataAnnotations
eksplicitnim postavljanjem pogrešaka modela pozivom postupka ModelState.AddModelError
pri čemu se kao argumenti predaju naziv svojstva i opis validacijske pogreške, a svojstvo
ModelState (tipa ModelStateDictionary) je svojstvo koje ima svaki upravljač
MVC u slučaju validacijske pogreške postavlja odgovarajuću css klasu na html element vezan uz
svojstvo s pogreškom, a nazivi css stilova za validacijske pogreške su input-validation-error, field-
validation-error i validation-summary-errors.
U primjeru Firma.MVC validacija se radi u poslovnom sloju, a za prikazan unutar web aplikacije koristi
se eksplicitno postavljanje pogreške pozivom postupka ModelState.AddModelError. S obzirom da je
način validacije isti za sve poslovne objekte kreirana je metoda s 2 argumenta, svojstvom ModelState
214
i poslovnim objektom pri čemu je metoda izvedena kao proširenje (engl. extension) klase
ModelStateDictionary.
// Primjer poziva:
ModelState.ValidateBusinessObject(objekt tipa BusinessBase)
Prilikom poziva postupka za stvaranje stranice potrebno je proslijediti lambda izraz za funkciju s 2
cijelobrojna argumenta koja vraća string. U gore navedenom povratna vrijednost takve funkcije će
biti rezultat postupka Url.Action pri čemu su p i s vrijednosti koje u u nekom trenutku bile u postupku
PageLinks. Primjerice, kod poziva pageUrl(i, pagingInfo.Sort) , p ima vrijednost i, a s ima vrijednost
pagingInfo.Sort.
215
gumb za svako mjesto. Forma se kreira korištenjem jedne od nekoliko preopterećenih metoda
Html.BeginForm predajući postavke forme (akcija, upravljač, parametri…).
Kako bi se izbjeglo da se slučajnim klikom na gumb Obriši izbriše podataka naknadno će korištenjem
javascripta34 biti dodan programski kod koji će korisnika upitati želi li izbrisati podatak. Taj princip se
upotrebljava i za druge stranice na kojima je omogućeno brisanje, pa su svi gumbi ukrašeni stilskom
klasom delete. Ta klasa nema svojstava i služi samo da bi skripta mogla pronaći sve takve kontrole,
bez da ih se eksplicitno mora navoditi u kodu skripte.
Klikom na gumb Obriši za gore navedenu formi poziva se akcija Delete na upravljaču
MjestoController. Brisanje nema vlastiti pogled te nakon brisanja dolazi do preusmjeravanja na akciju
pregleda svih mjesta. Parametri page i sort su preneseni kako ne bi došlo do povratka na početnu
stranicu u pregledu mjesta, već upravo na onu s koje je zahtjev za brisanje upućen. Eventualno se
ispisuje tekst pogreške. ViewBag ili ViewState nisu za to prikladni, jer upravljač za brisanje nema
vlastiti pogled kojem bi proslijedio model i dodatne podatke, već dolazi do preusmjeravanja.
Eventualna pogreška prilikom brisanja stavlja se u svojstvo TempData a podaci iz TempData se brišu
nakon dovršetka http zahtjeva (dakle, imaju smisla samo kod prvog preusmjeravanja). TempData se
koristi iz pogleda ili iz glavne stranice.
[HttpPost]
public ActionResult Delete(int id, int page = 1, int sort = 1)
{
try
{
MjestoBllProvider bll = new MjestoBllProvider();
Mjesto mjesto = bll.Fetch(id);
mjesto.Delete();
bll.Save(mjesto);
}
catch (Exception exc)
{
TempData["Pogreska"] = exc.Message;
}
return RedirectToAction("Index", new { page = page, sort = sort });
}
34
Skripta Firma.js s pripadajućim kôdom uključena je na glavnoj stranici
216
14.6 Prikaz artikala
Za prikaz artikala koristi se model koji sadrži kolekciju artikala (objekata iz Firma.BLL) i informacije o
stranicama i broju elemenata. Artikli se prikazuju tablično, a u svakom retku s podacima artikla
prikazuje se i slika artikla i poveznice za ažuriranje i brisanje artikala. Za ažuriranje prikazane su 2
verzije, klasično kao u primjeru mjesta ili unutar retka koristeći jQuery i Ajax.
@model FirmaMvc.Models.ArtiklListViewModel
...
<table>
@foreach (var item in Model.ArtiklList)
{
<tr>
<td><img src="@Url.Action("GetImage", "Artikl",
new { id = item.SifArtikla })" ... /> </td>
<td>@item.SifArtikla</td> <td>@item.NazArtikla</td>
...
<td>@Html.ActionLink("Ažuriraj", "Edit",
new { id = item.SifArtikla,
page = Model.PagingInfo.CurrentPage })
...
Dodavanje slike vrši se prilikom unosa ostalih podataka o artiklima (npr. na formi za ažuriranje)
dodavanje HTML kontrole input tipa file, pri čemu forma mora biti označena kao multipart/form-
data.
217
Primjer: FirmaMVC \ Views \ Artikl \ Edit.cshtml
Naziv input kontrole i naziv argumenta u postupku koji prima podatke moraju biti isti. Ulazni
argument koji predstavlja prenesenu datoteku je tipa HttpPostedFileWrapper kojim se može dobiti
informacija o veličini te dobiti ulazni tok i pročitati sadržaj.
[HttpPost]
public ActionResult Edit(Artikl artikl,
HttpPostedFileWrapper slika, bool obrisiSliku, int page = 1){
var bll = new ArtiklBllProvider();
Artikl original = bll.Fetch(artikl.SifArtikla.Value);
...
if (slika != null) {
original.SlikaArtikla = new byte[slika.ContentLength];
slika.InputStream.Read(original.SlikaArtikla, 0, slika.ContentLength);
Nakon što se stranica s prikazom artikala učita, kod pisan u jQueryju pronalazi sve takve poveznice i
pridružuje im odgovarajući događaj. jQuery kod koji se izvršava tek nakon učitavanja stranice počinje
s $(function() { …
218
Poziva se postupak vlastiti postupak SetEditAjax iz firma.js. U kodu navedene metode sprječava se
uobičajeno ponašanje poveznice (preventDefault) te se poziva akcija predana parametrom
editAjaxUrl koja izaziv GET varijanta poziva uz šifru artikla izvučenu iz vlastitog atributa. Redak u
kojem se poveznica nalazila (redak s detaljima artikla) se mijenja sadržajem rezultata pozvane akcije.
Predložak za ažuriranje kojeg je vratio postupak EditAjax sadrži retke tablice s html kontrolama za
unos i ispis rezultata validacije. Svaka kontrola ima vlastiti atribut sifartikla kako bi se razlikovala od
ostalih na stranici. Namjena pojedine kontrole (tj. informacija kojem svojstvu artikla kontrola
pripada) u ovom primjeru evidentira se korištenjem stilskih klasa.
219
Primjer: FirmaMVC \ Views \ Artikl \ EditAjax.cshtml
<td colspan="2">
<span class="error">@TempData["Pogreska"]</span>
@Html.ValidationSummary()
</td>
<td>
<input type="text" value="@Model.NazArtikla"
data-sifartikla="@Model.SifArtikla" class="nazartikla" />
</td>
<td>
<input type="text" value="@Model.JedMjere"
data-sifartikla="@Model.SifArtikla" class="jedmjere" />
</td>...
<input type="button" value="Spremi"
class="saveajax" data-sifartikla="@Model.SifArtikla" />
...
$(function () {
$(".saveajax").click(function () {
var sifartikla = $(this).data('sifartikla');
var nazartikla = $(".nazartikla[data-sifartikla='" +
sifartikla + "']").val();
...
var zastusluga = $(".zastusluga[data-sifartikla='" +
sifartikla + "']").is(':checked');
var url = '@Url.Action("EditAjax")';
var tr = $(this).parents("tr");
Klikom na kontrolu označenu stilskom klasom saveajax dolazi do slanja podataka (koristi se
jQueryjeva funkcija $.post) nakon čega se sadržaj trenutnog retka zamijeni rezultatom akcije.
Ako je snimanje bilo uspješno vraća se parcijalni pogled Show, a u protivnom se iscrtava parcijalni
pogled EditAjax te se ispisuju validacijske pogreške.
220
Primjer: FirmaMVC \ Controllers \ ArtiklController.cs
[HttpPost]
public ActionResult EditAjax(Artikl artikl) {
Artikl original = ...dohvat artikla iz baze...
try{
… izmjena vrijednosti originalnom objektu
ModelState.ValidateBusinessObject(original);
if (ModelState.IsValid) {
bll.Save(original);
return RedirectToAction("Show",...
}
}
catch (Exception exc) {
TempData["Pogreska"] = exc.Message;
}
return PartialView(original);
}
Klikom na gumb Odustani sadržaj retka se mijenja rezultatom akcije Show pri čemu je potrebno
ponovno postaviti povezivanja za novoučitane elemente.
[$(function () {
$(".cancelajax").click(function () {
var sifartikla = $(this).data('sifartikla');
var url = '@Url.Action("Show",
new { page = ViewBag.CurrentPage })';
var tr = $(this).parents("tr");
Brisanje artikla Ajax pozivom vrši se isključivo POST postupkom koji prima šifru artikla (parametar id u
postupku brisanja). Postupak brisanja vraća JSON koji je nastao iz anonimne klase koja ima dva
svojstva: svojstvo Successful za informaciju da li je postupak brisanja uspio i svojstvo ErrorMessage
koji sadrži eventualni opis pogreške.
221
Primjer: FirmaMVC \ Controllers \ ArtiklController.cs
[HttpPost]
public JsonResult DeleteAjax(int id) {
var result = new { Successful = true,
ErrorMessage = string.Empty };
try {
...
artikl.Delete();
bll.Save(artikl);
}
catch (Exception exc) {
result = new { Successful = false,
ErrorMessage = exc.Message };
}
return Json(result);
}
Brisanje je pozvanom klikom na gumb i potvrdom brisanja, nakon čega je uslijedio POST zahtjev
(adresa zahtjeva i id su prethodno pripremljeni). U slučaju uspješnog brisanja redak u kojem je bio
artikl uklanja se iz strukture stranice, a u protivnom se ispisuje poruka o pogrešci.
222
Slika 101. Prikaz dokumenta sa stavkama
Index – akcija koja služi kao početna stranica koja preusmjerava zahtjev na akciju Create ili
Details u ovisnosti postoji li barem jedan dokument u bazi podataka ili ne.
Create – sadrži GET i POST varijantu za unos novog dokumenta te koristi pogled u View \
Dokument \ Create.cshtml. Postupak u POST varijanti prima Dokument kao parametar.
Details – prikazuje jedan dokument i sve njegove stavke. Odabir dokumenta vrši se tako da je
proslijeđen parametar za broj stranice, a svaka stranica sadrži samo jedan dokument, pa se
de facto radi o dohvatu n-tog dokumenta. Za prikaz koristi se pogled View \ Dokument \
Details.cshtml
Edit – akcija za ažuriranje dokumenta koja sadrži GET i POST varijante za ažuriranje. GET
varijanta prima id dokumenta kojeg treba ažurirati i trenutnu stranicu kako bi se nakon
ažuriranja mogao ponovo prikazati isti dokument. POST varijanta prima dokument i listu
logičkih (bool) vrijednosti naziv BrisiStavku koje predstavljaju stavke koje treba ukloniti iz
dokumenta. I-ti redak stavke u u pogledu View \ Dokument \ Edit.cshtml sadrži checkbox
naziva BrisiStavku[i] što se onda automatski povezuje u parametar polja logičkih varijabli
naziva BrisiStavku.
Delete – akcija za brisanje dokumenta koja ima samo POST varijantu, a ovisnosti o uspješnosti
brisanja dokumenta rezultat preusmjerava na akciju Index ili Details u slučaju pogreške.
DodajStavku – akcija za dodavanje stavke u dokument sa samo POST varijantom koja prima
podatke o novoj stavci i nakon dodavanja preusmjerava izvršavanje na akciju Details
223
ObrisiStavku – akcija za brisanje stavke iz dokumenta sa samo POST varijantom koja prima id
dokumenta i id stavke koju treba obrisati. Nakon brisanja dolazi do preusmjeravanja na akciju
Details.
Kod većine akcija koristi se parametar page kako bi se nakon akcije mogao prikazati trenutni (a nakon
brisanja prethodni) dokument. Za dohvat dokumenta koristi se postupak FetchFromPosition iz BLL
sloja. Postupkom se vrši dohvat 1 podatka počevši od neke stranice što je zapravo dohvat n-tog
dokumenta.
Kao model za prikaz dokument koristi se pomoćni razred koji sadrži pojedinačni dokument i
informacije o straničenju.
Prilikom dohvata dokumenta dolazi i do dohvata njegovih stavki (što je obavljeno u poslovnom sloju),
podaci pripremaju za straničenja te se vrši priprema padajućih listi za odabir artikla u stavkama.
Padajuće liste nisu dio modela, nego se prenose kroz ViewBag.
224
Primjer: FirmaMVC \ Controllers \ DokumentController.cs
@Html.DropDownList("SifArtikla",
new SelectList(ViewBag.Artikli, "Key", "Text"),
new { @class = "ddlartikl" }
)
Brisanje pojedine stavke, brisanje dokumenta i dodavanje stavki izvedeni su slično kao u primjeru za
Mjesto. Specifičnost ovog primjeru su ažuriranje dokumenta i stavki te validacija.
Napomena: Ažuriranje stavki vrši se kad i ažuriranje dokumenta, posebnom akcijom.
...
@Html.HiddenFor(m => m.Stavke[i].JedCijArtikla)
...
@Html.DropDownList("SifArtikla",
new SelectList(ViewBag.Artikli, "Key", "Text"),
new { @class = "ddlartikl" }
)
...
Obriši stavku: @Html.CheckBox("BrisiStavku[" + i + "]")
Za svaku stavku stvorit će se checkbox kontrola koja označava treba li obrisati stavku ili ne pri čemu
su nazivi ovih kontrola oblika BrisiStavku[0…broj stavki] te upravljač prima listu logičkih vrijednosti
naziva BrisiStavku.
225
Primjer: FirmaMVC \ Controllers \ DokumentController.cs
[HttpPost]
public ActionResult Edit(int page,
Dokument dokument, List<bool> BrisiStavku) {
...
14.8 Zadaci
Zadatak 1. Čemu služi model, čemu pogled a čemu upravljač?
Zadatak 2. Gdje se u modelu arhitekture MVC nalazi poslovna logika?
Zadatak 3. Treba li validacija podataka biti bliže prezentacijskom ili sloju pohrane podataka?
226
15 Web servisi
Način razvoja dijeljenih aplikacija mijenjao se kroz povijest. U razdoblju strukturiranog razvoja mogle
su se višekratno iskoristiti samo funkcije neovisne o (globalnim) podacima. Pojavom objektno
orijentiranog razvoja podaci i ponašanje se objedinjuju u objekte, ali problem dijeljenja je ostao isti –
mogao se dijeliti samo izvorni programski kod pisan u istom jeziku. Eventualna razmjena podataka
odvijala se korištenjem TCP-a ili slične tehnologije pri čemu u toj komunikaciji nije bilo veće koristi od
objektno orijentirane tehnologije. S vremenom pojavljuju se statičke biblioteke (.lib) i dinamičke
biblioteke (.dll) funkcija koje se mogu dijeliti između više aplikacija. Početkom devedesetih pojavljuje
se Component Object Model (COM), a kasnije i DCOM (Distributed Component Object Model), a
kasnije i.NET Remoting kao načini razmjene podataka između aplikacija pri čemu umjesto dijeljenja
izvornog koda klijent i server imaju dogovoren binarni tip podataka u razmjeni35. Iako su navedeni
pristupi predstavljali napredak, patili su od značajnih problema kao što je problem verzioniranja
(engl. DLL hell). Konačno, početkom ovog stoljeća pojavljuje servisno orijentirana arhitektura (engl.
Service Oriented Architecture, SOA) kao koncept koji će omogućiti distribuirane aplikacije između
različitih platformi koje komuniciraju razmjenom podataka među servisima.
Servis je jedna ili više funkcionalnih komponenti (ili cijeli sustav) s kojim se komunicira putem javno
objavljenih i precizno definiranih sučelja. Komunikacija je moguća između heterogenih klijenata, a
sam servis funkcionira na principu crne kutije - implementacija je skrivena od javnosti. Servis prima
jedan ili više zahtjeva i vraća jedan ili više odgovora. Za komunikaciju se koriste otvoreni web
standardi: HTTP, XML, SOAP itd.
Servisno orijentirana arhitektura je skup precizno definiranih, međusobno neovisnih servisa
povezanih u logički jedinstvenu aplikaciju. Kao što objektno orijentirana aplikacija povezuje objekte,
tako servisno orijentirana arhitektura povezuje servise stvarajući distribuirani sustav u kojem
sudjeluje više autonomnih servisa međusobno šaljući poruke preko granica određenih procesom,
mrežom, i dalje.
Pri izradi servisa potrebno je voditi računa o interoperabilnosti i sigurnosti komunikacije (tko sve
može i smije pozvati servis), problemu višenitnosti, brzini obrade postupka i mogućnostima
skalabilnosti. Neuspjeh prilikom izvršavanja servisa ne smije ostaviti sustav u stanju pogreške
(konzistentnost stanja). Servis mora odlikovati pouzdanost i robusnost. Pogreške u servisu treba
obraditi, a klijent treba znati je li servis primio i obradio poruku.
35
Za detaljnije pogledati A Brief History of the Microsoft Distributed Stack, N. Pathak: Pro WCF 4, Apress
227
neutralni, a tipovi specifični za pojedini jezik moraju se moći pretvoriti u neutralni oblik i
obrnuto. Implementacijski postupci ostaju tajna
Semantika, a ne samo sintaksa: Servise je potrebno smisleno imenovati i logički
kategorizirati
228
15.4 Primjer web servisa
U primjeru WCF \ KlasicniWebServis izrađen je klasični web servis s postupkom koji vraća popis
država. Klasični web servis izrađuje se unutar web aplikacije odabirom opcije Add New Item Web
Service čime se stvaraju dvije datoteke ekstenzija asmx i asmx.cs, a konkretni kod servisa piše se u
datoteci ekstenzije asmx.cs. Po potrebi je moguće dodati i dodatne razrede za razmjenu podataka, pa
je tako u ovom primjeru dodana datoteke Drzava s 3 svojstva (Naziv, Oznaka, ISO3 oznaka države)
koji se koriste u rezultatu.36
Kako bi neki postupak u razredu bio ujedno i postupak web servisa potrebno je dodati atribut
WebMethod.
Class PROVJERI
[WebMethod]
public List<Drzava> PopisDrzava() {
List<Drzava> list = new List<Drzava>();
var bll = new Firma.DrzavaBllProvider();
foreach (var d in bll.FetchAll()) {
list.Add(new Drzava {
Naziv = d.NazDrzave,
Oznaka = d.OznDrzave,
Iso3Oznaka = d.ISO3Drzave
});
}
return list;
}
…
36
Razred Drzava iz Firma.BLL sadrži podatke koji se žele koristiti u razmjeni podataka, ali taj razred se ne može
serijalizirati u XML bez dodatnih modifikacija.
229
Slika 104. Koncept izrade proxy klase za komunikaciju s web servisom
Referenciranje web servisa iz projekta vrši se desnim klikom na projekt i odabirom opcije Add Web
Reference → Add Service Reference i unosom imena za prostor imena pod kojim će se proxy
generirati, nakon čega na disku nastaje nekoliko datoteka (wsdl, disco, …), a u datoteci app.config se
stvaraju zapisi o postavkama komunikacije (način povezivanja, adresa servisa, maksimalna veličina
poruke, …).
Slika 105. Koraci prilikom dodavanja reference na web servis u razvojnom okruženju
230
S obzirom da proxy u kombinaciji s postavkama iz konfiguracijske datoteke skriva složenost
komunikacije sa servisom, poziv iz koda je nalik pozivu bilo koje druge metode u projektu.
Web servis iz gornjeg primjera će vratiti xml koji predstavlja (serijaliziranu) listu država. Svaki svojstvo
objekta koji je sadržan u rezutatu se, ako drugačije nije navedeno, posprema kao istoimeni element u
povratnom xml-u. Promjena strukture xml-a moguće je korištenjem atributa kao u sljedećem
primjeru.
[XmlType("D")]
public class Drzava{
[XmlElement("Ozn")]
public string Oznaka { get; set; }
public string Naziv { get; set; }
[XmlAttribute("ISO3")]
public string Iso3Oznaka { get; set; }
}
U ovom slučaju u povratnom xml-u Iso3Oznaka će se umjesto kao element pospremiti kao atribut
elementa oznake D (umjesto Drzava), a naziv elemeta koji sadrži vrijednost svojstva Oznaka bit će
Ozn. Generirani omotač na klijentu u ovom slučaju ima razred D, a ne razred Drzava. Ako se neko
svojstvo želi isključiti iz serijalizacije, potrebno je upotrijebiti atribut [XmlIgnore], što može biti i
nužno ako se neko svojstvo ne može serijalizirati u xml (npr. Hashtable).37
37
Atribut Serializable nije potreban ako se radi o xml serijalizaciji. Potreban je ako se koristi binarna
serijalizacija
231
15.5 WCF servisi
WCF (engl. Windows Communication Foundation) je radni okvir za izradu naprednijih oblika (web)
servisa, pri čemu servis ne mora nužno biti web servis, to jest mogu se koristiti različiti protokoli
komunikacije (HTTP, TCP, Net pipes, …). WCF servisi baziraju se na tzv. ABC prinicipu (skraćenica
Address, Binding i Contract). Adresa i način povezivanja odvojeni su od podataka i konkretne
implementacije servisa i uobičajeno su zapisani u konfiguracijskim datotekama (web.config,
app.config). Ugovor se sastoji od skupa sučelja s postupcima servisa i razreda za podatke koji
sudjeluju u razmjeni podataka. Ugovor sadrže obje strane u komunikaciji i neovisan je o adresi i
načinu povezivanja. Na ovaj način postiže se jasnije odvajanje razreda za komunikaciju te je
jednostavnije promjena razreda, implementacije servisa ili smještaja servisa.
WCF servis se razvija na način da se prvo definira ugovor, nakon čega se mogu istovremeno razvijati i
servis i klijent, a zatim slijedi implementacija ugovora i izlaganje WCF servisa u kojem se određuju
adresa, ponašanje i način povezivanja s pristupnim točkama servisa. U primjerima koji slijede ugovor,
implementacija i smještaj su podijeljeni u tri odvojena projekta pri čemu su ugovor i implementacija
projekti tip Class Library, a smještaj je prikazan s 2 primjera projekta (web aplikacija i windows
aplikacija)
232
netPeerTcpBinding P2P komunikacija u kojoj svaki čvor je ujedno klijent i server
prema ostalim sudionicima
netMsmqBinding Povezivanje za asinkronu komunikaciju između klijenta i
servisa
msmqIntegrationBinding Omogućava komunikaciju sa postojećim sustavima koji
komuniciraju koristeći MSMQ
[ServiceContract]
public interface IFirmaServis {
[OperationContract]
List<Drzava38> PopisDrzava();
[OperationContract]
List<Osoba> PopisOsoba();...
Implementacija sučelja je izvedena u zasebnom projektu koji referencira projekt s ugovorom (i ostale
potrebne dll-ove). Implementacija ne ovisi o načinu povezivanja, a po potrebi se može koristiti i kao
obični dll (ne mora nužno biti izložena kao servis)
38
WCF podržava naprednije načine serijalizacije, pa se može iskoristiti razred Drzava iz poslovnog sloja, što nije
moguće kod klasičnog servisa zbog svojstva BLLProvider koji je tipa IBllProvider.
233
Primjer: WCF \ ImplementacijaUgovora \ FirmaServis.cs
Konkretna implementacija nekog WCF ugovora izlaže se (udomljuje, engl. host) unutar neke web ili
windows aplikacije. U sljedećem primjeru korištena je prazna web aplikacija (ne mora nužno biti
korištena samo za WCF servis) koja referencira projekt koji sadrži implementaciju ugovora, a u
datoteci web.config navodi se naziv konkretne implementacije i relativna adresa na kojoj će se WCF
servisi nalaziti.
<system.serviceModel>
...
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="Firma.svc"
service="ImplementacijaUgovora.FirmaServis"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
Bez dodatnih postavki ovako definiran WCF servis je dostupan kao web servis na adresi
http://.../Firma.svc uz pretpostavljeni način povezivanja (basicHttpBinding). Servis je sada dostupan
svima koji imaju njegovu definiciju u obliku wsdl dokumenta ili dll projekta koji predstavlja ugovor
servisa.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
234
Da bi servis automatski nudio prikaz wsdl-a potrebno je omogućiti razmjenu metapodataka (engl.
Metadata exchange - MEX) nakon čega se wsdl biti dostupan na adresi http://.../Firma.svc?wsdl.
Proxy kod za poziv servisa može se u tom slučaju kreirati naredbom
svcutil.exe http://.../Firma.svc?wsdl
235
Primjer: WCF \ PrimjeriPoziva \ app.config
<system.serviceModel>
...
<binding name="BasicHttpBinding_IFirmaServis" />
...
<client>
<endpoint address="http://localhost:609339/Firma.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IFirmaServis"
contract="FirmaWebServis.IFirmaServis"
name="BasicHttpBinding_IFirmaServis" />
</client>
Generirani proxy sadrži i razred koji služi kao klijent za poziv web servisa. Razred sadrži sve postupke
iz ugovora, kao i njihove asinkrone varijante.
Prilikom dodavanje reference na servis uobičaljeno je uključena opcija Reuse types in all referenced
assemblies. Ako projekt u kojem se referencira WCF servis ujedno ima referenciran dll ugovora WCF
servisa, onda ne dolazi do stvaranja novih razreda (u primjeru je referenciran Ugovor.dll, pa se koristi
Ugovor.Osoba), a inače se kreiraju razredi istih imena, ali različitog prostora imena oblika
NazivProjekta.NazivReference (npr. PrimjeriPoziva.FirmaWebServis pri čemu je
FirmaWebServis.Drzava ≠ Firma.Drzava).
39
Web aplikacija s WCF servisom je u ovom primjeru postavljena na privremenom web serveru kojem je Visual
Studio inicijalno dodijelio slučajno odabrani port, što se po potrebi može promijeniti u projektnoj
konfiguracijskoj datoteci (.csproj)
236
Primjer: WCF \ PrimjeriPoziva \ FormWCF
<system.serviceModel>
<client>
<endpoint contract="Ugovor.IFirmaServis"
name="FirmaEndPointWebServis"
address="http://localhost:6093/Firma.svc"
binding="basicHttpBinding" />
<endpoint contract="Ugovor.IFirmaServis"
name="FirmaEndPointLokalno"
address="net.pipe://localhost/FirmaServis"
binding="netNamedPipeBinding" />
</client>
</system.serviceModel>
Postavke WCF klijenta navode se programski ili u konfiguracijskim datotekama. Radi bolje
preglednosti mogu se izdvojiti u posebnu konfiguracijsku datoteku koja se uključi iz datoteke
web.config (npr. <system.serviceModel> <bindings configSource="ime.config" />…). WCF postavke u
konfiguracijskoj datoteci mogu se pregledavati i mijenjati i posebnim alatom koji se može pokrenuti iz
Visual Studia odabirom opcije Tools → WCF Service Configuration Editor.
U slučaju da se lokacija i način izlaganja WCF servisa promijeni potrebno je samo promijeniti postavke
pristupne točke, što se može ilustrirati primjerom u kojem je smještaj implementacije ugovora unutar
237
Windows aplikacije pri čemu se za povezivanje koristi cjevovod (prikladno ako su i servis i klijent na
istom računalu). Za izlaganje WCF servisa koristi se razred ServiceHost.
ServiceHost host =
new ServiceHost(typeof(ImplementacijaUgovora.FirmaServis),
new Uri[] { new Uri("net.pipe://localhost") });
host.AddServiceEndpoint(typeof(Ugovor.IFirmaServis),
binding, "FirmaServis");
host.Open();
Na klijentu je sada potrebno samo promijeniti parametre pristupne točke, tj. odabrati pristupnu
točku s nekim drugim nazivom u konfiguracijskoj datoteci (u ovom slučaju FirmaEndPointLokalno
umjesto FirmaEndPointWebServis).
[DataContract]
public class Mjesto {
[DataMember]
public int Pbr { get; set; }
public string NazMjesta { get; set; }
[DataMember]
public string NazDrzave { get; set; }
[DataMember]
public string PostNazMjesta { get; set; }
}
Posebnu pažnju treba obratiti na situacije kada stvarni tipovi povratnih vrijednosti nisu unaprijed
poznati kao što se slučaj u situacijama kada postupak servisa za rezultat ima tip sučelja ili neki od
baznih razreda ili Object kao vršni razred.
238
Konkretna implementacija servisa tada može vratiti izvedeni razred ili implementaciju sučelja, ali
klijent primljeni podatak ne bi mogao ispravno deserijalizirati jer ne bi imao informaciju o tipu
podataka koji odgovara serijaliziranim podacima. Za takve slučajeve potrebno je najaviti moguće
povratne tipove (osim ako se ne radi o primitivnim tipovima). Navođenje tipova vrši se korištenjem
atributa KnownType i ServiceKnownType pri čemu se navode svi poznati izvedeni razredi nekog
razreda ili sučelja. Atribut KnownType stavlja se ispred povratnog tipa, a atribut ServiceKnownType
ispred postupka servisa.
U sljedećem primjeru prikazano je navođenje svih izvedenih tipova iz razreda Partner ispred postupka
koji vraća popis partnera.
[OperationContract]
[ServiceKnownType(typeof(Osoba))]
[ServiceKnownType(typeof(Tvrtka))]
List<Partner> PopisPartnera();
Alternativa navođenju svih poznatih tipova unutar atributa (Service)KnownType je napisati razred i
postupak koji vraća sve poznate tipove podatka, a u atributu ServiceKnowType navesti naziv
postupka koji vraća tip izvedenog razreda. Praktična alternativa može biti i navođenje poznatih tipova
u konfiguracijskog datoteci kao u donjem primjeru čime se izbjegava potreba za izmjenom izvornog
koda servisa. Poznate tipove je u tom slučaju potrebno navesti u konfiguracijskim datotekama i na
serveru i na klijentu.
Primjer:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Ugovor.Partner,Ugovor">
<knownType type="Ugovor.Osoba,Ugovor" />
<knownType type="Ugovor.Tvrtka,Ugovor" />
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
239
Primjer: WCF \ Ugovor \ IFirmaServis.cs
[OperationContract]
[FaultContract(typeof(Pogreska))]
string PostupakSPogreskom(VrstaPogreske vrsta);
Dodatne mogućnosti obrade pogrešaka mogu se postići korištenjem sučelja IErrorHandler. Primjer
klijenta koji ispravno rukuje iznimkama prikazan je sljedećim programskim odsječkom.
try{
using (ChannelFactory<Ugovor.IFirmaServis> factory = new
ChannelFactory<Ugovor.IFirmaServis>(endPointName)) {
240
Primjer: WCF \ PrimjeriPoziva \ app.config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Prilagodjeno" maxBufferPoolSize="5000000"
maxReceivedMessageSize="5000000"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="FirmaEndPointWebServis"
contract="Ugovor.IFirmaServis"
address="http://localhost:6093/Firma.svc"
binding="basicHttpBinding" bindingConfiguration="Prilagodjeno"
/>
241
Primjer: WCF \ Ugovor \ IFirmaServis.cs
[OperationContract]
[WebGet(UriTemplate = "GetOsoba/{idOsobe}",
BodyStyle=WebMessageBodyStyle.Wrapped)]
Osoba DohvatiOsobu(string idOsobe);
U prethodnom primjeru, uz pristupnu točku na adresi rest (vidi definiciju pristupne točke u primjeru
ispod) pozivom url-a http://localhost:6093/Firma.svc/rest/GetOsoba/10 izvršit će se postupak
DohvatiOsobu za osobu s id-om osobe 10. Svojstvo BodyStyle određuje da li će rezultat biti dodatno
ugniježđen unutar xml ili json elementa.
Ako se u se u konfiguracijskoj datoteci ne navede niti jedna pristupna točka podrazumijeva se
pristupna točka s načinom povezivanja basicHttpBinding. Navođenjem bilo koje druge pristupne
točke ova podrazumijevana vrsta povezivanja se gubi te je po potrebi treba eksplicitno definirati. Ista
implementacija servisa može biti izložena na više načina povezivanja, ali na različitim adresama. U
konfiguracijskoj datoteci navodi se naziv razreda implementacije te sve pristupne točke. Za svaku
točku se navodi relativna adresa, razred ugovora i način povezivanja te opcionalno naziv postavki
ponašanja (behaviorConfiguration). Za pristupnu točku za koju adresa nije navedena koristi se prazni
string.
<services>
<service name="ImplementacijaUgovora.FirmaServis">
<endpoint binding="basicHttpBinding"
contract="Ugovor.IFirmaServis"/>
<endpoint address="rest" binding="webHttpBinding"
contract="Ugovor.IFirmaServis"
behaviorConfiguration="restBehaviour" />
</service>
</services>
242
Primjer: WCF \ SmjestajWebApp \ web.config
<endpointBehaviors>
<behavior name="restBehaviour">
<!-- <webHttp defaultOutgoingResponseFormat="Json" /> -->
<webHttp automaticFormatSelectionEnabled="true" />
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
Za ostale zahtjeve osim GET, koristi se atribut WebInvoke kojim se može definirati putanja do
postupka i parametri koji se prenose kroz adresu postupka40 (atribut UriTemplate), vrsta metode
HTTP zahtjeve (atribut Method pretpostavljane vrijednosti POST), format ulaza i izlaza servisa
(atributi RequestFormat i ResponseFormat) ako je potrebno da budu drugačiji od ostalih postupka i
postavki u konfiguraijskoj datoteci te stil odgovara (atribut BodyStyle) kojim se određuje da li je
rezultat dodatno omotan u jedan vršni element ili ne.
[OperationContract]
[WebInvoke(UriTemplate="UpdateOsoba/{idOsobe}", Method = "PUT",
BodyStyle = WebMessageBodyStyle.Bare)]
Osoba AzurirajOsobu(string idOsobe, Osoba o);
40
Poruka servisa, tj. ostali podaci su sadržani u POST ili PUT dijelu zahtjeva
243
15.6.3 Primjer poziva REST servisa iz .NET klijenta
Za poziv REST servisa iz .NET klijenta koristi se razred HttpClient te proširanja iz assemblyja
System.Net.HttpFormatting za automatsku deserijalizaciju iz XML-a i JSON-a u željeni razred i
obrnuto. Razred HttpClient nudi asinkrone metode za komunikaciju s web stranicom ili web servisom
i to za sve 4 vrste HTTP zahtjeva: GetAsync, PostAsync, PutAsync, DeleteAsync, a moguća je i
automatska serijalizacija u XML ili JSON kod PUT i POST zahtjeva metodama PostAsJsonAsync,
PostAsXmlAsync, PutAsJsonAsync, PutAsXmlAsync te kod GET zahtjeva metoda ReadAsAsnyc. U
sljedećem primjeru prikazani su odsječak koda za dohvat popisa osoba pri čemu klijent želi rezultat u
JSON formatu te odsječak koda za ažuriranje podatka o osobi.
244
Slika 109. Primjer rada s alatom Fiddler
15.6.5 WebApi
WebApi predstavlja okvir za razvoj REST servisa. Struktura projekta nalik je ASP.Net MVC-u te ima
postavke usmjeravanja i upravljače pri čemu su API upravljači izvedeni iz razreda ApiController.
245
Primjer: WCF \ WebApi \ App_Start \ WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
U odnosu na WCF WebAPI je prikladan za sve preglednike i mobilne uređaje i nudi veću podršku za
REST, primjerice naprednije mogućnosti formiranja URL-a. Dodatno, izrada REST servisa je
jednostavnija s WebAPI-em. Prednost WCF-a nad WebAPI-jem je podrška za više protokola, a ne
samo HTTP i mogućnosti definiranja vlastitog protokola. WCF podržava više formata sadržaja (i tekst i
binarni sadržaj), nudi naprednije sigurnosne mehanizme. Dodatno WCF se jednostavnim dodavanjem
atributa može koristiti istovremenom i kao WCF i kao REST servis, pri čemu se proxy klijent WCF
servisa može automatski generirati na osnovu WSDL-a.
15.7 Zadaci
Zadatak 1. Što je proxy?
Zadatak 2. Koje protokole povezivanja podržava WCF?
Zadatak 3. Što je posebnost/prednost REST servisa?
246
16 Reference
16.1 Literatura
1. A Guide to the Project Management Body of Knowledge (PMBOK® Guide) , 5th edition,
Project Management Institute, 2013.
2. Code Complete, 2nd edition, Steve McConnell, Microsoft Press, 2004.
3. Configuration Management Best Practices, Aiello & Sachs, Addison-Wesley, 2010.
4. Effective Project Management: Traditional, Adaptive, Extreme 7th ed., Wysocki, R. K. , Wiley,
2014.
5. Inside C#, Tom Archer 2ed, Microsoft Press, 2002.
6. ISO/IEC/IEEE 24765:2010 Systems and software engineering—Vocabulary
7. ISO/IEC/IEEE 29148:2011 Systems and software engineering —Life cycle processes--
Requirements engineering
8. Professional Application Lifecycle Management with Visual Studio® 2013, Gousset et.al, John
Wiley & Sons, Inc., 2014.
9. Software Engineering: A Practitioner's Approach, 7th edition, Pressman R. S., R. S. Pressman
& Associates, Inc., 2010.
10. Software Engineering 10ed, Sommerville I., Pearson, 2015.
247