Modul 3 - Lekcija 2
Razmjena podataka između Controller-a i View-a, te upotreba Action Filter-a
⏱️ Trajanje: ~3 časa | 📚 Nivo: Srednji | 🎯 Praktični primjeri: 5
Osim prosljeđivanja snažno tipizovanog Modela (Strongly Typed Model) metodi
View(model),
MVC nudi dodatna tri načina za prosljeđivanje privremenih podataka iz Controller-a u View:
Ovi rječnici koriste se za prenošenje pomoćnih informacija poput poruka o greškama, statusa operacija, title taga na stranici i padajućih listi (Dropdown objekata).
ViewData je dictionary objekat (Dictionary<string, object>) koji
omogućava
prosljeđivanje podataka iz Controller-a u View. Podaci su dostupni samo tokom trenutnog HTTP
zahtjeva.
// --- CONTROLLER ---
public ActionResult Index()
{
ViewData["MinistryName"] = "Ministarstvo Finansija";
ViewData["EmployeeCount"] = 350;
return View();
}
// --- VIEW (Index.cshtml) ---
<h1>@ViewData["MinistryName"]</h1>
<p>Broj zaposlenih: @ViewData["EmployeeCount"]</p>
Zahtijeva eksplicitni type casting ako koristite metode nad objektom i nema IntelliSense podršku.
ViewBag je dinamički wrapper oko ViewData. Omogućava dinamičko dodavanje
svojstava putem dot notacije (npr. ViewBag.Key) bez type casting-a na
View strani.
// --- CONTROLLER ---
public ActionResult Index()
{
ViewBag.MinistryCode = "MF";
ViewBag.Departments = db.Departments.ToList(); // Nema potrebe za TypeCast
return View();
}
// --- VIEW (Index.cshtml) ---
<h1>Ministarstvo: @ViewBag.MinistryCode</h1>
@foreach (var dept in ViewBag.Departments) // C# zna koji je objekat
{
<p>@dept.DepartmentName - @dept.Budget KM</p>
}
Oni koriste isti kontejner – promjena ViewBag.Title će automatski promijeniti
i ViewData["Title"]. Zbog preglednosti koristite isključivo ViewBag dizajn.
TempData čuva podatke između dva uzastopna zahtjeva. Često se koristi za prebacivanje Success poruka na Index prikaz nakon uspješnoj POST snimanja.
Za razliku od ViewBag(za isti HTTP poziv), TempData preživljava HTTP Redirect jer u pozadini koristi HTTP Session. Kada se u narednom MVC zahtjevu vrijednost jednom pročita iz TempData rječnika, ona se briše i oslobađa poslužiteljsku memoriju.
[HttpPost]
public ActionResult Create(Department dept)
{
db.Departments.Add(dept);
db.SaveChanges();
TempData["SuccessMessage"] = "Odjel uspješno kreiran!"; // PISAO
return RedirectToAction("Index"); // 302 REDIRECT REQUEST
}
public ActionResult Index() // <- DRUGI NOVI ZAHTJEV
{
ViewBag.Message = TempData["SuccessMessage"]; // ČITAO, BRISANJE!
return View();
}
Action Filteri su atributske klase koje dodaju se na Action Metode radi ubacivanja C# koda "oko" vašeg stvarnog operativnog Controller metoda koda.
U poslovnim (enterprise) aplikacijama ovi presretači se masovno koriste za rješavanje nevidljivih tehničkih zahtjeva ("Cross-Cutting Concerns"):
Time održavamo Controller kod fokusiranim isključivo na logiku radnje!
Presretač grešaka. Kada kod "pukne", umjesto žute programske stranice, HandleError nam vraća čistu HTML stranicu "Doslo je do greske" bez otkrivanja C# tajni.
// Globalno postavljen za cijelu aplikaciju (Global.asax -> FilterConfig.cs)
filters.Add(new HandleErrorAttribute());
// Ili lokalno postavljen samo na neku metodu kojom upravljamo:
[HandleError]
public ActionResult CalculateTaxes()
{
throw new Exception("Neobuhvaćena sistemska greška");
}
// Specijaliziran sa custom View-om kad "pukne" specifičan kontroler
[HandleError(View = "MaintenanceErrorPage")]
public ActionResult DatabaseHeavyTask()
{
// C# kod
}
Filter bez kojeg nijedna korporativna i sigurnosna .NET MVC aplikacija ne može funkcionisati. Usmjerava "anonymous" korisnike na Login ekran.
// Zahtijeva da korisnik makar bude Logovan (bilo kakav account)
[Authorize]
public ActionResult Dashboard()
{
return View();
}
// Zahtijeva specifičnu poslovnu grupu/rolu zaduženu za odobravanje
[Authorize(Roles = "SuperAdmin, FinancialOffice")]
public ActionResult DeleteResource(int id)
{
// Samo oni logovani a koji pripadaju Role grupama pokreću kod
}
// Override ponašanje klase, recimo ako je na klasi [Authorize],
// ovu specifičnu metodu ne filtrira:
[AllowAnonymous]
public ActionResult PublicTermsAndConditions()
{
return View();
}
Ponekad želimo napisati sopstveni Filter. Nasljeđivanjem klase ActionFilterAttribute
možemo ga zalijepiti iznad svake metode!
public class LoggovanjeAktivnostiUpraveAttribute : ActionFilterAttribute
{
// Metoda se okida ODMAH PRIJE nego Controller metod počne:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string ipAdresa = filterContext.HttpContext.Request.UserHostAddress;
string userName = filterContext.HttpContext.User.Identity.Name;
string actionName = filterContext.ActionDescriptor.ActionName;
// Snimimo u Logging bazu zapisa!
DbLogger.Snimi(ipAdresa, userName, actionName, DateTime.Now);
}
}
// KORIŠTENJE FILTERA:
[LoggovanjeAktivnostiUprave]
public ActionResult PregledUgovora() { return View(); }
Kreirajte AuditLogAttribute koji bilježi IP adresu korisnika i naziv akcije u
tekstualni
fajl svake akcije koja je pod autorizacijom (simulacija audit loga).
public class AuditLogAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var action = filterContext.ActionDescriptor.ActionName;
var controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var log = $"Akcija {controller}/{action} pozvana u {DateTime.Now}";
// Jednostavan fajl log upis (potreban IO .txt fajl path)
System.IO.File.AppendAllText("C:\\Logs\\AuditLog.txt", log + Environment.NewLine);
}
}