# 22 • ASP.NET

> Návrh webové aplikace ASP.NET, Razor Pages, handlery, Razor syntaxe, služby, konfigurace aplikace
> 

# Co je ASP.NET

**ASP.NET** je open-source framework od **Microsoftu** pro vývoj webových aplikací. Píše se v jazyce **C#** a běží nad **.NET platformou**. Cross-platform: funguje na Windows, Linuxu i macOS.

### ASP.NET Framework vs ASP.NET Core (klasický zmatek)

|  | ASP.NET Framework (Klasický) | ASP.NET Core (Moderní) |
| --- | --- | --- |
| **Platforma** | Jen Windows | Cross-platform |
| **Vývoj** | Pouze údržba, žádné nové features | Aktivní vývoj |
| **Performance** | Slabší | Výrazně vyšší |
| **Modulárnost** | Monolitický | Modulární (jen co potřebuješ) |
| **Hosting** | Jen IIS | IIS, Kestrel, Nginx, Docker |
| **Dnešní použití** | Legacy projekty | Vše nové |

Když dnes řekneš "ASP.NET", typicky myslíš **ASP.NET Core**. Microsoft od .NET 5 (2020) zjednodušil pojmenování: ASP.NET Core teď žije v .NET (bez prefixu "Core"). Pro maturitu stačí říct "ASP.NET" nebo "ASP.NET Core".

# Typy ASP.NET aplikací

| Typ | Popis | Kdy použít |
| --- | --- | --- |
| **Razor Pages** | Stránka má vlastní model, page-focused | CRUD, formuláře, jednoduché až střední weby |
| **MVC** | Model-View-Controller | Větší projekty s komplexní logikou |
| **Web API** | REST API bez UI | Backend pro mobilní/SPA aplikace |
| **Minimal API** | Lightweight API bez kontrolerů (od .NET 6) | Mikroslužby, drobné endpointy |
| **Blazor** | SPA v C# bez (nebo s minimem) JavaScriptu | Interaktivní UI v .NET ekosystému |

### Blazor varianty

| Varianta | Princip |
| --- | --- |
| **Blazor Server** | C# kód běží na serveru, UI updates přes SignalR (WebSocket) |
| **Blazor WebAssembly** | C# v prohlížeči přes WASM, žádný server runtime |
| **Blazor Hybrid** | Nativní aplikace (MAUI) s Blazor UI |
| **Blazor United** (od .NET 8) | Mix server + WASM + statické rendering podle stránky |

# Struktura Razor Pages projektu

```
MojeApp/
├── Pages/                  ← Razor Pages (.cshtml + .cshtml.cs)
│   ├── Shared/
│   │   ├── _Layout.cshtml  ← společný layout
│   │   └── _ValidationScriptsPartial.cshtml
│   ├── _ViewImports.cshtml ← globální @using, @addTagHelper
│   ├── _ViewStart.cshtml   ← nastavení Layout pro všechny stránky
│   ├── Index.cshtml        ← HTML šablona
│   ├── Index.cshtml.cs     ← C# PageModel
│   └── ...
├── wwwroot/                ← statické soubory (CSS, JS, obrázky)
├── Models/                 ← třídy modelů (data)
├── Services/               ← business logika
├── Data/                   ← DbContext pro EF Core
├── Migrations/             ← EF Core migrace
├── Program.cs              ← vstupní bod, konfigurace
├── appsettings.json        ← konfigurace
├── appsettings.Development.json  ← override pro development
├── MojeApp.csproj          ← project file
└── launchSettings.json     ← profily spuštění (Properties/)
```

## 4 • Flow aplikace: jak se zpracuje request

![image.png](22%20%E2%80%A2%20ASP%20NET/image.png)

**Kestrel** je vestavěný HTTP server. V developmentu běží přímo na localhost. V produkci stojí typicky za reverzní proxy.

**Reverzní proxy** funguje jako prostředník mezi klientem a Kestrelem. Důvody: TLS terminace, load balancing, ochrana před DDoS, kompresí gzip/Brotli, cachování statiky.

# **Middleware pipeline**

**Middleware** je komponenta, která zpracovává HTTP request **v řadě**. Každý middleware buď zpracuje request, předá ho dalšímu, nebo vrátí response.

```csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler("/Error");    // 1. zachytit výjimky
app.UseHsts();                        // 2. force HTTPS hlavička
app.UseHttpsRedirection();            // 3. přesměrovat HTTP → HTTPS
app.UseStaticFiles();                 // 4. servírovat /wwwroot
app.UseRouting();                     // 5. najít endpoint
app.UseCors();                        // 6. CORS hlavičky
app.UseAuthentication();              // 7. zjistit, kdo je uživatel
app.UseAuthorization();               // 8. zjistit, co smí
app.MapRazorPages();                  // 9. spustit Razor Page handler

app.Run();
```

**Pořadí v pipeline je kritické**

```csharp
// ❌ Špatně: Authorization před Authentication
app.UseAuthorization();
app.UseAuthentication();   // už je pozdě, User je null

// ✓ Správně
app.UseAuthentication();
app.UseAuthorization();
```

**Vlastní middleware**

```csharp
app.Use(async (context, next) =>
{
    var sw = Stopwatch.StartNew();
    await next();   // pokračovat dál v pipeline
    sw.Stop();
    Console.WriteLine($"Request trval {sw.ElapsedMilliseconds}ms");
});
```

# Razor Pages

Moderní page-focused přístup. Každá stránka má dva soubory:

```csharp
Pages/
├── Index.cshtml        ← HTML šablona (Razor syntaxe)
└── Index.cshtml.cs     ← C# logika (PageModel)
```

### Příklad

**`Index.cshtml`** (šablona):

```csharp
@page
@model IndexModel

<h1>Vítej, @Model.Uzivatel</h1>

<form method="post">
    <label asp-for="Zprava"></label>
    <input asp-for="Zprava" />
    <span asp-validation-for="Zprava"></span>
    <button type="submit">Odeslat</button>
</form>
```

**`Index.cshtml.cs`** (model):

```csharp
public class IndexModel : PageModel
{
    public string Uzivatel { get; set; } = "axo";

    [BindProperty]
    [Required(ErrorMessage = "Zpráva je povinná")]
    [StringLength(500)]
    public string Zprava { get; set; }

    public void OnGet()
    {
        // spustí se při GET requestu
    }

    public IActionResult OnPost()
    {
        if (!ModelState.IsValid)
        {
            return Page();   // znovu zobrazí stránku s validačními chybami
        }

        // zpracovat data...
        return RedirectToPage("/Success");
    }
}
```

### `@page` direktiva

První řádek `.cshtml` souboru. Říká frameworku "tohle je Razor Page, ne jen view". Bez ní by se stránka přes URL nedala otevřít.

### Routing v Razor Pages

URL se odvozuje od umístění v `/Pages` složce:

| Soubor | URL |
| --- | --- |
| `Pages/Index.cshtml` | `/` nebo `/Index` |
| `Pages/About.cshtml` | `/About` |
| `Pages/Products/Index.cshtml` | `/Products` |
| `Pages/Products/Detail.cshtml` | `/Products/Detail` |

### Route parametry

```csharp
@page "{id:int}"
@model DetailModel
```

URL `/Products/Detail/69` → handler dostane `id = 69`.

```csharp
public void OnGet(int id) { /* ... */ }
```

# Handlery

Handlery jsou metody v PageModelu, které zpracovávají HTTP requesty.

### Základní handlery

| Handler | Spustí se při |
| --- | --- |
| `OnGet()` | GET request (otevření stránky) |
| `OnPost()` | POST request (odeslání formuláře) |
| `OnGetAsync()` | Asynchronní GET |
| `OnPostAsync()` | Asynchronní POST |
| `OnPut()`, `OnDelete()` | Další HTTP metody (méně časté pro Razor Pages) |

### Návratové typy

csharp

```csharp
public void OnGet()              // void: vyrenderuje stránku
public IActionResult OnGet()     // může vrátit různé výsledky:
{
    return Page();                          // vyrenderuje stránku
    return Redirect("/Home");               // 302 redirect
    return RedirectToPage("/Index");        // redirect na jinou Razor Page
    return NotFound();                       // 404
    return BadRequest();                     // 400
    return new JsonResult(data);             // JSON odpověď
    return File(bytes, "application/pdf");   // soubor ke stažení
}
```

### Pojmenované handlery

Jedna stránka může mít víc handlerů pro stejnou HTTP metodu, rozlišené názvem:

**V HTML:**

```html
<form method="post">
  <button asp-page-handler="Save">Uložit</button>
  <button asp-page-handler="Delete">Smazat</button>
  <button asp-page-handler="Cancel">Zrušit</button>
</form>
```

**V PageModelu:**

```csharp
public IActionResult OnPostSave()    { /* uložit */ return RedirectToPage(); }
public IActionResult OnPostDelete()  { /* smazat */ return RedirectToPage(); }
public IActionResult OnPostCancel()  { /* zrušit */ return Page(); }
```

ASP.NET podle parametru `handler` v requestu zvolí správnou metodu.

**Předávání parametrů**

```csharp
// URL: /Products?id=69&category=tech
public void OnGet(int id, string category)
{
    // id = 69, category = "tech"
}

// Z routy: @page "{id:int}"
public void OnGet(int id) { }

// Z těla requestu (binding)
[BindProperty]
public Product Product { get; set; }

public void OnPost() { /* Product je naplněn */ }
```

# **Model Binding a validace**

**Model Binding** automaticky převede data z requestu (formulář, query, route, JSON) na objekty C#.

### Zdroje bindingu

| Atribut | Zdroj |
| --- | --- |
| `[FromForm]` | Form data |
| `[FromQuery]` | Query string |
| `[FromRoute]` | URL parametry |
| `[FromBody]` | Tělo requestu (JSON) |
| `[FromHeader]` | HTTP hlavička |
| `[FromServices]` | DI kontejner |
| `[BindProperty]` | Form data (pro PageModel properties) |

**Validační atributy**

```csharp
public class UserInput
{
    [Required(ErrorMessage = "Jméno je povinné")]
    [StringLength(50, MinimumLength = 2)]
    public string Name { get; set; }

    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Range(18, 120)]
    public int Age { get; set; }

    [RegularExpression(@"^\+?\d{9,15}$")]
    public string Phone { get; set; }

    [Url]
    public string Website { get; set; }

    [Compare(nameof(Password))]
    public string PasswordConfirm { get; set; }
}
```

**Kontrola validace**

```csharp
public IActionResult OnPost()
{
    if (!ModelState.IsValid)
    {
        return Page();   // zobrazí stránku s chybami
    }
    // pokračovat...
}
```

`ModelState` obsahuje všechny validační chyby. V Razor šabloně se zobrazují přes `<span asp-validation-for="Property">`.

# Razor syntaxe

**Razor** umožňuje vkládat **C# do HTML**. Přepínání pomocí `@`.

### Základy

```csharp
@* Komentář v Razoru *@

<!-- Výpis hodnoty -->
<h1>@Model.Jmeno</h1>
<p>Věk: @Model.Vek</p>

<!-- Inline výraz -->
<p>Stáří: @(2026 - Model.RokNarozeni) let</p>

<!-- C# blok -->
@{
    var pozdrav = "Ahoj";
    var dnes = DateTime.Now;
    var jmeno = Model.Jmeno?.ToUpper() ?? "ANONYM";
}
<p>@pozdrav, @jmeno! Dnes je @dnes.ToShortDateString().</p>

<!-- Raw HTML (nesanitizovaný, používat opatrně) -->
<div>@Html.Raw(Model.HtmlObsah)</div>
```

### Podmínky

```csharp
@if (Model.IsAdmin)
{
    <p>Jsi administrátor</p>
}
else if (Model.IsModerator)
{
    <p>Jsi moderátor</p>
}
else
{
    <p>Jsi běžný uživatel</p>
}

@* Ternární výraz *@
<span class="@(Model.IsActive ? "active" : "inactive")">Status</span>
```

### Cykly

```csharp
<ul>
@foreach (var item in Model.Seznam)
{
    <li>
        <strong>@item.Nazev</strong>
        @if (item.Discount > 0)
        {
            <span>(sleva @item.Discount%)</span>
        }
    </li>
}
</ul>

@for (int i = 0; i < 5; i++)
{
    <p>Řádek @i</p>
}
```

### **Lokální funkce v Razoru**

```csharp
@{
    string FormatPrice(decimal price) => $"{price:F2} Kč";
}

<p>Cena: @FormatPrice(Model.Price)</p>
```

### Escapování

```csharp
@* Symbol "@" v textu se píše dvakrát *@
<p>Napiš email@@example.com</p>

@* Sekvence s mezerou je textem *@
<p>Cena: @Model.Price @("Kč")</p>
```

# Tag Helpers

**Tag Helpers** jsou C# rozšíření HTML atributů. Generují HTML automaticky, znají URL routing a model binding.

```csharp
@* Místo: <a href="/Products/Detail?id=69">Detail</a> *@
<a asp-page="/Products/Detail" asp-route-id="69">Detail</a>

@* Formulářové prvky napojené na model *@
<form method="post">
    <label asp-for="Email"></label>           @* <label for="Email">Email</label> *@
    <input asp-for="Email" />                 @* <input type="email" id="Email" name="Email" /> *@
    <span asp-validation-for="Email"></span>  @* validační chyba pro Email *@
    <button type="submit">Odeslat</button>
</form>
```

### Nejpoužívanější Tag Helpers

| Helper | Co dělá |
| --- | --- |
| `asp-for` | Bind input/label na property modelu (i s type podle datového typu) |
| `asp-page` | URL pro Razor Page |
| `asp-action` / `asp-controller` | URL pro MVC akci |
| `asp-route-{param}` | Hodnota parametru v route |
| `asp-validation-for` | Validační chyba pro property |
| `asp-validation-summary` | Souhrn všech chyb |
| `asp-items` | Naplnit `<select>` z kolekce |
| `asp-anti-forgery` | CSRF token (default v `<form>`) |
| `asp-append-version` | Cache busting pro CSS/JS |

### **Příklad: `<select>`**

```csharp
@* Místo ručního foreach: *@
<select asp-for="CategoryId" asp-items="Model.Categories"></select>

@* V PageModelu: *@
public SelectList Categories { get; set; }

public void OnGet()
{
    Categories = new SelectList(_db.Categories, "Id", "Name");
}
```

# Layout a partial views

### `_Layout.cshtml` (sdílený layout)

```csharp
<!DOCTYPE html>
<html lang="cs">
<head>
    <meta charset="utf-8" />
    <title>@ViewData["Title"] - MojeApp</title>
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav>...</nav>
    </header>

    <main>
        @RenderBody()   @* obsah konkrétní stránky *@
    </main>

    <footer>
        @await Html.PartialAsync("_Footer")
    </footer>

    @RenderSection("Scripts", required: false)
</body>
</html>
```

**`_ViewStart.cshtml`**

Nastavuje Layout pro všechny stránky:

```csharp
@{
    Layout = "_Layout";
}
```

**`_ViewImports.cshtml`**
Globální `@using` a `@addTagHelper`:

```csharp
@using MojeApp
@using MojeApp.Models
@namespace MojeApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
```

### Partial views

Znovu použitelné kusy HTML:

```csharp
@* Pages/Shared/_UserCard.cshtml *@
@model User
<div class="card">
    <h3>@Model.Name</h3>
    <p>@Model.Email</p>
</div>
```

```csharp
@* Použití *@
<partial name="_UserCard" model="someUser" />
```

# Služby a Dependency Injection

**Služba** je třída s business logikou. **Dependency Injection (DI)** je vzor, kdy si třídy nevyrábí závislosti samy, ale dostávají je zvenku (typicky přes konstruktor).

### Životní cyklus služeb

| Typ | Popis | Kdy použít |
| --- | --- | --- |
| **Singleton** | Jedna instance pro celou aplikaci | Cache, logger, sdílený stav |
| **Scoped** | Jedna instance na HTTP request | DbContext, business logika s requestním stavem |
| **Transient** | Nová instance při každém použití | Lehké bezstavové služby |

### Příklad vlastní služby

**`Services/IDatumService.cs`** (rozhraní):

```csharp
public interface IDatumService
{
    string ZiskejCas();
    DateTime DalsiPracovniDen(DateTime start);
}
```

**`Services/DatumService.cs`** (implementace):

```csharp
public class DatumService : IDatumService
{
    public string ZiskejCas() => DateTime.Now.ToString("HH:mm:ss");

    public DateTime DalsiPracovniDen(DateTime start)
    {
        var day = start.AddDays(1);
        while (day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday)
            day = day.AddDays(1);
        return day;
    }
}
```

**`Program.cs`** (registrace):

```csharp
builder.Services.AddScoped<IDatumService, DatumService>();
// nebo: AddSingleton<>, AddTransient<>
```

**Použití v PageModelu:**

```csharp
public class IndexModel : PageModel
{
    private readonly IDatumService _datumService;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(IDatumService datumService, ILogger<IndexModel> logger)
    {
        _datumService = datumService;
        _logger = logger;
    }

    public string Cas { get; set; }

    public void OnGet()
    {
        Cas = _datumService.ZiskejCas();
        _logger.LogInformation("Načtena stránka v {time}", Cas);
    }
}
```

### Výhody DI

- **Testovatelnost**: v unit testech podstrčíš mock místo reálné služby
- **Vyměnitelnost**: změníš implementaci v `Program.cs`, kód komponent nezmění
- **Loose coupling**: komponenty závisí na rozhraních, ne na konkrétních třídách
- **Lifecycle management**: framework řeší vytváření a likvidaci

# Konfigurace aplikace

### `appsettings.json`

Centrální konfigurační soubor. Nastavení **se nepíše do kódu**.

```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MojeDB;Trusted_Connection=True;"
  },
  "MojeNastaveni": {
    "Pozdrav": "Ahoj světe",
    "MaxPocetZaznamu": 67,
    "Email": "axo@example.com"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
```

### Environment-specific konfigurace

ASP.NET načítá soubory v tomto pořadí (pozdější přepisuje):

1. appsettings.json
2. appsettings.{Environment}.json (Development / Staging / Production)
3. User Secrets (jen v Development)
4. Environment variables
5. Command-line arguments

```json
// appsettings.Development.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Debug"
    }
  }
}
```

**Čtení konfigurace v C#**

```csharp
public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public void OnGet()
    {
        var pozdrav = _config["MojeNastaveni:Pozdrav"];
        var max = _config.GetValue<int>("MojeNastaveni:MaxPocetZaznamu");
        var connString = _config.GetConnectionString("DefaultConnection");
    }
}
```

**Strongly typed konfigurace (lepší)**

```csharp
// Models/MojeNastaveni.cs
public class MojeNastaveni
{
    public string Pozdrav { get; set; }
    public int MaxPocetZaznamu { get; set; }
    public string Email { get; set; }
}

// Program.cs
builder.Services.Configure<MojeNastaveni>(
    builder.Configuration.GetSection("MojeNastaveni"));

// V PageModelu
public IndexModel(IOptions<MojeNastaveni> options)
{
    _settings = options.Value;
}
```

### Citlivá data: User Secrets

V developmentu **NIKDY** nepiš hesla do `appsettings.json` (commitne se do gitu).

```bash
dotnet user-secrets init
dotnet user-secrets set "ApiKeys:Stripe" "sk_test_67xyz..."
```

Data se uloží mimo projektovou složku (v profilu uživatele) a načítají se jen v Development environmentu.

**`Program.cs` v .NET 6+ (top-level statements)**

```csharp
var builder = WebApplication.CreateBuilder(args);

// === Konfigurace služeb ===
builder.Services.AddRazorPages();
builder.Services.AddScoped<IDatumService, DatumService>();
builder.Services.AddDbContext<AppDbContext>(opts =>
    opts.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddAuthentication("Cookies").AddCookie();

var app = builder.Build();

// === Middleware pipeline ===
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();

app.Run();
```

# Entity Framework Core (ORM)

**Entity Framework Core** je ORM (Object-Relational Mapper) od Microsoftu. Místo psaní SQL pracuješ s C# objekty, EF Core za tebe generuje SQL dotazy.
****

### DbContext

```csharp
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<User> Users { get; set; }
    public DbSet<Post> Posts { get; set; }
}
```

### Modely (entity)

```csharp
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime CreatedAt { get; set; }

    public List<Post> Posts { get; set; }   // navigation property
}
```

**Použití v PageModelu**

```csharp
public class IndexModel : PageModel
{
    private readonly AppDbContext _db;

    public IndexModel(AppDbContext db) { _db = db; }

    public List<User> Users { get; set; }

    public async Task OnGetAsync()
    {
        Users = await _db.Users
            .Where(u => u.CreatedAt > DateTime.Now.AddDays(-30))
            .OrderBy(u => u.Name)
            .ToListAsync();
    }
}
```

Migrace

```bash
dotnet ef migrations add InitialCreate
dotnet ef database update
```

EF Core porovná model s aktuální DB a vygeneruje SQL pro úpravy schématu.

# **Předávání dat mezi requesty**

| Mechanismus | Životnost | Použití |
| --- | --- | --- |
| **PageModel property** | Per request | Standardní (s `[BindProperty]`) |
| **TempData** | Přežije jeden redirect | Success/error zprávy po POST→Redirect→GET |
| **ViewData** / **ViewBag** | Per request | Sdílení s layoutem (preferovat strongly-typed model) |
| **Session** | Per uživatelská session | Košík, multi-step formulář |
| **Cache** | Aplikace-wide | Sdílená data, drahé výpočty |

```csharp
public IActionResult OnPostSave()
{
    // ... uložit ...
    TempData["Success"] = "Uloženo!";
    return RedirectToPage("/Index");
}
```

```csharp
@if (TempData["Success"] != null)
{
    <div class="alert alert-success">@TempData["Success"]</div>
}
```

# Logování

ASP.NET má vestavěné logování přes `ILogger<T>`:

```csharp
public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(ILogger<IndexModel> logger) { _logger = logger; }

    public void OnGet()
    {
        _logger.LogInformation("Stránka navštívena uživatelem {User}", User.Identity.Name);
        _logger.LogWarning("Něco neobvyklého");
        _logger.LogError(exception, "Chyba při zpracování");
    }
}
```

Úrovně logů: `Trace < Debug < Information < Warning < Error < Critical`.

Konfigurace minimální úrovně v `appsettings.json` (sekce `Logging`).

## 17 • Rychlý tahák

| Pojem | Klíčová fakta |
| --- | --- |
| **ASP.NET Core** | Cross-platform, moderní, .NET 10 (2026) |
| **ASP.NET Framework** | Legacy, jen Windows, žádné nové features |
| **Razor Pages** | Page-focused, `.cshtml` + `.cshtml.cs` |
| **MVC** | Model-View-Controller pro větší projekty |
| **Minimal API** | Lightweight API bez kontrolerů |
| **Blazor** | C# v prohlížeči (Server, WASM, Hybrid) |
| **Kestrel** | Vestavěný HTTP server |
| **Reverzní proxy** | Nginx/IIS před Kestrelem (TLS, load balance) |
| **Middleware** | Pipeline komponent, pořadí kritické |
| **`@page`** | Direktiva pro Razor Page |
| **`OnGet()`, `OnPost()`** | Handlery pro HTTP metody |
| **Pojmenované handlery** | `OnPostSave()`, `OnPostDelete()` |
| **`[BindProperty]`** | Auto-binding form dat na property |
| **Model Binding** | `[FromForm]`, `[FromQuery]`, `[FromRoute]`, `[FromBody]` |
| **Validace** | `[Required]`, `[EmailAddress]`, `[Range]`, `ModelState.IsValid` |
| **Razor `@`** | Přepnutí do C# v HTML |
| **Tag Helpers** | `asp-for`, `asp-page`, `asp-route-*`, `asp-validation-for` |
| **`_Layout.cshtml`** | Sdílený layout |
| **`_ViewStart.cshtml`** | Globální nastavení Layout |
| **DI** | Singleton / Scoped / Transient |
| **Singleton** | Jedna instance celkem |
| **Scoped** | Jedna na HTTP request |
| **Transient** | Vždy nová |
| **`appsettings.json`** | Centrální konfigurace |
| **Environment** | `appsettings.{Env}.json`, User Secrets pro dev |
| **`Program.cs`** | Vstupní bod, registrace + pipeline |
| **EF Core** | ORM, `DbContext`, `DbSet`, migrace |
| **TempData** | Survives one redirect (success/error zprávy) |

---

## 18 • Tipy pro ústní zkoušku

### Jak začít

> *"ASP.NET je framework od Microsoftu pro vývoj webových aplikací. Píše se v C# a běží nad .NET platformou, aktuálně .NET 10 LTS. Podporuje různé typy aplikací: Razor Pages pro klasické weby, MVC pro komplexní projekty, Web API pro REST, Minimal API pro mikroslužby a Blazor pro SPA v C#. Můžu se zaměřit na konkrétní téma."*
> 

### Co komise typicky chce slyšet

- **Rozdíl ASP.NET Framework vs ASP.NET Core** (legacy vs moderní cross-platform).
- **Typy aplikací** (Razor Pages, MVC, Web API, Blazor).
- **Flow requestu**: Internet → Reverzní proxy → Kestrel → Middleware → Endpoint.
- **Handlery** v PageModelu, pojmenované handlery.
- **DI lifetimes** (Singleton, Scoped, Transient) s konkrétními příklady.
- **Konfigurace v `appsettings.json`** a proč ne hardcoded.
- **Razor syntaxe**: `@`, `@if`, `@foreach`, `@Model`.

### Doplňky, které komisi potěší

- **.NET 10 LTS** od listopadu 2025.
- **Tag Helpers** jako moderní alternativa k HTML atributům.
- **Model Binding** s `[FromForm]`, `[FromQuery]`, atd.
- **Validační atributy** ([Required], [EmailAddress]) a `ModelState`.
- **Captive Dependency** problem (scoped do singleton).
- **User Secrets** pro citlivá data v development.
- **Environment-specific konfigurace** (`appsettings.Development.json`).
- **EF Core** jako ORM, migrace.
- **`Program.cs` top-level statements** od .NET 6.

### Časté chytáky

| Otázka | Odpověď |
| --- | --- |
| *Rozdíl ASP.NET Framework a ASP.NET Core?* | Framework je legacy jen pro Windows, Core je moderní cross-platform a aktivně vyvíjený. |
| *Co je Kestrel?* | Vestavěný HTTP server ASP.NET Core. V produkci za reverzní proxy. |
| *Kdy Singleton, Scoped, Transient?* | Singleton = sdílený stav (cache, logger). Scoped = per request (DbContext). Transient = bezstavové. |
| *Proč nemít citlivé klíče v appsettings.json?* | Soubor se commituje do gitu. Pro Development je User Secrets, pro Production environment variables. |
| *Co dělá `[BindProperty]`?* | Říká frameworku, aby property automaticky naplnil z form data při POST requestu. |
| *Proč pojmenované handlery?* | Jedna stránka může mít víc POST akcí (Save, Delete, Cancel). Rozliší se podle `asp-page-handler`. |
| *Co je `@page` direktiva?* | Označuje soubor jako Razor Page (ne jen view). Musí být první řádek `.cshtml`. |
| *Co je middleware pipeline?* | Řada komponent, kterými prochází request. Pořadí má význam (Auth před Authorization). |