MODUL 1 - LEKCIJA 2

Global.asax, App_Start i HTTP Životni Ciklus

Razumijevanje konfiguracije aplikacije i kako MVC obrađuje HTTP zahtjeve

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

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

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

3. Application_Error()

Izvršava se kada se dogodi neobrađena greška. Ovo je važno za:

🛠️ Primjer: Error Handling u Global.asax
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:

🛠️ RouteConfig.cs
// 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:

  1. Pronalazi EmployeeController
  2. Poziva Details action metodu
  3. Prosljeđuje 5 kao id parametar

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.

🛠️ BundleConfig.cs
// 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

🛠️ Korištenje Bundle-a
@* 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.

🛠️ FilterConfig.cs
// 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.

🛠️ LocalDB Connection String
<?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.

🛠️ SQL Server Express Connection String
<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, SQLEXPRESS je naziv instance
  • MultipleActiveResultSets=True - Dozvoljava više otvorenih SqlDataReader-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.

🛠️ Production SQL Server (Windows Auth)
<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 servera
  • Integrated Security=SSPI - Identično kao True, koristi Security Support Provider Interface
  • Persist 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ć.

🛠️ SQL Authentication (Backup opcija)
<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.exe za 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
🛠️ Pristup Connection String-u iz C#
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
🛠️ App Settings - Potpuna Državna Konfiguracija
<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
🛠️ Pristup appSettings Vrijednostima
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
🛠️ Email Servis sa appSettings
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
🛠️ System.Web - Pot puna 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

  1. HTTP Zahtjev Stiže
    • IIS (Internet Information Services) prima zahtjev
    • Zahtjev se prosljeđuje ASP.NET runtime-u
  2. Application_BeginRequest
    • Izvršava se u Global.asax
    • Prilika za inicijalizaciju per-request varijabli
  3. Routing
    • MVC routing analizira URL
    • Određuje koji Controller i Action metodu pozvati
    • Ekstraktuje parametre iz URL-a
  4. Controller Instanciranje
    • MVC kreira instancu Controller klase
    • Poziva se Controller konstruktor
  5. 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)
  6. View Rendering
    • Action metoda vraća ViewResult
    • MVC pronalazi odgovarajući View fajl
    • View se renderuje sa Razor sintaksom
    • HTML se vraća korisniku
  7. Application_EndRequest
    • Izvršava se u Global.asax
    • Prilika za čišćenje resursa
  8. HTTP Odgovor
    • HTML se šalje korisniku
    • Zahtjev je završen
🛠️ Vizuelizacija Životnog Ciklusa
// 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:

  • RoutingControllerActionView
  • 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.

💡 Rješenje: Potpuni Web.config
<?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 LocalDB sa MultipleActiveResultSets=True za 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!).
💡 Rješenje: Global.asax
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:

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