MODUL 1 - LEKCIJA 1

MVC Princip i Razlike od WebForms

Razumijevanje MVC arhitekture i konfiguracija razvojnog okruženja u Visual Studiju

⏱️ Trajanje: ~3 časa 📚 Nivo: Početni 🎯 Praktični primjeri: 5

📖 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:

🛠️ Primjer Modela (Javna Uprava)
// 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.

🛠️ Primjer View-a (Lista Ministarstava)
@* 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.

🛠️ Primjer Controller-a
// 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.

3. Ostali načini razmjene informacija

Pored ViewState-a, koristili su se i standardni mehanizmi:

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).

Backend -> Frontend:

Frontend -> Backend:

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.

Novi alati:

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

Današnji izazov: SPA vs. SSR

Glavni izazov u .NET 9 nije više ViewState, već odluka:

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.

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.

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.

Zaključak: Kako izabrati?

📁 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.

📂 Struktura Foldera
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:

  1. File → New → Project (ili Ctrl+Shift+N)
  2. Odaberite "ASP.NET Web Application (.NET Framework)"
  3. Odaberite "MVC" template
  4. Provjerite opcije:
    • ✅ Add folders and core references for: MVC
    • ✅ Add unit tests (opcionalno, ali preporučeno)
  5. 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:

📦 Osnovni NuGet Paketi
<?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.

💡 Rješenje: Model (Department.cs)
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; }
    }
}
💡 Rješenje: Controller (DepartmentsController.cs)
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);
        }
    }
}
💡 Rješenje: View (Index.cshtml)
@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 ProductController pravilno imenovan i nasljeđuje Controller
  • Da li je Index.cshtml u Views/Product/ folderu
  • Da li je @model direktiva ispravno postavljena

✅ Zaključak

U ovoj lekciji ste naučili:

📚 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.