Jak je každému jasné, tak ASP.NET MVC je založeno na návrhovém vzoru Model-View-Controller. Rozebírat tady přímo tento vzor by bylo trošku kontraproduktivní, protože o něm již bylo napsáno mnoho. Zejména bych vypíchl výborné povídání o MVC na Zdrojáku. Zde bych se rád podíval na to, jak konkrétně je tento vzor implementován v ASP.NET MVC.
Jako základ mého krátkého povídání bych si vzal obrázek vzoru MVC z Wikipedie.
Controller je v ASP.NET MVC reprezentovaný rozhraním IController, které předepisuje implementaci jediné metody Execute. Většinou ale nepracujeme přímo s tímto rozhraním, ale s nějakou vlastní implementací controlleru odvozenou od třídy Controller.
View je nejčastěji reprezentován *.aspx stránkou, která se postará o vyrenderování HTML. Není to ale vůbec podmínkou, např. při použití nějakého alternativního view-enginu. Ale pořád mluvíme o vracení HTML. View přitom nemusí nutně vracet HTML, např. jsou běžné views, které vrací Json (pro další zpracování v JavaScriptu), XML (např. RSS Feed) nebo něco úplně jiného.
Model? Prostě business vrstva. Zde se určitě sluší dodat, že pouze controller a view jsou součástí prezentační vrstvy. Z čehož mimo jiné vyplývá, že controller a view o sobě mohou navzájem vědět (a vědí), kdežto model by měl být naprosto nezávislý na view a controlleru.
Výše uvedené je myslím docela zřejmé a přímo to odpovídá definici MVC. Jak je na tom ale ASP.NET MVC se vztahy mezi jednotlivými částmi?
Závislost controlleru na modelu je zřejmá a logická, protože controller typicky načítá data z business vrstvy, spouští business operace apod.
Závislost view na modelu je také jasná, neboť view zobrazuje data z business vrstvy. V případě klasické *.aspx stránky je tato vazba dána typovým parametrem třídy ViewPage<TModel>.
Závislost controlleru na view já dána tím, že každá action method vrací nějaký ActionResult – a ten je už přímo vazbou na konkrétní view. Např. když v action method voláme „return View();„, tak vracíme ViewResult, které už nese informaci o tom, jaká *.aspx stránka bude vyrenderována.
Závislost view na controlleru už tak zřejmá být nemusí. Tuto vazbu totiž vytváříme vždy, když generujeme nějaký odkaz směřující na zpět do naší aplikace. Např. pomocí „Html.ActionLink(„link“, „Detail“, „Product“)“ generujeme odkaz na action method Detail v controlleru ProductController. Tedy ve view máme zapsánu informaci o tom, že existuje nějaký controller.
Ve výše odkazovaném obrázku se dále vyskytuje vazba modelu na view. Tato vazba by neměla být v žádném případě přímá, tedy neměli bychom business vrstvu přímo vázat s prezentační vrstvou. Tato vazba bývá nejčastěji realizována eventami, které informují view o nějaké změně v modelu. Tento druh vazby není v ASP.NET MVC nějak explicitně podporovaný.
Takřka vše, co bylo až dosud řečeno o ASP.NET MVC, odpovídá vzoru MVC. Jak je ale uvedeno ve výše odkazovaném článku, každá implementace MVC má svá specifika a ASP.NET MVC není výjimkou.
Osobně považuji za nejzásadnější specifikum ASP.NET MVC to, že když chceme předat informace o modelu (tedy business vrstvě) z controlleru do view a chceme to udělat silně typově, tak musíme předat právě jednu instanci. Např. když chceme poeditovat produkt, předáme instanci třídy Product z business vrstvy. Ale ouha, v combo-boxu bychom chtěli zobrazit názvy kategorií, takže je musíme také nějak propašovat do view. Toto se typicky řeší tak, že si vytvoříme jakousi poměrně hloupou třídu, často označovanou jako agregační model nebo view-model, která typicky obsahuje jako properties instance všech typů, které potřebujeme předat do view. V našem příkladu tedy může třída ProductViewModel obsahovat property typu Product a List<Category>.
Zde je důležité si uvědomit, že už trošku specializujeme MVC – místo toho, abychom používali přímo model (business vrstvu) používáme view-model, což můžeme považovat za fasádu k modelu pro účely zobrazení (view). Tím de facto vzniká v aplikaci další vrstva mezi aplikační a prezentační, která pokud je vhodně navržená, tak může být znovupoužita i s jiným GUI frameworkem (WPF, WinForms, WebForms, …). A to se vyplatí! 🙂
Tento koncept lze ale dále velmi zajímavě rozvíjet. View-model totiž nemusí být pouze tupá třída s pár properties, ale můžeme do ní přesunout prezentační logiku, která je typicky obsažena v controlleru a poměrně špatně se tam znovupoužívá. Controllery jsou pak velmi jednoduché a vlastní komunikace s modelem (business vrstvou) je zajišťována view-modelem. Ale o tom podrobněji až někdy příště 🙂 Kdyby byl ale někdo jó nedočkavý, tak něco o této problematice napsal Jarda Jirava…