2. diel - Prvá webová aplikácia v ASP.NET Core MVC
V minulej lekcii, Úvod do MVC architektúry v ASP.NET Core , sme si uviedli MVC architektúru. Dnes tieto znalosti využijeme v praxi a naprogramujeme svoju prvú webovú aplikáciu v ASP.NET Core MVC.
Kurz predpokladá základné znalosti C # .NET a HTML. Ak niečomu nebudete rozumieť, prečítajte si najprv základné kurzy k týmto technológiám, kde je všetko potrebné vysvetlené.
Tutoriály píšem pre Visual Studio verziu 2017, rozhranie iných verzií sa môže trochu líšiť, ale určite nijako dramaticky, takže by ste všetko popisované mali nájsť. Pre vývoj v ASP.NET Core 2 a vyšším však potrebujete minimálne Visual Studio 2017 vo verzii 15.3.0 alebo novší, a mať nainštalovaný .NET Core 2.x SDK (prípadne je k stiahnutiu na https://www.microsoft.com/ ... ownload / core).
Založenie projektu
Naša prvá webová aplikácia bude generátor náhodných čísel. Začnime založením nového projektu vo Visual Studio. Nový projekt založíme pomocou hlavného menu File -> New -> Project.
V dialógu vyberieme ako jazyk C #, ako typ projektu ASP.NET Core Web
Application a meno zvolíme MVCNahodneCislo
. Pokiaľ tu kategórii
"ASP.NET Core" nemáte, použite odkaz "Open Visual Studio Installer" v ľavej
časti okna. ASP.NET Core nájdete v kategórii Web & Cloud, v pravej časti
je následne potrebné zaškrtnúť .NET Core development tools for Web.
Akonáhle dialóg potvrdíme, zobrazí sa ďalší s výberom template. Template je předgenerovaná štruktúra projektu. My začneme s prázdnym projektom a preto vyberieme zatiaľ Empty. Uistite sa, že hore máte vybranú verziu ASP.NET Core 2.0 alebo vyšší. Potvrdíme.
Adresárová štruktúra
Hoci sme založili prázdny projekt, Visual Studio aj tak vygenerovalo niekoľko nových súborov. To je preto, že ASP.NET Core je framework, teda hotové riešenie, ktoré iba prispôsobujeme pre náš účel.
V Solution Exploreri po pravej strane pre začiatok klikneme pravým
tlačidlom na projekt a pomocou Add -> New folder vytvoríme zložky
Models
, Views
a Controllers
. Práve sem
pridáme komponenty našej aplikácie tak, ako sme si vysvetľovali v minulej
lekcii.
Model
Začnime modelom. Do zložky Models
pridáme jednoduchú triedu,
ktorú nazveme Generator
. Bude mať nasledujúci obsah:
public class Generator { private Random random = new Random(); public int VratCislo() { return random.Next(100); } }
Trieda nerobí nič iné, než že vracia náhodné číslo z privátnej
inštancie triedy Random
. Prakticky nemá takýto model veľký
zmysel, pre nás je však dôležitý princíp a v budúcnosti budeme úplne
rovnako vracať napr. Článok z databázy. Vytvorili sme teda logickú časť
aplikácie.
Controller
Teraz pridáme Controller
do zložky Controllers
pomocou pravého tlačidla a výberu Add -> Controller. Ako typ vyberieme MVC
Controller - Empty. Ostatné typy nám umožňujú napr. Rovno vygenerovať
pohľady, použijeme ich ďalej v kurze.
Ako meno kontroleru zvolíme HomeController
. Meno kontroleru by
malo vždy končiť na Controller
. HomeController
je
obvyklý názov kontroleru, ktorý sa spustí vo chvíli, keď na stránku
prídeme (bez toho aby sme zadávali ďalšie parametre, teda ako homepage).
Visual Studio nám vygenerovalo novú triedu, ktorá vyzerá takto:
public class HomeController : Controller { public IActionResult Index() { return View(); } }
Metóda Index()
sa na kontroléra zavolá vo chvíli, kedy
užívateľ zadá požiadavku na stránku, ktorú daný kontrolér spravuje.
Práve v tejto metóde vytvoríme inštanciu modelu, získame si od neho dáta a
tieto dáta odovzdáme pohľadu.
Metóda využíva ako návratový typ rozhrania IActionResult
,
ktoré reprezentuje objekt, ktorý po dokončení požiadavke zasielame späť
prehliadači. V našom prípade mu zasielame šablónu (objekt
View
). Rovnako tak mu môžeme zaslať súbor, žiadosť o
presmerovanie alebo napríklad dáta v JSON. Vrátiť môžeme dokonca i len
string
, ktorý sa v prehliadači potom vypíše.
Odovzdanie dát pohľadu
K odovzdaniu dát máme na výber z 3 kolekcií, ktoré sú prístupné tak v kontroleru, tak neskôr v pohľade. V kontroleru kolekcii naplníme dátami z modelu a v pohľade z nej dáta vypíšeme do pripravenej HTML šablóny.
Môžeme použiť kolekcie:
- ViewData - Kolekcia na spôsob
Dictionary
, kam vkladáme jednotlivé ukazovatele pre šablónu pod textové kľúče. Používala sa hlavne predtým, ako C# zaviedol kľúčové slovodynamic
. - ViewBag -
ViewBag
využíva dynamické vlastnosti, ktoré sú v C# .NET od verzie 4.0. Namiesto kľúčov zapisujeme rovno do vlastností, ktoré sa naViewBag
vytvorí. - TempData - Pomerne mätúce kolekcia, slúžiace na odovzdanie dát najmä pri presmerovaní. Dáta sú vymazané po dokončení požiadavke.
Je vlastne jedno, či budeme dáta do šablóny odovzdávať pomocou
ViewBag
alebo ViewData
, keďže ViewBag
interne využíva pre svoje vlastnosti práve ViewData
. To
znamená, že čokoľvek uložíte do ViewBagu
, to bude prístupné
aj ako položka ViewData
a naopak. Výhodou ViewBag
u
je však to, že nemusíme vykonávať konverziu (type casting). Microsoft vo
svojej dokumentácii ale využíva skôr staršie ViewData
, sčasti
je to preto, že ViewBag momentálne nie je dostupný v Razor Pages (iný typ
stránok, ktorý sa dá v Core vytvárať). Na výbere kolekcie príliš
nezáleží.
Niekedy (u architektúry MVVM - Model-View-ViewModel) sa môžete stretnúť aj s posielaním dát pohľade cez k tomu určený objekt naplnený dátami, tzv. ViewModel, tento spôsob si však ukážeme až ďalej v kurze.
Upravme metódu Index()
v kontroleru tak, aby metóda pred
vrátením pohľade získala dáta z modelu a tá uložila do
ViewBag
:
public IActionResult Index() { Generator generator = new Generator(); ViewBag.Cislo = generator.VratCislo(); return View(); }
Aby sme mohli pristúpiť k modelu, je potrebné pridať using
.
Aj keď to všetci určite viete, pre istotu zopakujem, že kliknete na červeno
podčiarknutý názov triedy Generator
a potom na žiarovku vľavo,
kde naklikne pridanie daného using
u. Ak by vám to nefungovalo,
môžete using
pridať aj manuálne ako
using MVCNahodneCislo.Models
na úplný začiatok súboru. V
kontroléru sme hotoví. Zareagovali sme na požiadavku na indexovú stránku a
prepojili model a pohľadom.
View
V našej aplikácii nám teraz chýba šablóna (pohľad), v ktorej výstup
zobrazíme užívateľovi. Pojmy šablóna a pohľad budem v kurze zamieňať a
myslím tým vždy pohľad. View najjednoduchšie pridáme priamo z
príslušného kontroleru. Klikneme pravým kamkoľvek do metódy
Index()
a zvolíme Add View.
Pohľad sa bude volať rovnako ako metóda. Potvrdíme.
Je nám vygenerovaná HTML šablóna s nasledujúcim obsahom:
@{ ViewData["Title"] = "Index"; } <h2>Index</h2>
Na začiatku vidíme zavináč a C# kód. To je syntaxe tzv. Razor engine, ktorý slúži pre vkladanie C# kódu do HTML. Existuje ešte niekoľko ďalších renderovacích enginov, ale takmer sa nepoužívajú.
Už vieme, že všetky logika by mala byť obsiahnutá v modeloch, v pohľadoch budeme C# používať iba k výpisu hotových dát, ktoré sme z modelov získali. Razor direktív by v šablónach malo byť čo možno najmenej.
Určite ste podľa obsahu vygenerovanej šablóny prišli na to, že
šablóna nie je priamo výsledná HTML stránka, ale iba jej časť, ktorá sa
potom vloží do layoutu. Ten však zatiaľ nemáme definovaný, výstup teda
nebude HTML validné, čo u prvého príkladu zanedbáme. V tejto šablóne sa
bude nachádzať iba to, čo je súčasťou jednej konkrétnej podstránky
nášho webu. Šablóne nastavíme jej titulok a vložíme do nej číslo z
modelu pomocou ViewBag
a Razor @
direktívy. Jej kód
bude teraz nasledujúce:
@{ ViewBag.Title = "Online generátor náhodných čísel"; } <h2>Náhodné číslo</h2> <p style="font-size: 2em;">@ViewBag.Cislo</p>
Pôvodné nastavenie titulku cez ViewData
som nahradil
ViewBag
, aby to bolo rovnaké, ale táto zmena nie je nutná.
Číslo vypíšeme z ViewBag
, kam ho uložil kontrolér. Ten ho
získal z modelu, ktorý ho vygeneroval.
Middleware, spracovanie požiadaviek a routovanie
Keby sme našu aplikáciu teraz spustili (Ctrl + F5),
zobrazila by sa iba "Hello World" hláška a náš kontrolér by sa nespustil
vôbec. Keďže sme na začiatku pre názornosť zvolili prázdnu šablónu,
musíme HomeController
najskôr naroutovat, aby sa spustil ako
predvolené. Práve tomuto mechanizmu napojovaní URL adries na kontrolery alebo
inej časti aplikácie sa hovorí routovanie a my ho tentoraz vykonáme v
súbore Startup.cs
. Obsah súboru vyzerá asi nasledovne:
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); }
Do tejto metódy budeme vkladať tzv. Middleware. Tie si v ASP.NET Core
môžeme predstaviť ako sériu filtrov, cez ktoré postupne putuje požiadavku
od užívateľa, než sa nájde ten vhodný, ktorý ho spracuje. Majú podobu
extension metód na rozhraní IApplicationBuilder
(niektorým z
vás pravdepodobne pripomenú návrhový vzor Chain
of responsibility).
Každý middleware v reťazci má iba obmedzenú a špecifickú
úlohu vo spracovanie požiadavky - prvý môže napr. Plniť len funkciu
loggeru, ďalšie middleware bude hľadať nejakú cookie alebo autorizačný
token a či ho nenájde, vráti chybovú hlášku alebo používateľa
presmeruje. Napr. middleware UseFileServer()
nám umožní ako
odpoveď vrátiť statický obsah (skripty v Javascriptu, obrázky, CSS súbory
atď.) nášho projektu a podobne.
Aby sme sa hneď po spustení aplikácie užívateľ nasmeroval na
HomeController
, môžeme použiť middleware
app.UseMvcWithDefaultRoute()
, ktorý vložíme do prostriedku
metódy Configure()
.
Týmto typom middleware, ktoré požiadavka smerujú na kontrolery, sa hovorí ruty.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvcWithDefaultRoute(); // Tento řádek jsme přidali app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); }
Pri spustení aplikácie sa teraz teda spustí HomeController
a
zavolá sa jeho verejná metóda Index()
. Ekvivalentom k
defaultnímu routovanie pomocou UseMvcWithDefaultRoute()
by mohol
byť nasledujúci callback, ktorý by kontrolér a jeho metódu explicitne
nastavoval:
app.UseMvc(routeBuilder => routeBuilder.MapRoute(name: "Default", template: "{controller}/{action}/{id?}", defaults: new { controller = "Home", action = "Index" } ));
My však zostaňme u predchádzajúcej varianty, k routovanie sa bližšie vrátime neskôr. Keď avšak teraz projekt spustíme, čaká nás nepríjemne vyzerajúce error (alebo výnimka priamo vo Visual Studiu):
ASP.NET Core Framework sa skladá z veľkého množstva "granulárnych" služieb a komponentov, ktoré sú pre fungovanie MVC potrebné. Aby všetko mohlo správne fungovať tak, ako očakávame, musíme tieto služby do našej aplikácie najskôr pridať (k čomu nás nabáda i text výnimky).
Presunieme sa preto do metódy ConfigureServices()
a zavolaním
metódy AddMvc()
pridáme do kolekcie služieb pre našu aplikáciu
všetko potrebné pre fungovanie MVC:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); }
Projekt spustíme. Uvidíte nasledujúce, tentoraz správny výsledok:
Port budete mať iný ako ja na screenshote.
Zopakovanie
Ešte si naposledy zopakujme ako celá aplikácia funguje.
Najskôr je požiadavka užívateľa spracovaný našimi Middleware a
přeroutován (posunutý) HomeController
u. Potom je spustená jeho
metóda Index()
. Tá sa spýta modelu na dáta a dáta uloží do
ViewBag
. Následne je vyrenderované pohľad, ktorý pomocou Razor
syntaxe na určité miesta v šablóne vypisuje dáta z Viewbag
.
Hotová stránka je odoslaná užívateľovi.
Zdrojové kódy dnešného projektu sú k stiahnutiu nižšie, bude to tak vo všetkých lekciách. Ak sa vám niečo nepodarilo, môžete si teda nájsť chybu. V budúcej lekcii, Obsluha formulárov v ASP.NET Core MVC , sa pozrieme na obsluhu formulárov.