📖 Uvod u MVC Pattern
Model-View-Controller (MVC) je arhitekturni pattern koji razdvaja aplikaciju u tri glavne komponente: Model (podaci i poslovna logika), View (korisnički interfejs) i Controller (koordinator između Modela i View-a). Ovaj pristup omogućava bolju organizaciju koda, testabilnost i održivost aplikacije.
🔑 Zašto MVC?
MVC pattern omogućava separation of concerns - svaka komponenta ima jasno definisanu odgovornost. Ovo znači da možete mijenjati View bez uticaja na Model, ili dodati novu funkcionalnost bez mijenjanja postojećeg koda.
🏗️ Tri Glavne Komponente MVC-a
1. Model - Poslovna Logika i Podaci
Model predstavlja poslovnu logiku i podatke aplikacije. On je odgovoran za:
- Validaciju podataka
- Pristup bazi podataka (obično kroz Entity Framework)
- Poslovna pravila i logika
- Reprezentaciju entiteta iz baze podataka
// Models/Department.cs (Stats.Departments)
namespace JavnaUprava.Models
{
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("Departments", Schema = "Stats")]
public class Department
{
[Key]
public int DepartmentID { get; set; }
[Required(ErrorMessage = "Naziv ministarstva je obavezan")]
[StringLength(100)]
[Display(Name = "Naziv Institucije")]
public string DepartmentName { get; set; }
[Required]
[StringLength(20)]
public string DepartmentCode { get; set; } // Npr. "MF", "MUP"
[Range(0, double.MaxValue, ErrorMessage = "Budžet mora biti pozitivan")]
[DataType(DataType.Currency)]
public decimal Budget { get; set; }
// Poslovna logika
public bool IsHighBudget()
{
return Budget > 10000000;
}
}
}
2. View - Korisnički Interfejs
View je odgovoran za prikaz podataka korisniku. U ASP.NET MVC, Views se kreiraju koristeći Razor sintaksu - kombinaciju HTML-a i C# koda.
- Prikazuje podatke iz Modela
- Ne sadrži poslovnu logiku
- Koristi Razor sintaksu za dinamički sadržaj
- Može koristiti Layout stranice za konzistentan dizajn
@* Views/Departments/Index.cshtml *@
@model IEnumerable<JavnaUprava.Models.Department>
<h2>Registar Državnih Institucija</h2>
<table class="table">
<thead>
<tr>
<th>Šifra</th>
<th>Institucija</th>
<th>Budžet (KM)</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@foreach (var dept in Model)
{
<tr>
<td>@dept.DepartmentCode</td>
<td>@dept.DepartmentName</td>
<td>@dept.Budget.ToString("C")</td>
<td>
@if(dept.IsHighBudget()) {
<span class="badge bg-warning">Visoki Prioritet</span>
} else {
<span class="badge bg-secondary">Standard</span>
}
</td>
</tr>
}
</tbody>
</table>
3. Controller - Koordinator
Controller prima korisničke zahtjeve, komunicira sa Modelom, i vraća odgovarajući View. On je "mozak" aplikacije koji odlučuje šta će se desiti kada korisnik klikne na dugme ili otvori URL.
- Prima HTTP zahtjeve
- Poziva Model za podatke ili poslovnu logiku
- Odlučuje koji View prikazati
- Vraća ActionResult (View, Redirect, JSON, itd.)
// Controllers/DepartmentsController.cs
using System.Web.Mvc;
using JavnaUprava.Models;
namespace JavnaUprava.Controllers
{
public class DepartmentsController : Controller
{
// GET: Departments
public ActionResult Index()
{
// Simulacija dohvatanja iz baze (StateStatisticsDB)
var departments = GetDepartmentsFromDb();
// Vraćamo View sa listom ministarstava
return View(departments);
}
// GET: Departments/Details/1
public ActionResult Details(int id)
{
var dept = GetDepartmentById(id);
if (dept == null)
{
return HttpNotFound();
}
return View(dept);
}
private List<Department> GetDepartmentsFromDb()
{
return new List<Department>
{
new Department { DepartmentID = 1, DepartmentName = "Ministarstvo Finansija", DepartmentCode = "MF", Budget = 50000000 },
new Department { DepartmentID = 2, DepartmentName = "Ministarstvo Obrazovanja", DepartmentCode = "MO", Budget = 30000000 }
};
}
}
}
🏛️ Konceptualni Okvir: Web Forms nasljeđe
ASP.NET Web Forms je bio pokušaj Microsofta da programerima koji su navikli na desktop aplikacije (poput VB6 ili WinForms) omogući da prave veb stranice na sličan način. Glavna ideja bila je sakriti kompleksnost HTTP protokola, koji je po svojoj prirodi stateless (ne pamti stanje između dva klika).
Evo kako je ta "magija" funkcionisala i zašto je to bila i prednost i prokletstvo.
1. Osnovni mehanizam: Postback
U Web Forms svijetu, skoro svaka interakcija (klik na dugme, promjena u padajućem meniju) slala je podatke nazad na istu tu stranicu. To se zove Postback.
Umjesto da ideš na novi URL, ti šalješ HTTP POST zahtjev samom sebi. Server tada ponovo kreira
cijelu stranicu, izvršava tvoj kod (npr. Button_Click) i vraća HTML nazad u browser.
2. ViewState: Memorija sakrivena u HTML-u
Pošto server "zaboravi" sve čim pošalje HTML browseru, Web Forms je koristio ViewState da bi održao privid stanja.
- Šta je to? To je ogromno skriveno polje u HTML-u (
<input type="hidden" id="__VIEWSTATE" ... />). - Kako radi? Svi podaci o tvojim kontrolama (šta piše u labeli, koja je boja dugmeta, šta je u tabeli) serijalizuju se u Base64 string i smještaju u to polje.
- Krug razmjene: Kada klikneš na dugme, browser šalje taj ogromni string nazad serveru. Server ga "otpakuje", rekonstruiše stanje kontrola kakvo je bilo, izvrši tvoju logiku, "upakuje" novo stanje i šalje ga nazad.
3. Ostali načini razmjene informacija
Pored ViewState-a, koristili su se i standardni mehanizmi:
- Session State: Podaci se čuvaju na serveru (u memoriji), a browser samo nosi ID sesije u kolačiću.
- QueryString: Podaci u URL-u (
stranica.aspx?id=5). - ControlState: Slično ViewState-u, ali rezervisano za kritične podatke kontrole koji se ne mogu isključiti.
Glavni izazovi i problemi
Iako je Web Forms omogućio brzi razvoj ("drag-and-drop" kontrola), donio je ozbiljne probleme koji su na kraju doveli do popularnosti ASP.NET MVC-a i modernih frontend frameworka (React, Angular).
⚠️ Problemi Web Forms-a
- "Debeli" ViewState: Ako si imao veliku tabelu (GridView) sa hiljadama redova, ViewState bi mogao narasti na nekoliko megabajta. Korisnik bi pri svakom kliku morao da šalje i prima taj ogroman, beskoristan string, što je drastično usporavalo stranicu.
- Kompleksan Page Lifecycle: Redoslijed događaja (Init, Load, PreRender, Unload) bio je izuzetno komplikovan. Ako bi pokušao da učitaš podatke u pogrešnom koraku, aplikacija bi se ponašala nepredvidivo.
- Teško testiranje (Unit Testing): Zbog uske povezanosti (coupling) između UI-a i koda u "Code-behind" datoteci (.aspx.cs), bilo je gotovo nemoguće testirati logiku bez pokretanja cijelog servera.
- Kontrola nad HTML-om: Web Forms kontrole su same generisale HTML. Često bi generisale "ružan" ili nevalidan kod koji je bilo teško stilizovati CSS-om ili učiniti responzivnim.
- SEO i URL-ovi: URL-ovi su obično završavali sa
.aspx, što nije bilo optimalno za pretraživače u poređenju sa današnjim "clean" URL-ovima.
Rezime: Web Forms vs. Moderni pristup
| Karakteristika | ASP.NET Web Forms | Moderni Web (Web API + React/Angular) |
|---|---|---|
| Stanje | Čuva se u ViewState (klijent) ili Session (server) | Klijent (State management) i Stateless API |
| Razmjena podataka | Cijeli HTML se ponovo šalje (Postback) | Samo JSON podaci putem fetch/axios |
| Kontrola HTML-a | Ograničena (Serverske kontrole) | Potpuna kontrola na klijentskoj strani |
Web Forms je bio genijalan most iz svijeta desktopa u svijet veba, ali je cijena te apstrakcije bila prevelika za moderan, brzi internet.
1. ASP.NET MVC 5 (Zlatno doba .NET Frameworka)
MVC 5 je bio direktan odgovor na probleme Web Formsa. Donio je filozofiju Separation of Concerns (razdvajanje odgovornosti).
- Razmjena informacija: Nema više ViewState-a. Komunikacija je striktno Request-Response.
Backend -> Frontend:
- Model: Direktno prosljeđivanje objekta u View.
- ViewBag/ViewData: "Vreće" za podatke koje traju samo dok se stranica rendera.
- TempData: Podaci koji prežive tačno jedan idući Request (obično za poruke poput "Uspješno ste se registrovali" nakon redirecta).
Frontend -> Backend:
- Model Binding: Magija koja automatski mapira imena polja iz HTML forme
(
<input name="Naslov">) u parametre C# metode u kontroleru.
Izazovi: I dalje vezan isključivo za Windows i IIS server. Teško testiranje
globalnih objekata poput HttpContext.
2. Moderni .NET (.NET 9)
Moderni .NET (počevši od .NET Core-a do današnjeg .NET 9) je potpuno prepisan framework. Fokus je na performansama, modularnosti i "cloud-native" razvoju.
- Razmjena informacija: Sve je bazirano na Dependency Injection (DI) i Middleware arhitekturi.
Novi alati:
- Tag Helpers: Umjesto ružnih
@Html.TextBoxFor(...), pišeš čist HTML sa specijalnim atributima (<input asp-for="Naslov" />) koje server prepoznaje. - Minimal APIs: Za brzu razmjenu JSON podataka bez potrebe za teškim kontrolerima.
- Strongly Typed Settings: Konfiguracije (
appsettings.json) se razmjenjuju kroz cijeli sistem pomoću IOptions paterna. - Frontend trend: MVC se danas često koristi samo kao "ljepilo" ili za SEO optimizovane stranice, dok se prava razmjena informacija dešava preko Web API-ja (JSON) prema React/Angular/Vue aplikacijama.
Velika komparacija: Web Forms vs. MVC 5 vs. .NET 9
| Karakteristika | Web Forms | ASP.NET MVC 5 | Moderni .NET 9 |
|---|---|---|---|
| Glavni koncept | Event-driven (kao desktop) | Pattern-based (Request/Response) | Modularni, High-performance |
| Stanje (State) | ViewState (težak, u HTML-u) | Stateless (nema ViewState-a) | Stateless + Distributed Cache |
| HTML kontrola | Generisana (često "prljava") | Potpuna (Razor Helpers) | Potpuna (Tag Helpers / Blazor) |
| Testabilnost | Jako teška (Unit testovi skoro nemogući) | Dobra (razdvojen Controller) | Odlična (sve je "injectable") |
| Platforma | Samo Windows | Samo Windows | Windows, Linux, macOS, Docker |
| Performanse | Sporo (zbog težine stranice) | Brže | Ekstremno brzo (među najbržima) |
Ključna razlika u "filozofiji" razmjene podataka
- Web Forms: "Ja ću ti (server) dati sve što ti treba u jednom velikom ruksaku (ViewState). Ti mi ga vrati kad klikneš na nešto, ja ću ga dopuniti i poslati ti ga nazad."
- MVC 5: "Ti mi pošalji tačno šta želiš (Request), ja ću procesirati i poslati ti svježe nacrtan HTML (Response). Ništa ne pamtim između."
- Moderni .NET (API/Blazor): "Evo ti samo sirovi podaci (JSON). Ti (frontend) odluči kako ćeš to nacrtati. Ako trebaš nešto, javi mi se na API, ja sam tu samo da procesiram logiku."
Današnji izazov: SPA vs. SSR
Glavni izazov u .NET 9 nije više ViewState, već odluka:
- SSR (Server Side Rendering): Klasični MVC/Razor Pages – brži prvi učitaji, bolje za Google (SEO).
- Client-Side (SPA): React/Angular sa .NET API-jem – bolje korisničko iskustvo (nema refresha stranice), ali kompleksnija razmjena podataka (JWT tokeni, CORS, JSON serijalizacija).
1. ViewBag vs. ViewData vs. TempData
Iako sva tri služe za prenos informacija koje nisu dio glavnog Modela, razlikuju se po načinu pisanja i "roku trajanja".
| Karakteristika | ViewData | ViewBag | TempData |
|---|---|---|---|
| Tip podataka | Rječnik (Dictionary) objekata. | Dinamički objekat (C# Dynamic). | Rječnik (Dictionary) objekata. |
| Sintaksa |
ViewData["Kljuc"] = "Vrijednost";
|
ViewBag.Kljuc = "Vrijednost";
|
TempData["Kljuc"] = "Vrijednost";
|
| Provjera tipa | Zahtijeva casting (npr.
(string)ViewData[...]).
|
Nije potreban casting (provjerava se u runtime-u). | Zahtijeva casting. |
| Životni vijek | Samo tokom trenutnog HTTP zahtjeva. | Samo tokom trenutnog HTTP zahtjeva. | Preživljava jedan HTTP Redirect. |
| Glavna svrha | Brzi prenos sitnih podataka u View. | Isto što i ViewData, samo "ljepša" sintaksa. | Prenos poruka o uspjehu/grešci nakon Redirect-a. |
Zlatno pravilo: Ako želiš prenijeti nešto što će korisnik vidjeti nakon što ga server preusmjeri na drugu stranicu (npr. "Profil je uspješno ažuriran"), koristi TempData. Za sve ostalo unutar iste stranice, koristi ViewBag (ili još bolje, pravi ViewModel).
2. Od ViewState-a do .NET 9: Velika Retrospektiva
Evolucija .NET-a na webu je priča o borbi između jednostavnosti razvoja i kontrole nad protokolom.
Era 1: ASP.NET Web Forms (Simulacija Desktopa)
Početkom 2000-ih, Microsoft je želio privući Windows programere na web. Izmislili su Postback i ViewState.
- Koncept: Web je bio "lažno" pamtljiv. Svaki klik je slao ogromni enkriptovani string (ViewState) nazad serveru kako bi se održalo stanje dugmića i tabela.
- Izazov: Stranice su bile teške, HTML je bio nepredvidiv, a razvojni ciklus stranice (Page Lifecycle) bio je prava noćna mora za debagovanje.
Era 2: ASP.NET MVC 5 (Povratak korijenima HTTP-a)
MVC je srušio iluziju "desktopa na webu". Programeri su ponovo morali razumjeti GET i POST metode.
- Koncept: Uvedeno je strogo razdvajanje: Model (podaci), View (izgled), Controller (logika). Razmjena informacija se preselila na ViewBag i Model Binding.
- Izazov: Sistem je i dalje bio "zaključan" za Windows i IIS (Internet Information Services), što je limitiralo skalabilnost u modernom cloud okruženju.
Era 3: .NET 9 (Brzina, Cloud i Modularnost)
Današnji .NET je jedan od najbržih frameworka na svijetu. Više nije samo "Microsoftov alat", već open-source ekosistem koji radi svuda.
- Koncept: Fokus je na API-first pristupu. Backend više ne "crta" stranicu svaki put; on šalje sirovi JSON modernim frontendima (poput Reacta ili vašeg budućeg HyperLingua projekta). Ako se i koristi serversko renderovanje, tu su Tag Helpers koji čine kod čistim i čitljivim.
- Izazov: Arhitektura je postala kompleksnija. Danas moraš odlučiti između monolitnog MVC-a, mikroservisa, Blazora ili čiste API varijante.
Zaključak: Kako izabrati?
- Web Forms je prošlost koju trebaš poznavati samo da bi održavao stare sisteme.
- MVC 5 je stabilan, ali polako postaje naslijeđeni (legacy) sistem.
- .NET 9 je standard. Nudi najbolje od oba svijeta: moćan backend i fleksibilnost u razmjeni podataka bez "magičnih" skrivenih polja koja usporavaju rad.
📁 Struktura MVC Projekta
Kada kreirate novi ASP.NET MVC projekat u Visual Studiju, dobijate specifičnu strukturu foldera koja prati MVC konvencije. Razumijevanje ove strukture je ključno za efikasan razvoj.
MyMvcApp/
├── App_Data/ # Podaci aplikacije (baze, XML fajlovi)
├── App_Start/ # Konfiguracija aplikacije
│ ├── BundleConfig.cs # Bundling i minification
│ ├── FilterConfig.cs # Globalni filteri
│ ├── RouteConfig.cs # Routing konfiguracija
│ └── WebApiConfig.cs # Web API konfiguracija (ako koristite)
├── Content/ # CSS, slike, fontovi
│ └── Site.css
├── Controllers/ # Controller klase
│ ├── HomeController.cs
│ └── EmployeeController.cs
├── Models/ # Model klase
│ └── Employee.cs
├── Scripts/ # JavaScript fajlovi
│ ├── jquery-3.6.0.js
│ └── bootstrap.js
├── Views/ # Razor view fajlovi
│ ├── Home/
│ │ ├── Index.cshtml
│ │ └── About.cshtml
│ ├── Employee/
│ │ ├── Index.cshtml
│ │ └── Details.cshtml
│ ├── Shared/
│ │ ├── _Layout.cshtml # Glavni layout
│ │ └── _PartialView.cshtml
│ └── _ViewStart.cshtml # Automatski se izvršava prije svakog view-a
├── Global.asax # Globalni event handleri
├── Web.config # Konfiguracija aplikacije
└── packages.config # NuGet paketi
Ključni Folderi i Njihova Svrha
Controllers/
Svi Controller-i se nalaze ovdje. Konvencija je da ime klase završava sa "Controller"
(npr. EmployeeController), a ime fajla je EmployeeController.cs.
Models/
Model klase koje predstavljaju entitete iz baze podataka ili ViewModele. Ovdje se također mogu nalaziti Data Annotations za validaciju.
Views/
Svaki Controller ima svoj podfolder u Views/. Na primjer, EmployeeController
koristi view-e iz Views/Employee/ foldera. Shared/ folder sadrži
view-e koji se dijele između više kontrolera (npr. _Layout.cshtml).
💡 Konvencije u MVC-u
MVC koristi convention over configuration pristup. Ako slijedite konvencije (npr. imenovanje Controller-a, smještanje View-a), MVC će automatski pronaći i koristiti odgovarajuće fajlove bez dodatne konfiguracije.
🛠️ Konfiguracija Visual Studio Projekta
Kreiranje Novog MVC Projekta
Koraci za kreiranje novog ASP.NET MVC projekta:
- File → New → Project (ili Ctrl+Shift+N)
- Odaberite "ASP.NET Web Application (.NET Framework)"
- Odaberite "MVC" template
-
Provjerite opcije:
- ✅ Add folders and core references for: MVC
- ✅ Add unit tests (opcionalno, ali preporučeno)
- Kliknite OK
🔑 Važno: .NET Framework vs .NET Core
Ovaj tutorial pokriva ASP.NET MVC 5 na .NET Framework-u. Ako vidite opciju za ".NET Core" ili ".NET 8/9", to je druga tehnologija koju ćemo pokriti u Modulu 9. Za sada koristite .NET Framework verziju.
NuGet Paketi
Visual Studio automatski instalira osnovne NuGet pakete, ali možda ćete trebati dodatne:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<!-- Osnovni MVC Framework -->
<package id="Microsoft.AspNet.Mvc" version="5.2.9" targetFramework="net48" />
<package id="Microsoft.AspNet.Razor" version="3.2.9" targetFramework="net48" />
<package id="Microsoft.AspNet.WebPages" version="3.2.9" targetFramework="net48" />
<!-- Front-end biblioteke -->
<package id="bootstrap" version="5.2.3" targetFramework="net48" />
<package id="jQuery" version="3.6.0" targetFramework="net48" />
<!-- Infrastruktura -->
<package id="Microsoft.Web.Infrastructure" version="2.0.1" targetFramework="net48" />
</packages>
🌐 CDN vs Lokalni Resursi
U primjeru iznad vidimo lokalne pakete (Bootstrap, jQuery). Često se postavlja pitanje: Da li koristiti lokalne fajlove ili CDN (Content Delivery Network)?
💡 CDN (npr. cdnjs.com)
- ✅ Brzina: Korisnik možda već ima fajl u cache-u pretraživača.
- ✅ Performanse: Smanjuje opterećenje vašeg servera.
- ❌ Ovisnost: Ako CDN padne (rijetko) ili korisnik nema internet (intranet), aplikacija ne radi ispravno.
🔐 Lokalni Fajlovi (Preporučeno za e-Upravu)
- ✅ Sigurnost: Potpuna kontrola nad kodom koji se izvršava.
- ✅ Dostupnost: Radi i na zatvorenim mrežama (intranet) bez izlaza na internet.
- ❌ Održavanje: Morate ručno ažurirati verzije paketa.
Zaključak: Za sisteme javne uprave (e-Uprava) koji često rade u zatvorenim mrežama, lokalni resursi su obavezni.
🎯 Praktična Vježba: Kreiranje Prvog MVC Projekta
Zadatak: Kreirajte Aplikaciju "JavnaUprava"
Vaš zadatak je da kreirate osnovnu strukturu aplikacije za evidenciju državnih institucija.
Korak 1: Kreirajte novi MVC projekat u Visual Studiju sa nazivom "JavnaUprava".
Korak 2: U folderu Models kreirajte klasu Department
sa svojstvima iz StateStatisticsDB sheme (ID, Name, Code, Budget).
Korak 3: Kreirajte DepartmentsController sa `Index` akcijom koja
vraća hard-coded listu od 3 ministarstva.
Korak 4: Kreirajte View Index.cshtml koji prikazuje tabelu
ministarstava sa formatiranim budžetom.
namespace JavnaUprava.Models
{
public class Department
{
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
public string DepartmentCode { get; set; }
public decimal Budget { get; set; }
}
}
using System.Collections.Generic;
using System.Web.Mvc;
using JavnaUprava.Models;
namespace JavnaUprava.Controllers
{
public class DepartmentsController : Controller
{
// GET: Departments
public ActionResult Index()
{
var departments = new List<Department>
{
new Department { DepartmentID = 1, DepartmentName = "Ministarstvo Finansija", DepartmentCode = "MF", Budget = 1500000000.00m },
new Department { DepartmentID = 2, DepartmentName = "Ministarstvo Zdravlja", DepartmentCode = "MZ", Budget = 2300000000.00m },
new Department { DepartmentID = 3, DepartmentName = "Ministarstvo Obrazovanja", DepartmentCode = "MO", Budget = 1800000000.00m }
};
return View(departments);
}
}
}
@model IEnumerable<JavnaUprava.Models.Department>
@{
ViewBag.Title = "Lista Ministarstava";
}
<h2>Lista Ministarstava</h2>
<table class="table">
<thead>
<tr>
<th>Šifra</th>
<th>Ministarstvo</th>
<th>Budžet</th>
</tr>
</thead>
<tbody>
@foreach(var d in Model)
{
<tr>
<td>@d.DepartmentCode</td>
<td>@d.DepartmentName</td>
<td>@d.Budget.ToString("C")</td>
</tr>
}
</tbody>
</table>
✅ Provjera
Pokrenite aplikaciju (F5) i navigirajte na /Product URL. Trebali biste vidjeti
tabelu sa tri proizvoda. Ako ne vidite podatke, provjerite:
- Da li je
ProductControllerpravilno imenovan i nasljeđujeController - Da li je
Index.cshtmluViews/Product/folderu - Da li je
@modeldirektiva ispravno postavljena
✅ Zaključak
U ovoj lekciji ste naučili:
- ✅ Šta je MVC pattern i kako funkcioniše
- ✅ Razlike između MVC-a i WebForms-a
- ✅ Strukturu MVC projekta i konvencije
- ✅ Kako kreirati osnovnu MVC aplikaciju
📚 Sljedeća Lekcija
U Lekciji 1.2 ćemo detaljno istražiti Global.asax, App_Start folder, Web.config i HTTP životni ciklus MVC aplikacije. Ovo će vam omogućiti potpuno razumijevanje kako MVC obrađuje zahtjeve.