📖 Razmjena Podataka
MVC nudi tri načina za prosljeđivanje podataka iz Controller-a u View: ViewData, ViewBag, i TempData. Svaki ima svoju svrhu i ograničenja.
📦 ViewData
ViewData je dictionary (Dictionary<string, object>) koji omogućava prosljeđivanje podataka iz Controller-a u View. Podaci su dostupni samo tokom trenutnog zahtjeva.
// Controller
public ActionResult Index()
{
ViewData["MinistryName"] = "Ministarstvo Finansija";
ViewData["EmployeeCount"] = 350;
return View();
}
// View
@ViewData["MinistryName"]
Broj zaposlenih: @ViewData["EmployeeCount"]
💡 ViewData Ograničenja
ViewData zahtijeva type casting i nema IntelliSense podršku. Koristite ga za jednostavne podatke.
🎒 ViewBag
ViewBag je dinamički wrapper oko ViewData. Omogućava dinamičko dodavanje svojstava bez type casting-a.
// Controller
public ActionResult Index()
{
ViewBag.MinistryCode = "MF";
ViewBag.BudgetYear = 2024;
ViewBag.Departments = db.Departments.ToList();
return View();
}
// View
Ministarstvo: @ViewBag.MinistryCode
Budžetska godina: @ViewBag.BudgetYear
@foreach (var dept in ViewBag.Departments)
{
@dept.DepartmentName - @dept.Budget KM
}
🔑 ViewBag vs ViewData
ViewBag i ViewData koriste isti storage - promjena u jednom se reflektuje u drugom. ViewBag je samo sintaksni šećer.
💾 TempData i Background Mehanizam
TempData čuva podatke između dva uzastopna zahtjeva. Koristi se pretežno za preusmjeravanja (redirects) nakon uspješnog snimanja ili zbog prikaza poruke o grešci.
Kako TempData radi u pozadini?
Za razliku od ViewData i ViewBag koji žive samo tokom trenutnog HTTP Request-a, TempData podrazumijevano u pozadini koristi sistemski Session State. To znači da se podaci čuvaju u memoriji servera (ili u Redis-u/SQL-u ako je konfigurisan Scale-Out za državne sisteme). Kada se vrijednost iz TempData rječnika jednom pročita (bilo u Action metodi ili na View-u), ona se markira za brisanje i nestaje iz Session-a na kraju tog Request-a, čime se automatski oslobađa dragocjena poslužiteljska memorija.
// Controller - Create action
[HttpPost]
public ActionResult Create(Department dept)
{
if (ModelState.IsValid)
{
db.Departments.Add(dept);
db.SaveChanges();
TempData["SuccessMessage"] = "Odjel uspješno kreiran!";
return RedirectToAction("Index");
}
return View(dept);
}
// Controller - Index action
public ActionResult Index()
{
// TempData je dostupan ovdje nakon redirect-a
ViewBag.Message = TempData["SuccessMessage"];
return View();
}
// View
@if (ViewBag.Message != null)
{
@ViewBag.Message
}
💡 TempData Keep()
Koristite TempData.Keep("key") da zadržite podatke za sljedeći zahtjev.
🔍 Action Filteri i Životni Ciklus
Action Filteri omogućavaju izvršavanje prilagođenog koda prije ili nakon izvršavanja Action metode. U velikim enterprise aplikacijama, kao što su portali za priznavanje diploma ili registar javnih nabavki, oni se masovno koriste za rješavanje tehničkih zahtjeva ("Cross-Cutting Concerns") poput logginga svake akcije u bazu, provjere kompleksne RBAC autorizacije, i cachinga, ostavljajući takav kod fizički izvan Controller klasa što čini kod mnogo čitljivijim.
Slika: Životni ciklus i redoslijed izvršavanja Action Filtera
1. HandleError Filter
// Globalni filter (FilterConfig.cs)
filters.Add(new HandleErrorAttribute());
// Ili na action metodi
[HandleError]
public ActionResult Index()
{
throw new Exception("Test greška");
}
// Custom error view
[HandleError(View = "CustomError")]
public ActionResult Index()
{
// ...
}
2. Authorize Filter
// Zahtijeva autentifikaciju
[Authorize]
public ActionResult Admin()
{
return View();
}
// Zahtijeva određenu ulogu
[Authorize(Roles = "Admin")]
public ActionResult Delete(int id)
{
// ...
}
// Dozvoljava anonimnim korisnicima
[AllowAnonymous]
public ActionResult Public()
{
return View();
}
3. Custom Action Filter
public class AuditLogAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Logujemo ko, šta i kada pristupa - obavezno za javnu upravu
string user = filterContext.HttpContext.User.Identity.Name ?? "Anonymous";
string action = filterContext.ActionDescriptor.ActionName;
string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string ip = filterContext.HttpContext.Request.UserHostAddress;
System.Diagnostics.Debug.WriteLine($"[AUDIT] User: {user} | Action: {controller}/{action} | IP: {ip}");
}
}
// Korištenje
[AuditLog]
[Authorize] // Obično ide uz autorizaciju
public ActionResult Index()
{
return View();
}
🎯 Praktična Vježba
Zadatak: Implementirajte AuditLog Filter
Kreirajte AuditLogAttribute koji bilježi IP adresu korisnika i naziv akcije u tekstualni
fajl (simulacija audit loga).
✅ Zaključak
Naučili ste:
- ✅ Razlike između ViewData, ViewBag i TempData
- ✅ Kada koristiti svaki pristup
- ✅ Kako kreirati i koristiti Action Filtere