6. diel - Obsluha formulárov v ASP.NET Core MVC
V predchádzajúcom kvíze, Kvíz - MVC, pohľad, middleware, routovanie v ASP.NET Core MVC, sme si overili nadobudnuté skúsenosti z predchádzajúcich lekcií.
V dnešnej lekcii ASP.NET Core si vyskúšame techniku
napojenia modelu priamo na View. Tejto technike sa hovorí
model binding a hodí sa najmä pri práci s formulármi.
Programovať budeme jednoduchú kalkulačku.
Vytvoríme si nový projekt podľa šablóny ASP.NET Core Web App
(Model-View-Controller), ktorý pomenujeme MVCCalculator:

Touto šablónou nám budú vygenerované jednotlivé
zložky pre MVC komponenty a nastavené východiskové
routy a konfigurácie, ktoré sme minule robili
ručne. Ďalej nám bude vygenerovaná aj zložka wwwroot/ pre
statický (nemenný) obsah webu. Tu budeme umiestňovať napríklad obrázky, CSS súbory alebo JavaScript
súbory. Visual Studio nám sem do zložky
lib/ taktiež automaticky pridalo populárne knižnice Bootstrap a jQuery. Minule sme túto šablónu
nevyužili, aby sme lepšie pochopili, ako ASP.NET Core a architektúra MVC
funguje.
Ako názov projektu nepoužívajte len
Calculator, pretože by kolidoval s názvom našej triedy, ktorú
si ďalej vytvoríme.
Bude nám vygenerovaný aj ukážkový projekt. Môžeme si ho skúsiť spustiť:

My tento projekt nebudeme potrebovať, a preto vyprázdnime všetok obsah
zložiek Models/, Controllers/ a Views/ v
okne Solution Explorer. Ponecháme si však súbor
Views/_ViewImports.cshtml, inak by nám správne nefungovali tzv.
tag helpers (viď ďalej).
Ak by sme začínali s prázdnym projektom ako minule, museli by sme tento súbor pridať ručne.
Rovnako si ukážme, ako bude naša hotová kalkulačka vyzerať:

Model
Začnime opäť modelom, ktorým bude trieda Calculator. Tú si
vytvoríme v zložke Models/.
Vlastnosti
Modelu pridáme niekoľko verejných vlastností, konkrétne dve
vstupné čísla, vybranú operáciu a
výsledok. Poslednou vlastnosťou bude zoznam
typu SelectListItem, ktorý bude obsahovať možné operácie pre
pohľad. Ten z nich následne vyrenderuje HTML element
<select>. Zoznam rovno naplníme v konštruktore:
public class Calculator { public int FirstNumber { get; set; } public int SecondNumber { get; set; } public double Result { get; private set; } public string Operation { get; set; } public List<SelectListItem> AvailableOperations { get; private set; } public Calculator() { Operation = "+"; AvailableOperations = [ new SelectListItem { Text = "Add", Value = "+", Selected = true }, new SelectListItem { Text = "Subtract", Value = "-" }, new SelectListItem { Text = "Multiply", Value = "*" }, new SelectListItem { Text = "Divide", Value = "/" } ]; } }
Vlastnosť Text triedy SelectListItem je popis
možnosti, ktorú vidí používateľ. Value je hodnota, ktorá sa
odosiela na server (nemala by obsahovať diakritiku). Môžeme nastaviť aj
vlastnosť Selected, ktorá označuje, či má byť položka pri
zobrazení stránky vybraná.
Nezabudneme na pridanie
using Microsoft.AspNetCore.Mvc.Rendering pre typ
SelectListItem.
Metóda CalculateResult()
Zostáva len metóda s nejakou logikou, ktorá podľa zvolenej operácie a
hodnôt v FirstNumber a SecondNumber vypočíta
výsledok:
public void CalculateResult() { Result = Operation switch { "+" => FirstNumber + SecondNumber, "-" => FirstNumber - SecondNumber, "*" => FirstNumber * SecondNumber, "/" => FirstNumber / SecondNumber, _ => 0 }; }
Výsledok sa po zavolaní metódy uloží do vlastnosti Result.
Rovnako tak by sme ho mohli aj vrátiť, ako sme to robili v minulom projekte s
náhodným číslom. Pre naše ďalšie zámery s bindingom to ale bude takto
výhodnejšie.
Namiesto klasického switch tu využívame jeho úspornejší
variant, ktorý máme k dispozícii od C# 9 a ktorý sa práve v tejto
situácii hodí, pretože nám značne zjednoduší kód.
Model máme hotový, pridajme si kontrolér.
Controller
Kontrolér budeme mať v našej aplikácii zase len jeden. Určite si spomíname, že kontrolér slúži na prepojenie modelu (logiky) a pohľadu (HTML šablóny).
Do zložky Controllers/ si pridáme nový MVC
Controller-Empty a pomenujeme ho HomeController. Tento
kontrolér sa spustí pri vstupe na predvolenú stránku aplikácie, pretože je
naň v súbore Program.cs nasmerovaná predvolená URL adresa.
Prejdime do jeho kódu a akciu Index() upravme do nasledujúcej
podoby:
public IActionResult Index() { Calculator calculator = new Calculator(); return View(calculator); }
Pri vstupe na stránku sa zavolá akcia Index(), to už vieme.
Vtedy vytvoríme novú inštanciu modelu, čo je stále rovnaké ako minule.
Novo však model odovzdáme pohľadu ako parameter.
Nezabudneme na pridanie using MVCCalculator.Models
pre Calculator.
View
Pre akciu Index() vygenerujeme pohľad. To urobíme opäť
kliknutím pravým tlačidlom kamkoľvek do akcie, zvolením Add
View... a potom Razor View (nie Razor View - Empty). Ako
Template zvolíme Create a Model class nastavíme na
Calculator. Nezabudneme odškrtnúť možnosť Use
a layout page, aby sme mali v pohľade zahrnutú aj základnú HTML
štruktúru:

Template nám umožňuje do pohľadu rovno predgenerovať nejaký kód, tejto technike sa hovorí scaffolding. Template Create vygeneruje pohľad napojený na zvolený model ak vlastnostiam tohto modelu vygeneruje formulár pre vytvorenie inštancie modelu. Keď aplikáciu teraz spustíme, vyzerá takto:

Vidíme, že Visual Studio vygenerovalo celkom štyri vstupy. Dva pre
čísla a po jednom pre výsledok a
operáciu. Operáciu však budeme chcieť zadávať pomocou
elementu <select> a výsledok nebudeme vypisovať do
formulárového poľa, ale do HTML odseku <p>.
Pohľad Index
Presunieme sa preto do súboru Index.cshtml a zmeníme ho do
nasledujúcej podoby:
@model MVCCalculator.Models.Calculator <!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width" /> <title>Calculator</title> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> </head> <body class="m-3"> <h1>Calculator</h1> <div class="row"> <div class="col-md-4"> <form asp-action="Index"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="FirstNumber"></label> <input asp-for="FirstNumber" class="form-control" /> <span asp-validation-for="FirstNumber" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="SecondNumber"></label> <input asp-for="SecondNumber" class="form-control" /> <span asp-validation-for="SecondNumber" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Operation"></label> @Html.DropDownListFor(model => model.Operation, new SelectList(Model.AvailableOperations, "Value", "Text"), new { @class = "form-select" }) <span asp-validation-for="Operation" class="text-danger"></span> </div> <div class="form-group mt-3"> <input type="submit" value="Calculate" class="btn btn-primary" /> </div> <p class="h3 mt-3">@Model.Result</p> </form> </div> </div> <script src="~/lib/jquery/dist/jquery.min.js"></script> @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } </body> </html>
Zmien sme oproti pôvodnej podobe šablóny až tak veľmi nevykonali. Na
úplnom začiatku šablóny vidíme nastavenie typu modelu
@model MVCCalculator.Models.Calculator, na ktorý je pohľad
nabindovaný (naviazaný). Ďalej sme v hlavičke stránky
<head> nastavili titulok stránky a
nalinkovali knižnicu Bootstrap s
predpripravenými CSS triedami, ktoré využívame na štýlovanie celej
stránky.
Všimnime si použitie vlnovky (~) na získanie
cesty do zložky wwwroot/, kde sa zložka s knižnicou Bootstrap nachádza.
Obsah stránky sme obalili do elementu <body>, na ktorého
začiatok sme umiestnili nadpis. Nasleduje formulár, ktorý vygenerovalo Visual
Studio a ktorý sme iba upravili. Na konci formulára vypisujeme vlastnosť
Result modelu Calculator do HTML odseku
<p>, čím ho zobrazíme používateľovi.
Tag helpers
Jednotlivé editačné polia pre vlastnosti modelu vkladáme týmto štýlom:
<div class="form-group"> <label asp-for="PropertyName"></label> <input asp-for="PropertyName" class="form-control" /> <span asp-validation-for="PropertyName" class="text-danger"></span> </div>
Atribúty asp-for sú tzv. tag helpers, pomocou
ktorých dokáže ASP.NET Core vygenerovať pre našu vlastnosť vhodný
ovládací prvok. Napríklad pre dátum sa vloží
DatePicker a podobne. Tento atribút zároveň zaisťuje prepojenie
popisu <label> so zodpovedajúcim vstupom
<input>.
Chybové hlášky
Atribút asp-validation-for vloží priestor na výpis
chybovej hlášky v prípade, že používateľ pole zle
vyplní. To sa zistí z dátového typu vlastnosti alebo prípadne pomocou
špeciálnych validačných atribútov (o tých si ešte povieme ďalej v
kurze). Všetko teda funguje úplne automaticky. Drobnou nevýhodou je, že
danú vlastnosť odovzdávame helperu ako text. Visual Studio nám našťastie
správnosť kódu dokáže skontrolovať aj tak.
Atribút asp-validation-summary na elemente
<div> umiestnenom na začiatku formulára zaistí zobrazenie
zhrnutia všetkých chýb, ktoré pri spracovaní formulára
nastanú:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
Tento atribút môže nadobúdať jednu z troch hodnôt:
All– vypíšu sa všetky chyby,ModelOnly– vypíšu sa všetky chyby okrem tých spôsobených zlým vyplnením poľa,None– nevypíšu sa žiadne chyby.
My používame hodnotu ModelOnly, ktorá je vhodná v
kombinácii s atribútom asp-validation-for. Chyby spôsobené
nesprávnym vyplnením poľa sa zobrazia priamo pri danom poli. Zvyšné chyby
sa potom zobrazia na začiatku formulára.
V rámci tag helpers máme k dispozícii aj niektoré špeciálne HTML elementy.
HTML helper
Môžeme vidieť, že kombinujeme tag helpers so starším systémom
vkladania ovládacích prvkov pomocou tzv. HTML helperu typu
IHtmlHelper. Nie všetky ovládacie prvky sú totiž v súčasnosti
tag helpermi podporované, niekedy sa tomuto riešeniu preto nevyhneme. K
inštancii tohto helperu pristupujeme cez vlastnosť Html
(@Html).
Týmto spôsobom napríklad pridávame pomocou metódy
DropDownListFor() element <select> na výber
operácie. Tejto metóde odovzdávame tri argumenty:
- názov vlastnosti, do ktorej sa má uložiť výsledok výberu,
- zoznam položiek výberu typu
SelectLista - anonymný objekt s atribútmi a ich hodnotami, ktoré sa majú pridať vygenerovanému elementu.
Zoznam SelectList vytvárame z položiek uložených v našom
modeli vo vlastnosti AvailableOperations. V konštruktore zoznamu
taktiež musíme definovať, aká vlastnosť položky obsahuje hodnotu a aká
popis danej položky.
Preferujeme napájanie formulárových prvkov na vlastnosti
modelu pomocou tag helperov (napríklad asp-for) ako pomocou
zavináčov. Predsa chceme, aby HTML šablóna vyzerala čo najviac ako HTML
kód 
Akcie formulára
Vráťme sa ešte na chvíľu k samotnému formuláru, ktorému nastavujeme
atribút asp-action. Opäť sa jedná o tag helper z ASP.NET Core,
ktorým hovoríme, na akú akciu sa má obsah formulára
odoslať pri jeho potvrdení (napr. kliknutím na tlačidlo typu
submit). My chceme, aby sa odosielal na akciu Index()
z kontroléra HomeController, preto tomuto atribútu nastavujeme
názov danej akcie Index().
V akom kontroléri sa má akcia hľadať, potom môžeme určiť atribútom
asp-controller. Bez uvedenia tohto atribútu sa akcia hľadá v
kontroléri daného pohľadu. V našom prípade tento atribút teda uvádzať
nemusíme.
Skripty pre validáciu
Vždy je nutné overovať, či dáta, ktoré nám užívateľ posiela, sú v
poriadku a zodpovedajú tomu, čo očakávame. Je teda nutné dáta
validovať. Preto na úplnom konci elementu
<body> pripájame skripty potrebné na správne fungovanie
automatickej validácie vstupov ešte vo webovom
prehliadači.
Tieto skripty sa nachádzajú v súbore
_ValidationScriptsPartial.cshtml, ktorý nám bol vygenerovaný v
priečinku Views/Shared/. Ide o tzv. čiastočný
pohľad (partial view), teda pohľad obsahujúci iba malú,
znovupoužiteľnú časť HTML kódu, ktorú môžeme vkladať do iných
pohľadov. Používame na to asynchrónnu
metódu RenderPartialAsync() HTML helperu, ktorej akurát
odovzdávame názov požadovaného pohľadu.
Pre správne fungovanie vyžadujú validačné skripty ešte aj skripty
knižnice jQuery, ktoré máme v
projekte už predinštalované a ktoré načítame o riadok vyššie pomocou
elementu <script>.
Pohľad _ViewImports
Aby nám tag helpers v projekte fungovali, je potrebné v ňom mať aj súbor
pomenovaný _ViewImports.cshtml s nasledujúcim obsahom:
@using MVCCalculator @using MVCCalculator.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Rovnako ako v C# súboroch, aj v .cshtml súboroch pracujeme s
mennými priestormi, ktoré obsahujú nami používané triedy. Súbor
_ViewImports.cshtml obsahuje príkazy using na
importovanie menných priestorov, ktoré sa majú pripojiť ku každému
pohľadu.
Súbor _ViewImports.cshtml už v projekte máme v
priečinku Views/.
Spustenie aplikácie
Po spustení aplikácie uvidíme takýto formulár:

Po jeho odoslaní sa zatiaľ nič nestane. Pokračovať budeme zase až nabudúce.
V nasledujúcej lekcii, Spracovanie dát a validácia v ASP.NET Core MVC, sa naučíme spracovávať dáta odoslané formulárom. Zmienime sa o fungovaní HTTP a nakoniec zavedieme validačné anotácie v modeloch.
Mal si s čímkoľvek problém? Zdrojový kód vzorovej aplikácie je k stiahnutiu každých pár lekcií. Zatiaľ pokračuj ďalej, a potom si svoju aplikáciu porovnaj so vzorom a ľahko opráv.
