📖 Uvod
Svaka ASP.NET MVC aplikacija ima Global.asax fajl koji definiše globalne event handler-e i App_Start folder koji sadrži konfiguracijske klase. Razumijevanje kako ovi fajlovi funkcionišu i kako MVC obrađuje HTTP zahtjeve je ključno za napredno programiranje.
🔑 Zašto je Ovo Važno?
Global.asax i App_Start su prvi fajlovi koji se izvršavaju kada aplikacija startuje. Oni konfigurišu routing, bundling, filtere i druge globalne postavke koje utiču na cijelu aplikaciju.
🌐 Global.asax: Globalni Event Handleri
Global.asax je poseban fajl koji se izvršava kada aplikacija startuje, zaustavlja, ili
kada
se dogodi određeni event. On nasljeđuje HttpApplication klasu i omogućava vam da se
"uključite"
u različite faze životnog ciklusa aplikacije.
// Global.asax.cs
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace JavnaUprava
{
public class MvcApplication : HttpApplication
{
// Izvršava se samo jednom kada aplikacija startuje
protected void Application_Start()
{
// Registracija svih konfiguracija iz App_Start foldera
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Inicijalizacija Audit Loggera za praćenje pristupa
// AuditService.Initialize();
}
// Izvršava se prije svakog HTTP zahtjeva
protected void Application_BeginRequest()
{
// Primjer: Sigurnosno logovanje svakog zahtjeva (Obavezno za državne institucije)
// AuditLog.LogRequest(Request.UserHostAddress, Request.Url.ToString());
}
// Izvršava se nakon što je zahtjev obrađen
protected void Application_EndRequest()
{
// Primjer: Mjerenje performansi odgovora
}
// Izvršava se kada se dogodi neobrađena greška
protected void Application_Error()
{
Exception exception = Server.GetLastError();
// Logovanje kritičnih grešaka u Centralni Registar Grešaka
// ErrorLogger.LogCritical(exception);
}
// Izvršava se kada aplikacija zaustavi (shutdown)
protected void Application_End()
{
// Zatvaranje konekcija prema Centralnom Registru
}
}
}
Ključne Metode u Global.asax
1. Application_Start()
Izvršava se samo jednom kada aplikacija prvi put startuje (ili nakon restart-a). Ovo je idealno mjesto za:
- Registraciju ruta (routing)
- Konfiguraciju bundling-a i minification-a
- Registraciju globalnih filtera
- Inicijalizaciju baze podataka
- Warm-up operacije
💡 Application_Start i Performance
Sve što uradite u Application_Start se izvršava samo jednom, što znači da možete
raditi "skupa" operacije (npr. učitavanje konfiguracije iz baze) bez uticaja na performanse
svakog zahtjeva.
2. Application_BeginRequest()
Izvršava se prije svakog HTTP zahtjeva. Koristite ga za:
- Logovanje zahtjeva
- Postavljanje kultura (jezik)
- Autentifikaciju
- Inicijalizaciju per-request varijabli
3. Application_Error()
Izvršava se kada se dogodi neobrađena greška. Ovo je važno za:
- Logovanje grešaka
- Slanje email obavještenja administratorima
- Preusmjeravanje na error stranicu
- Sakrivanje detalja greške u produkciji
protected void Application_Error()
{
Exception exception = Server.GetLastError();
// Logovanje greške (u produkciji bi koristili NLog, Serilog, itd.)
System.Diagnostics.Debug.WriteLine($"Greška: {exception.Message}");
System.Diagnostics.Debug.WriteLine($"Stack Trace: {exception.StackTrace}");
// Preusmjeravanje na error stranicu
Response.Clear();
Response.TrySkipIisCustomErrors = true;
// Preusmjeravanje na custom error controller
HttpException httpException = exception as HttpException;
if (httpException != null)
{
switch (httpException.GetHttpCode())
{
case 404:
Response.Redirect("~/Error/NotFound");
break;
case 500:
Response.Redirect("~/Error/ServerError");
break;
default:
Response.Redirect("~/Error/Index");
break;
}
}
else
{
Response.Redirect("~/Error/Index");
}
}
📁 App_Start Folder: Konfiguracija Aplikacije
App_Start folder sadrži klase koje konfigurišu različite aspekte MVC aplikacije.
Ove klase se pozivaju iz Application_Start metode u Global.asax.
1. RouteConfig.cs - Routing Konfiguracija
RouteConfig.cs definiše kako MVC mapira URL-ove na Controller i Action metode.
Detaljnije ćemo ovo pokriti u Modulu 5, ali evo osnovnog pregleda:
// App_Start/RouteConfig.cs
using System.Web.Mvc;
using System.Web.Routing;
namespace JavnaUprava
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
// Ignorisanje određenih ruta (npr. za fajlove)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Default routing konvencija
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}
);
}
}
}
💡 Kako Routing Radi?
Kada korisnik otvori URL /Employee/Details/5, MVC routing:
- Pronalazi
EmployeeController - Poziva
Detailsaction metodu - Prosljeđuje
5kaoidparametar
Detaljnije o routing-u u Modulu 5.
2. BundleConfig.cs - Bundling i Minification
BundleConfig.cs konfiguriše bundling (spajanje više fajlova u jedan)
i minification (smanjivanje veličine) CSS i JavaScript fajlova. Ovo poboljšava
performanse aplikacije smanjujući broj HTTP zahtjeva i veličinu fajlova.
// App_Start/BundleConfig.cs
using System.Web;
using System.Web.Optimization;
namespace JavnaUprava
{
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
// JavaScript bundle - spaja više JS fajlova u jedan
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js"));
// CSS bundle - spaja više CSS fajlova u jedan
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
// U produkciji, bundling automatski minifikuje fajlove
// U development modu, možete vidjeti originalne fajlove
#if DEBUG
BundleTable.EnableOptimizations = false; // Isključeno u development-u
#else
BundleTable.EnableOptimizations = true; // Uključeno u produkciji
#endif
}
}
}
Korištenje Bundle-a u View-u
@* Views/Shared/_Layout.cshtml *@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title</title>
@* Umjesto pojedinačnih CSS fajlova, koristimo bundle *@
@Styles.Render("~/Content/css")
</head>
<body>
@RenderBody()
@* Umjesto pojedinačnih JS fajlova, koristimo bundle *@
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
</body>
</html>
🔑 Prednosti Bundling-a
- Smanjenje HTTP zahtjeva: Umjesto 10 zahtjeva za 10 JS fajlova, imate 1 zahtjev za bundle
- Minification: Automatsko uklanjanje komentara, whitespace-a, i skraćivanje imena varijabli
- Cache-iranje: Browser cache-ira bundle, što poboljšava performanse
3. FilterConfig.cs - Globalni Filteri
FilterConfig.cs registruje globalne filtere koji se primjenjuju na sve
Controller-e i Action metode. Filteri omogućavaju vam da izvršite kod prije ili nakon action metode.
// App_Start/FilterConfig.cs
using System.Web.Mvc;
namespace JavnaUprava
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// HandleError filter - automatski hvata neobrađene greške
filters.Add(new HandleErrorAttribute());
// Autorizacija - zahtijeva autentifikaciju za sve action metode (Sigurnosni standard)
// filters.Add(new AuthorizeAttribute());
}
}
}
💡 Filteri u Detaljima
Detaljnije o filterima (Authorization, Action, Result, Exception) ćemo pokriti u Modulu 3 kada budemo radili sa Controller-ima.
⚙️ Web.config: Konfiguracija Aplikacije
Web.config je XML fajl koji sadrži konfiguraciju ASP.NET aplikacije. On definiše connection string-ove, postavke kompajliranja, error handling, i mnoge druge opcije.
Ključne Sekcije u Web.config
1. connectionStrings - Povezivanje sa Bazom Podataka
connectionStrings sekcija u Web.config sadrži sve connection string-ove koji
omogućavaju aplikaciji
da se poveže sa bazom podataka. Entity Framework i klasični ADO.NET koriste ove
connection string-ove za pristup SQL Server-u.
Scenario 1: LocalDB (Development Okruženje)
LocalDB je lightweight verzija SQL Server-a idealna za development. Automatski se instalira sa Visual Studio-om.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<!--
name: Logički naziv koji koristite u kodu (npr. DbContext konstruktor)
connectionString: Detalji konekcije
providerName: ADO.NET provider (Entity Framework koristi ovo)
-->
<add name="StateStatisticsDB"
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=StateStatisticsDB;Integrated Security=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
🔍 Analiza Connection String-a (LocalDB)
| Parametar | Vrijednost | Objašnjenje |
|---|---|---|
Data Source |
(LocalDb)\MSSQLLocalDB |
SQL Server instanca. LocalDB koristi posebnu sintaksu sa zagradama. |
Initial Catalog |
StateStatisticsDB |
Naziv baze podataka. Alternativa:
Database=StateStatisticsDB
|
Integrated Security |
True |
Windows Authentication - koristi trenutno prijavljenog Windows korisnika. Sigurnije od SQL Auth. |
providerName |
System.Data.SqlClient |
ADO.NET provider za SQL Server. Entity Framework 6 zahtijeva ovo. |
Scenario 2: SQL Server Express (Test Okruženje)
SQL Server Express je besplatna verzija SQL Server-a sa više funkcionalnosti od LocalDB-a, pogodan za test servere.
<connectionStrings>
<!-- SQL Server Express sa Windows Authentication -->
<add name="StateStatisticsDB"
connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=StateStatisticsDB;Integrated Security=True;MultipleActiveResultSets=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>
🔍 Novi Parametri
Data Source=.\SQLEXPRESS- Dot (.) znači lokalni server,SQLEXPRESSje naziv instanceMultipleActiveResultSets=True- Dozvoljava više otvorenihSqlDataReader-a istovremeno (potrebno za neke EF scenarije)
Scenario 3: SQL Server (Production) - Windows Authentication
Za produkcijske servere u državnim institucijama, Windows Authentication je OBAVEZAN sigurnosni standard.
<connectionStrings>
<!-- Produkcijski SQL Server sa Windows Authentication -->
<add name="StateStatisticsDB"
connectionString="Server=sql-prod.vlada.local;Database=StateStatisticsDB;Integrated Security=SSPI;Persist Security Info=False;"
providerName="System.Data.SqlClient" />
</connectionStrings>
🔍 Production Parametri
Server=sql-prod.vlada.local- FQDN (Fully Qualified Domain Name) produkcijskog serveraIntegrated Security=SSPI- Identično kaoTrue, koristi Security Support Provider InterfacePersist Security Info=False- NE čuva osjetljive podatke u konekciji nakon otvaranja (sigurnosna praksa)
Scenario 4: SQL Authentication (Alternativa - NE PREPORUČUJE SE)
SQL Authentication koristi username/password umjesto Windows korisnika. Koristi se samo ako Windows Auth nije moguć.
<connectionStrings>
<!-- SQL Authentication (samo za posebne slučajeve) -->
<add name="StateStatisticsDB"
connectionString="Server=sql-prod.vlada.local;Database=StateStatisticsDB;User Id=app_statistics;Password=ENCRYPTED_PASSWORD;"
providerName="System.Data.SqlClient" />
</connectionStrings>
⚠️ SIGURNOSNO UPOZORENJE: SQL Authentication
NIKADA ne čuvajte passworde u plain text u Web.config! Ovo je
ZABRANJENA PRAKSA u državnim aplikacijama.
Sigurne alternative:
- ✅ Windows Authentication (najpoželjnije)
- ✅ Enkriptovani Web.config (koristiti
aspnet_regiis.exeza enkriptovanje connectionStrings sekcije) - ✅ Azure Key Vault ili slični servisi za tajne
- ✅ Environment Variables sa ograničenim pristupom
Korištenje Connection String-a u Kodu
using System.Configuration;
using System.Data.SqlClient;
// Čitanje connection string-a po imenu
string connString = ConfigurationManager.ConnectionStrings["StateStatisticsDB"].ConnectionString;
// Provjera da li postoji (null-safe)
if (ConfigurationManager.ConnectionStrings["StateStatisticsDB"] != null)
{
string safeConnString = ConfigurationManager.ConnectionStrings["StateStatisticsDB"].ConnectionString;
// Kreiranje SqlConnection objekta
using (SqlConnection conn = new SqlConnection(safeConnString))
{
conn.Open();
// Rad sa bazom...
}
}
// Entity Framework DbContext automatski koristi connection string
public class StateStatisticsContext : DbContext
{
// EF će potražiti connection string sa imenom "StateStatisticsDB"
public StateStatisticsContext() : base("StateStatisticsDB")
{
}
}
2. appSettings - Prilagođene Postavke
appSettings sekcija omogućava vam da defini šete key-value parove za
konfiguraciju aplikacije
bez potrebe da ih hard-kodirate u C# kodu. Ovo je idealno za postavke koje se mogu mijenjati između
različitih okruženja.
Kompletna appSettings Konfiguracija za Državnu Aplikaciju
<configuration>
<appSettings>
<!-- ============================================ -->
<!-- EMAIL KONFIGURACIJA (SMTP) -->
<!-- ============================================ -->
<!-- Server za slanje email-ova -->
<add key="SmtpServer" value="mail.vlada.gov.ba" />
<!-- Port (587 = TLS, 465 = SSL, 25 = Unencrypted - NE KORISTITI) -->
<add key="SmtpPort" value="587" />
<!-- Zahtijeva li SMTP server autentifikaciju -->
<add key="SmtpRequiresAuth" value="true" />
<!-- Username za SMTP (koristiti service account) -->
<add key="SmtpUsername" value="[email protected]" />
<!-- Password za SMTP - U PRODUKCIJI ENKRIPTOVATI! -->
<add key="SmtpPassword" value="ENCRYPTED_OR_FROM_VAULT" />
<!-- Pošiljalac email-ova -->
<add key="EmailFrom" value="[email protected]" />
<!-- Pošiljalac ime (prikazuje se u emailu) -->
<add key="EmailFromName" value="Sistem Državne Statistike" />
<!-- Email za administrativne notifikacije -->
<add key="AdminEmail" value="[email protected]" />
<!-- ============================================ -->
<!-- INSTITUCIONALNA KONFIGURACIJA -->
<!-- ============================================ -->
<!-- Kod institucije (koristi se u izvještajima) -->
<add key="InstitutionCode" value="AS" />
<!-- Puni naziv institucije -->
<add key="InstitutionName" value="Agencija za Statistiku" />
<!-- Okruženje (Development/Staging/Production) -->
<add key="Environment" value="Development" />
<!-- Verzija aplikacije -->
<add key="AppVersion" value="1.0.0" />
<!-- ============================================ -->
<!-- SIGURNOST I AUDIT -->
<!-- ============================================ -->
<!-- Da li je audit logging omogućen -->
<add key="EnableAuditLog" value="true" />
<!-- Da li logirati sve SQL upite (samo za development) -->
<add key="LogSqlQueries" value="false" />
<!-- Trajanje sesije u minutima -->
<add key="SessionTimeoutMinutes" value="30" />
<!-- Maksimalan broj neuspješnih login pokušaja -->
<add key="MaxLoginAttempts" value="5" />
<!-- Lockout trajanje nakon neuspješnih pokušaja (minuti) -->
<add key="LockoutDurationMinutes" value="15" />
<!-- ============================================ -->
<!-- INTEGRACIJE SA VANJSKIM SISTEMIMA -->
<!-- ============================================ -->
<!-- API endpoint Centralnog Registra Građana -->
<add key="CentralRegistryApiUrl" value="https://api.registar.gov.ba/v1/" />
<!-- API ključ za Centralni Registar -->
<add key="CentralRegistryApiKey" value="API_KEY_STORED_IN_VAULT" />
<!-- Timeout za API pozive (sekunde) -->
<add key="ApiTimeoutSeconds" value="30" />
<!-- ============================================ -->
<!-- FILE UPLOAD I STORAGE -->
<!-- ============================================ -->
<!-- Maksimalna veličina upload-a (MB) -->
<add key="MaxUploadSizeMB" value="10" />
<!-- Dozvoljene ekstenzije fajlova -->
<add key="AllowedFileExtensions" value=".pdf,.docx,.xlsx,.csv" />
<!-- Lokacija za privremene fajlove -->
<add key="TempFilePath" value="C:\Temp\StateStatistics\" />
<!-- Lokacija za arhiviranje izvještaja -->
<add key="ReportArchivePath" value="C:\Archives\Reports\" />
<!-- ============================================ -->
<!-- FEATURE FLAGS (Omogućavanje/Onemogućavanje) -->
<!-- ============================================ -->
<!-- Da li prikazati novu Dashboard funkcionalnost -->
<add key="EnableNewDashboard" value="false" />
<!-- Da li omogućiti PDF export -->
<add key="EnablePdfExport" value="true" />
<!-- Da li omogućiti Excel export -->
<add key="EnableExcelExport" value="true" />
<!-- ============================================ -->
<!-- LOGGING I MONITORING -->
<!-- ============================================ -->
<!-- Log level (Trace/Debug/Info/Warning/Error/Fatal) -->
<add key="LogLevel" value="Info" />
<!-- Da li logirati u fajl -->
<add key="LogToFile" value="true" />
<!-- Putanja do log fajlova -->
<add key="LogFilePath" value="C:\Logs\StateStatistics\" />
<!-- ============================================ -->
<!-- LOKALIZACIJA -->
<!-- ============================================ -->
<!-- Default jezik aplikacije -->
<add key="DefaultLanguage" value="bs-BA" />
<!-- Podržani jezici (comma-separated) -->
<add key="SupportedLanguages" value="bs-BA,hr-HR,sr-Latn-BA" />
</appSettings>
</configuration>
Čitanje appSettings iz C# Koda
using System;
using System.Configuration;
// ========================================
// 1. OSNOVNO ČITANJE (String vrijednost)
// ========================================
string smtpServer = ConfigurationManager.AppSettings["SmtpServer"];
// Rezultat: "mail.vlada.gov.ba"
// ========================================
// 2. NULL-SAFE ČITANJE SA DEFAULT VRIJEDNOŠĆU
// ========================================
// Ako ključ ne postoji, vrati "localhost"
string smtpServerSafe = ConfigurationManager.AppSettings["SmtpServer"] ?? "localhost";
// ========================================
// 3. KONVERZIJA U INT
// ========================================
// Čitanje porta kao integer
string smtpPortString = ConfigurationManager.AppSettings["SmtpPort"];
int smtpPort = int.Parse(smtpPortString); // Može baciti exception!
// Siguran način (sa default vrijednošću)
int smtpPortSafe;
if (!int.TryParse(ConfigurationManager.AppSettings["SmtpPort"], out smtpPortSafe))
{
smtpPortSafe = 587; // Default vrijednost
}
// ========================================
// 4. KONVERZIJA U BOOL
// ========================================
bool isAuditEnabled = bool.Parse(ConfigurationManager.AppSettings["EnableAuditLog"] ?? "false");
// Siguran način
bool isAuditEnabledSafe = false;
bool.TryParse(ConfigurationManager.AppSettings["EnableAuditLog"], out isAuditEnabledSafe);
// ========================================
// 5. PARSIRANJE LISTE (Comma-separated)
// ========================================
string extensionsString = ConfigurationManager.AppSettings["AllowedFileExtensions"];
string[] allowedExtensions = extensionsString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// Rezultat: [".pdf", ".docx", ".xlsx", ".csv"]
// ========================================
// 6. HELPER METODA ZA ČITANJE (Best Practice)
// ========================================
public static class ConfigHelper
{
public static string GetString(string key, string defaultValue = "")
{
return ConfigurationManager.AppSettings[key] ?? defaultValue;
}
public static int GetInt(string key, int defaultValue = 0)
{
int result;
return int.TryParse(ConfigurationManager.AppSettings[key], out result) ? result : defaultValue;
}
public static bool GetBool(string key, bool defaultValue = false)
{
bool result;
return bool.TryParse(ConfigurationManager.AppSettings[key], out result) ? result : defaultValue;
}
}
// Korištenje helper metode
string institutionCode = ConfigHelper.GetString("InstitutionCode", "UNKNOWN");
int sessionTimeout = ConfigHelper.GetInt("SessionTimeoutMinutes", 30);
bool auditEnabled = ConfigHelper.GetBool("EnableAuditLog", false);
Praktičan Primjer: Email Servis
using System.Configuration;
using System.Net;
using System.Net.Mail;
public class EmailService
{
private readonly string _smtpServer;
private readonly int _smtpPort;
private readonly string _username;
private readonly string _password;
private readonly string _fromEmail;
private readonly string _fromName;
public EmailService()
{
// Učitavanje svih postavki iz Web.config
_smtpServer = ConfigurationManager.AppSettings["SmtpServer"];
_smtpPort = int.Parse(ConfigurationManager.AppSettings["SmtpPort"] ?? "587");
_username = ConfigurationManager.AppSettings["SmtpUsername"];
_password = ConfigurationManager.AppSettings["SmtpPassword"];
_fromEmail = ConfigurationManager.AppSettings["EmailFrom"];
_fromName = ConfigurationManager.AppSettings["EmailFromName"];
}
public void SendNotification(string toEmail, string subject, string body)
{
using (var client = new SmtpClient(_smtpServer, _smtpPort))
{
client.Credentials = new NetworkCredential(_username, _password);
client.EnableSsl = true;
var message = new MailMessage
{
From = new MailAddress(_fromEmail, _fromName),
Subject = subject,
Body = body,
IsBodyHtml = true
};
message.To.Add(toEmail);
client.Send(message);
}
}
}
🔑 appSettings vs. connectionStrings
| Aspekt | appSettings | connectionStrings |
|---|---|---|
| Svrha | Konfiguracijske postavke aplikacije (email, API ključevi, feature flags) | Isključivo za database connection string-ove |
| Format | Key-value parovi | name + connectionString + providerName |
| Pristup u kodu | ConfigurationManager.AppSettings["key"] |
ConfigurationManager.ConnectionStrings["name"]
|
| Enkriptovanje | Moguće, ali connectionStrings ima prioritet | Moguće sa aspnet_regiis.exe |
⚠️ SIGURNOSNE PRAKSE ZA appSettings
- 🚫 NIKADA ne čuvajte passworde u plain text!
- ✅ Koristite Azure Key Vault, AWS Secrets Manager, ili HashiCorp Vault
- ✅ Enkriptujte osjetljive sekcije sa
aspnet_regiis.exe -pef "appSettings" "C:\Path\To\App" - ✅ Koristite Environment Variables za produkcijske tajne
- ✅ Koristite Web.config transformacije (Web.Debug.config, Web.Release.config) za različita okruženja
3. system.web - ASP.NET Postavke
system.web sekcija definiše kako ASP.NET runtime obrađuje zahtjeve. Ovo je
najvažnija
konfiguracija sekcija za MVC aplikacije.
Kompletna system.web Konfiguracija
<configuration>
<system.web>
<!-- ============================================ -->
<!-- 1. COMPILATION (Kompajliranje) -->
<!-- ============================================ -->
<compilation
debug="true"
targetFramework="4.8">
<!--
debug="true": Uključuje debug simbole, omogućava detaljne error poruke
OBAVEZNO staviti na "false" u produkciji!
targetFramework: .NET Framework verzija (4.5, 4.6, 4.7, 4.8)
-->
<assemblies>
<!-- Registracija dodatnih assembly-a ako je potrebno -->
<add assembly="System.Data.Entity, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
<!-- ============================================ -->
<!-- 2. CUSTOM ERRORS (Prilagođene Error Stranice) -->
<!-- ============================================ -->
<customErrors
mode="RemoteOnly"
defaultRedirect="~/Error/Index">
<!--
mode: Kontroliše prikazivanje error stranica
- "Off": Prikazuje detaljne ASP.NET greške (SAMO za development!)
- "On": Uvijek prikazuje prilagođene error stranice
- "RemoteOnly": Prikazuje ASP.NET greške lokalno, prilagođene remote korisnicima (PREPORUČENO)
defaultRedirect: Fallback stranica za sve neobrađene greške
-->
<error statusCode="400" redirect="~/Error/BadRequest" />
<error statusCode="403" redirect="~/Error/Forbidden" />
<error statusCode="404" redirect="~/Error/NotFound" />
<error statusCode="500" redirect="~/Error/ServerError" />
</customErrors>
<!-- ============================================ -->
<!-- 3. SESSION STATE (Upravljanje Sesijom) -->
<!-- ============================================ -->
<sessionState
mode="InProc"
timeout="30"
cookieless="UseCookies"
cookieName="ASP.NET_SessionId">
<!--
mode: Gdje se čuvaju session podaci
- "InProc": U memoriji web servera (BRZO, ali gubite sesiju kod restart-a)
- "StateServer": Na zasebnom State Server servisu (perzistentno)
- "SQLServer": U SQL Server bazi (najsigurnije, za load-balanced okruženja)
- "Off": Onemogućeno
timeout: Trajanje sesije u minutima (30 = 30 minuta neaktivnosti)
cookieless: Kako se čuva session ID
- "UseCookies": Uvijek u cookie (PREPORUČENO)
- "UseUri": U URL-u (nesigurno)
- "AutoDetect": Automatski detektuje
-->
</sessionState>
<!-- ============================================ -->
<!-- 4. AUTHENTICATION (Autentifikacija) -->
<!-- ============================================ -->
<authentication mode="Forms">
<!--
mode: Tip autentifikacije
- "None": Bez autentifikacije
- "Windows": Windows/Active Directory Authentication (za intranet)
- "Forms": Forms-based authentication (za internet aplikacije)
- "Passport": Microsoft Passport (zastarjelo)
-->
<forms
name=".ASPXAUTH"
loginUrl="~/Account/Login"
timeout="2880"
slidingExpiration="true"
protection="All"
requireSSL="false">
<!--
name: Naziv authentication cookie-a
loginUrl: Stranica za prijavu
timeout: Trajanje auth cookie-a u minutima (2880 = 48 sati)
slidingExpiration: Ako true, timeout se obnavlja sa svakim zahtjevom
protection: Kako se štiti cookie
- "All": Enkriptovan i validiran (PREPORUČENO)
- "Encryption": Samo enkriptovan
- "Validation": Samo validiran
- "None": Bez zaštite (NIKAD!)
requireSSL: Zahtijeva li HTTPS (u produkciji MORA biti true!)
-->
</forms>
</authentication>
<!-- ============================================ -->
<!-- 5. AUTHORIZATION (Autorizacija) -->
<!-- ============================================ -->
<authorization>
<!-- Dozvoli svim korisnicima pristup (default) -->
<allow users="*" />
<!-- Primjer: Blokiraj anonimne korisnike (zahtijeva login) -->
<!-- <deny users="?" /> -->
<!-- Primjer: Dozvoli samo određene korisnike -->
<!-- <allow users="[email protected],[email protected]" /> -->
<!-- Primjer: Dozvoli samo određene role -->
<!-- <allow roles="Admin,Manager" /> -->
</authorization>
<!-- ============================================ -->
<!-- 6. HTTP RUNTIME (Ograničenja Zahtjeva) -->
<!-- ============================================ -->
<httpRuntime
maxRequestLength="20480"
executionTimeout="300"
requestValidationMode="2.0"
enableVersionHeader="false">
<!--
maxRequestLength: Maksimalna veličina zahtjeva u KB (20480 KB = 20 MB)
Važno za file upload!
executionTimeout: Maksimalno vrijeme izvršavanja zahtjeva (sekunde)
requestValidationMode: Nivo validacije zahtjeva
- "2.0": ASP.NET 2.0 stil (validira sve)
- "4.0": ASP.NET 4.0+ stil (validira samo gdje je potrebno)
enableVersionHeader: Prikazuje li ASP.NET verziju u HTTP header-u
(MORA biti false u produkciji - sigurnost!)
-->
</httpRuntime>
<!-- ============================================ -->
<!-- 7. PAGES (Postavke Za Sve Stranice) -->
<!-- ============================================ -->
<pages
validateRequest="true"
enableViewState="false"
clientIDMode="AutoID">
<!--
validateRequest: Zaštita od XSS napada (provjerava input za script tagove)
MORA biti true osim ako znate šta radite!
enableViewState: Da li koristiti ViewState (MVC NE KORISTI ViewState!)
clientIDMode: Kako se generišu ID-ovi HTML elemenata
- "AutoID": ASP.NET generiše ID-ove (WebForms stil)
- "Static": Koristite ID kako ste ga napisali
- "Predictable": Kombinacija (za DataControls)
-->
<namespaces>
<!-- Default namespace-ovi dostupni u svim View-ima -->
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.Optimization" />
</namespaces>
</pages>
<!-- ============================================ -->
<!-- 8. GLOBALIZATION (Lokalizacija) -->
<!-- ============================================ -->
<globalization
culture="bs-BA"
uiCulture="bs-BA"
requestEncoding="utf-8"
responseEncoding="utf-8"
fileEncoding="utf-8">
<!--
culture: Kultura za datum, valuta, brojeve (formatiranje)
uiCulture: Kultura za UI tekstove (resource fajlovi)
Kodiranja: UTF-8 je standard za Bosanski jezik (ćčšž)
Primjeri cultura:
- "bs-BA": Bosanski (Bosna i Hercegovina)
- "hr-HR": Hrvatski
- "sr-Latn-BA": Srpski (Latinica)
- "en-US": Engleski (SAD)
-->
</globalization>
<!-- ============================================ -->
<!-- 9. MACHINE KEY (Enkripcija i Validacija) -->
<!-- ============================================ -->
<!-- VAŽNO: U produkciji sa load balancer-om, svi serveri MORAJU imati isti machineKey! -->
<machineKey
validationKey="AUTO,IsolateApps"
decryptionKey="AUTO,IsolateApps"
validation="HMACSHA256"
decryption="AES">
<!--
validationKey: Ključ za validaciju ViewState i cookies
decryptionKey: Ključ za enkriptovanje ViewState i cookies
validation: Algoritam za validaciju (HMACSHA256 je najsigurniji)
decryption: Algoritam za enkriptovanje (AES je standard)
"AUTO,IsolateApps": ASP.NET automatski generiše ključeve
PRODUKCIJA SA LOAD BALANCER-OM: Koristite fiksne ključeve!
Generiši\u0161ite sa: https://www.allkeysgenerator.com/Random/ASP-Net-MachineKey-Generator.aspx
Primjer:
<machineKey
validationKey="LONG_HEX_STRING_64_CHARS"
decryptionKey="LONG_HEX_STRING_32_CHARS"
validation="HMACSHA256"
decryption="AES" />
-->
</machineKey>
<!-- ============================================ -->
<!-- 10. MEMBERSHIP (Upravljanje Korisnicima) -->
<!-- ============================================ -->
<!-- Napomena: ASP.NET Identity (Modul 7) zamjenjuje Membership, ali evo strukture -->
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<clear />
<add name="DefaultMembershipProvider"
type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers"
connectionStringName="StateStatisticsDB"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="true"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="8"
passwordAttemptWindow="10" />
</providers>
</membership>
</system.web>
</configuration>
Analiza Ključnih Elemenata
🔍 1. compilation - DEBUG vs. RELEASE
| Aspekt | debug="true" (Development) | debug="false" (Production) |
|---|---|---|
| Performanse | ❌ Sporije (bez optimizacija) | ✅ Brže (kompajler optimizuje) |
| Memorija | ❌ Veća potrošnja | ✅ Manja potrošnja |
| Error poruke | ✅ Detaljne (sa stack trace) | ⚠️ Ograni čene (sigurnost) |
| Breakpoint-i | ✅ Rade u debugger-u | ❌ Ne rade |
🔍 2. sessionState - Gdje Čuvati Sesiju?
| Mode | Prednosti | Mane | Kada Koristiti |
|---|---|---|---|
| InProc | ✅ Najbrži ✅ Jednostavan |
❌ Gubite podatke kod restart-a servera ❌ Ne radi sa load balancer-om |
Development, mali projekti |
| StateServer | ✅ Perzistentno ✅ Radi sa load balancer-om |
⚠️ Sporije od InProc ⚠️ Zahtijeva dodatni servis |
Srednji projekti |
| SQLServer | ✅ Najsigurnije ✅ Visoka dostupnost ✅ Radi sa load balancer-om |
⚠️ Najsporije ⚠️ Zahtijeva SQL Server |
Produkcijski državni sistemi |
⚠️ KRITIČNE SIGURNOSNE POSTAVKE ZA PRODUKCIJU
| Element | Development | Production (OBAVEZNO!) |
|---|---|---|
compilation debug |
true |
false 🔴 |
customErrors mode |
Off |
On ili RemoteOnly 🔴 |
forms requireSSL |
false |
true 🔴 |
httpRuntime enableVersionHeader |
true |
false 🔴 |
pages validateRequest |
true |
true 🔴 |
🔄 HTTP Životni Ciklus MVC Aplikacije
Razumijevanje HTTP životnog ciklusa je ključno za efikasno programiranje u MVC-u. Evo koraka koji se dešavaju kada korisnik pošalje HTTP zahtjev:
Koraci HTTP Životnog Ciklusa
-
HTTP Zahtjev Stiže
- IIS (Internet Information Services) prima zahtjev
- Zahtjev se prosljeđuje ASP.NET runtime-u
-
Application_BeginRequest
- Izvršava se u
Global.asax - Prilika za inicijalizaciju per-request varijabli
- Izvršava se u
-
Routing
- MVC routing analizira URL
- Određuje koji Controller i Action metodu pozvati
- Ekstraktuje parametre iz URL-a
-
Controller Instanciranje
- MVC kreira instancu Controller klase
- Poziva se Controller konstruktor
-
Action Method Execution
- Izvršavaju se Authorization Filteri (npr. [Authorize])
- Izvršavaju se Action Filteri (prije action metode)
- Poziva se Action metoda
- Izvršavaju se Result Filteri (nakon action metode)
-
View Rendering
- Action metoda vraća
ViewResult - MVC pronalazi odgovarajući View fajl
- View se renderuje sa Razor sintaksom
- HTML se vraća korisniku
- Action metoda vraća
-
Application_EndRequest
- Izvršava se u
Global.asax - Prilika za čišćenje resursa
- Izvršava se u
-
HTTP Odgovor
- HTML se šalje korisniku
- Zahtjev je završen
// Primjer: Kako MVC obrađuje zahtjev /Employee/Details/5
// 1. Global.asax - Application_BeginRequest
protected void Application_BeginRequest()
{
// Log: "Zahtjev započeo: /Employee/Details/5"
}
// 2. Routing - RouteConfig
// Mapira: Controller = "Employee", Action = "Details", id = "5"
// 3. Controller Instanciranje
var controller = new EmployeeController();
// 4. Authorization Filter (ako postoji [Authorize])
if (!User.IsAuthenticated)
{
RedirectToLogin();
}
// 5. Action Method Execution
var result = controller.Details(5);
// 6. View Rendering
// MVC pronalazi: Views/Employee/Details.cshtml
// Renderuje sa Razor sintaksom
// Vraća HTML
// 7. Global.asax - Application_EndRequest
protected void Application_EndRequest()
{
// Log: "Zahtjev završen"
}
🔑 Ključna Razlika od WebForms
Za razliku od WebForms-a koji ima kompleksan Page Lifecycle sa mnogo event-a (Page_Init, Page_Load, Page_PreRender, itd.), MVC ima jednostavniji i predvidljiviji životni ciklus:
- Routing → Controller → Action → View
- Nema ViewState, nema kompleksnih event-a
- Lakše za razumijevanje i testiranje
🎯 Praktična Vježba: Konfiguracija Audit Loginga za Javnu Upravu
Zadatak: Konfiguracija Audit Loginga za Javnu Upravu
Vaš zadatak je da konfigurišete Global.asax da bilježi svaki pristup aplikaciji, što je
zakonska obaveza za državne sisteme.
Zadatak 1: U Web.config dodajte connection string za
StateStatisticsDB i appSetting EnableAuditLog sa vrijednošću "true".
Zadatak 2: U Global.asax, unutar
Application_BeginRequest, provjerite da li je audit omogućen i ispišite detalje
zahtjeva (IP adresa, Putanja) u Debug konzolu.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- ============================================ -->
<!-- CONNECTION STRINGS -->
<!-- ============================================ -->
<connectionStrings>
<!-- LocalDB konekcija za StateStatisticsDB -->
<add name="StateStatisticsDB"
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=StateStatisticsDB;Integrated Security=True;MultipleActiveResultSets=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>
<!-- ============================================ -->
<!-- APP SETTINGS -->
<!-- ============================================ -->
<appSettings>
<!-- AUDIT LOGGING KONFIGURACIJA -->
<add key="EnableAuditLog" value="true" />
<!-- Gdje se čuvaju audit logovi -->
<add key="AuditLogPath" value="C:\Logs\StateStatistics\Audit\" />
<!-- INSTITUCIJSKA KONFIGURACIJA -->
<add key="InstitutionCode" value="AS" />
<add key="InstitutionName" value="Agencija za Statistiku" />
<add key="Environment" value="Development" />
</appSettings>
<!-- ============================================ -->
<!-- SYSTEM.WEB -->
<!-- ============================================ -->
<system.web>
<!-- Kompajliranje u development modu -->
<compilation debug="true" targetFramework="4.8" />
<!-- Custom error stranice (Off za development) -->
<customErrors mode="Off" />
<!-- Session u memoriji (30 min timeout) -->
<sessionState mode="InProc" timeout="30" />
<!-- HTTP Runtime postavke -->
<httpRuntime
maxRequestLength="20480"
executionTimeout="300"
enableVersionHeader="false" />
<!-- Sigurnosne postavke -->
<pages validateRequest="true" enableViewState="false" />
<!-- Bosanski jezik po defaultu -->
<globalization culture="bs-BA" uiCulture="bs-BA" />
</system.web>
</configuration>
📝 Objašnjenje Rješenja - Web.config
- connectionStrings: Koristi
LocalDBsaMultipleActiveResultSets=Trueza Entity Framework. - EnableAuditLog: Uključuje audit logging funkcionalnost.
- AuditLogPath: Definiše gdje će se čuvati log fajlovi (u produkciji bi ovo bila centralna lokacija).
- debug="true": Omogućava detaljan debugging (samo za development!).
- customErrors mode="Off": Prikazuje detaljne error poruke (samo za development!).
protected void Application_BeginRequest()
{
bool auditEnabled = bool.Parse(ConfigurationManager.AppSettings["EnableAuditLog"] ?? "false");
if (auditEnabled)
{
string clientIp = Request.UserHostAddress;
string path = Request.Url.AbsolutePath;
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// U produkciji ovo ide u AuditLogs tabelu u bazi
System.Diagnostics.Debug.WriteLine($"[AUDIT] {timestamp} - IP: {clientIp} - Path: {path}");
}
}
✅ Zaključak
U ovoj lekciji ste naučili:
- ✅ Kako funkcioniše Global.asax i globalni event handleri
- ✅ Svrhu App_Start foldera i konfiguracijskih klasa
- ✅ Kako konfigurisati Web.config za različite postavke
- ✅ HTTP životni ciklus MVC aplikacije
- ✅ Razlike između MVC i WebForms lifecycle-a
📚 Sljedeći Modul
U Modulu 2 ćemo naučiti kako koristiti Entity Framework 6 za pristup podacima. Naučićete Database-First i Code-First pristupe, migracije, i CRUD operacije.