Vývojářský blog Tomáše Hercega

Tisk článku Tisk článku

Diskuse o MVC a můj názor na něj

[Zpět na blog]

Datum: 4. 6. 2009 14:38       Autor: Tomáš Herceg       Zobrazeno: 2221x

Kategorie: ASP.NET, Život, vesmír a vůbec


Včera jsem se zúčastnil diskuse asp.net MVC Best Practices pořádanou v místní pobočce Microsoftu. Sešlo se tam mnoho zajímavých lidí, nejen ti, kteří dělají v .NETu, ale i lidé, kteří vyvíjejí na jiných platformách, ale používají MVC. Já sám jsem se do diskuse moc nezapojoval, protože můžu srovnávat pouze ASP.NET MVC a ASP.NET WebForms, které tam převážná část diskutujících neznala, ale rád bych tady zareagoval na pár “argumentů” pro MVC, které mi až tolik jako argumenty nepřijdou (ale je to jen proto, že to srovnávám s ASP.NET WebForms). Kdybych ASP.NET nezažil a pracoval dřív jen v PHP, pak bych rozhodně MVC uvítal. Jenže já jsem mezi tím absolvoval WebForms a právě proto se mi MVC (a teď nemyslím jen ASP.NET MVC, ale MVC vzor obecně) nelíbí.

Následující odstavce jsou můj osobní názor na MVC, nenapsal jsem toho v něm tolik, ale myslím, že dost na to, abych si o tom názor udělal. Není to rozhodně špatný přístup architektury aplikací, nicméně v ASP.NET WebForms se mi dělá lépe.

Jen stručně - jak fungují WebForms a jak funguje MVC

ASP.NET WebForms vznikly zhruba před deseti lety a byly svým způsobem revoluční. Oproti klasickému spaghetti kódu se v ASP.NET do stránky daly serverové komponenty (které se zapsaly normálně do HTML stránky) a fungovaly na nich normálním způsobem události, jak je známe třeba z WinForms aplikací. Stav komponent bylo třeba nějak zachovat a někam uložit, vzhledem k tomu, že protokol HTTP je bezstavový, zařídilo se to tak, že celá stránka je formulář a obsahuje mimo jiné skryté pole __VIEWSTATE, které tyto stavové informace drží.

Jednoduše lze oddělit vzhled stránky (markup se serverovými komponentami) a aplikační logika (code behind, který obsahuje obsluhy událostí a samozřejmě mnoho vlastních tříd, který zajištují datovou vrstvu a bussiness logiku; v code behindu by měly být jen obsluhy událostí, manipulace s komponentami a volání funkcí z bussiness vrstvy).

MVC funguje trochu jinak - celá aplikace se dělí na 3 striktně oddělené vrstvy - Model, který obsahuje datovou vrstvu a bussiness logiku (např. zakládání objednávek) se vším všudy, např. validace (jméno objednávky musí být vyplněno). Další vrstvou je Controller, který zpracovává vstupy od uživatele (reaguje na HTTP požadavky a rozhoduje, co se má stát; volá metody z bussiness vrstvy, vytáhne příslušná data z databáze atd.), řeší také oprávnění uživatele, a View, který dostane data od Controlleru a nějakým způsobem je zobrazí (např. vygeneruje HTML). To je velmi stručně řečeno, pokud chcete podrobnější výklad, vřele doporučuji články o MVC od Borka Bernarda, které vyšly na webu http://zdrojak.root.cz.

ASP.NET a tlačítko Zpět

Jeden z argumentů, který včera zazněl, a ke kterému jsem se i vyjadřoval, bylo, že “ASP.NET WebForms aplikace nectí protokol HTTP, že se používá POST místo GETu, že správně nefunguje tlačítko Zpět atd.”

Ano, je pravda, že ASP.NET zachází s HTTP jinak, než ostatní technologie. Pokud je programátor prase a nepozná rozdíl mezi komponentami HyperLink a LinkButton (HyperLink je klasický odkaz na jinou URL, tedy potažmo GET, a LinkButton je odkaz, který pomocí klientského skriptu odesílá formulář, dělá PostBack, potažmo tedy POST), pak se může velmi snadno stát, že i pro operace, pro které se má používat GET, se použije PostBack. Tuhle pitomost dělá co já vím ještě komponenta Calendar, kterou ale stejně nedoporučuji používat, protože generuje strašné HTML.

Stejně tak nekorektní fungování tlačítka Zpět, samozřejmě že v ASP.NET jde napsat aplikace, kde Zpět nebude fungovat správně, ale chce to dost námahy a stane se to akorát lidem, kteří absolutně nechápou, jak HTTP funguje. Tohle prostě není problém ASP.NET WebForms, ale problém programátora. Programovat v ASP.NET tak, abychom správně používali POST a GET nedá žádnou práci navíc, je to naprosto přirozené.

MVC a lepší testování

Obecně si myslím, že většina programátorů v ČR ještě nedospěla k tomu, že kód by měla nějak systematicky testovat. Ano, testujeme všichni tím, že alespoň jednou zkusíme, jestli aplikace jde spustit. U větších aplikací se ale většinou vyplatí strávit čas vytvořením sofistikované sady testů (což mimochodem není nic jednoduchého). “Aplikace v MVC se testují daleko lépe než ostatní aplikace.

Pokud je aplikace zbastlená (tzn. je psaná pomocí spaghetti kódu, nemá pořádnou datovou vrstvu, nebo se píše v ASP.NET a i komplexní logika je v code behindu), nemá stejně smysl testovat a nikdo ji ani testovat nebude. Pokud je to aplikace malá, všeho všudy o deseti stránkách, nemá většinou cenu ani nějakou datovou a business vrstvu dělat (v případě, že víme, že se na aplikaci nebude nic moc nabalovat, pokud ano, je nutné s tím počítat dopředu).

Pokud je aplikace větší a testovat by se měla, tak má stejně nějak vyčleněnou datovou a business vrstvu (model). Ten vypadá víceméně stejně bez ohledu na použitou technologii a testovat se bude také stejně. Pro testování funkčnosti aplikace se používají nějaké automatizované web testy (simulace požadavků a sledování výsledků podle předem daného scénáře), skuteční testeři, kteří aplikaci fyzicky proklikají, případně další způsoby, ale ty jsou také nezávislé na použité technologii a jdou aplikovat prakticky všude.

Co v MVC zbývá? Model otestovaný máme, View také, chybí ještě Controller. Je ten potřeba testovat? Podle mého názoru v drtivé většině případů ne. To, jestli správně funguje autentizace, se dá ošetřit (a také se to tak většinou dělá) spíš pomocí webtestů, a v Controlleru stejně děláme jen to, že zavoláme něco z Modelu, který upraví databázi (což už máme otestované), a pak vytáhneme data a předáme pohledu (což se otestuje webovou částí). Jakákoliv složitější logika nemá stejně v Controlleru co dělat a patří do modelu. Co se tam tedy testuje lépe?

MVC se hodí na všechny typy webových aplikací

Tohle je argument, který se mi nelíbí ani trochu, není ničím podepřen. Pokud má znamenat, že se v MVC dají napsat všechny webové aplikace, pak nezbývá než souhlasit (není ani divu, kdyby MVC nebylo turingovsky úplné, tak by se s ním určitě ani nikdo nezabýval). Problém je v tom, že pořád mám v MVC při programování víc práce (a není to tím, že bych s tím neuměl nebo dělal nějaké koncepční chyby).

Demonstrováno to bylo včera na pěkném příkladu - mám nějakou stránku, na kterou chci přidat komentáře. V Modelu mám vše již nachystané, mám napsanou nějakou komponentu, která komentáře zobrazí.

V ASP.NET WebForms to můžu udělat jednoduše - komponenta prostě sáhne do databáze, vytáhne komentáře a zobrazí je. Není to nic proti ničemu, neporušujeme tím žádný koncept, nemixuji vzhled a logiku dohromady (ve stránce řeknu, co tam má být a jak se to má udělat, o to se vůbec nestarám; v komponentě mám definován vzhled, logika je v modelu a v code behindu jen vytáhnu data a plácnu je do nějakého Repeateru). Vše tedy spočívá jen v tom, že přidám do stránky komponentu.

V MVC musím sáhnout na víc míst - komponentu pro View mám sice již napsanou, ale ona si nemůže sáhnout do modelu (respektive může, ale je to proti architektuře MVC, má to i svá logická opodstatnění, View má být tupá šablona, která jen zobrazuje data, nemá obsahovat žádnou logiku, data má dostat od Controlleru). Musím tedy upravit View (přidat tam na správné místo tu komponentu), a navíc musím upravit Controller, aby předával do View data pro tu komponentu, sama si je vzít nemůže. Je nutné si uvědomit, že Model není databáze, model je soustava tříd, která poskytuje funkce pro práci s daty, samotnou business logiku (třeba evidenci dokumentů, přidávání, odebírání, schvalování, připomínkování atd.). Jak to komunikuje s databází a co je to vlastně za databázi (SQL nebo něco jiného), to už je z hlediska architektury nepodstatné.

Tady je trochu zádrhel - zatímco v ASP.NET z komponenty do modelu sahat můžu, v MVC bych neměl. Já bych správně neměl ani v ASP.NET, ne kvůli konceptu, ale proto, že si tím můžu solidně zavařit a na první pohled není vidět, kolik dotazů do databáze bude a jak to bude s výkonností. Pokud ty komentáře chci zobrazit na třech místech a jedné stránce, tak v ASP.NET si do modelu komponenta sáhne třikrát (když to udělám hloupě; když ne, tak si to model nacacheuje, ale to nemusí být samozřejmost, navíc ne vždy je to takto jednoduché), v MVC jen jednou a všechny “dotazy a žádosti pro data” mám na jednom místě - v Controlleru. Je tedy hned vidět, co stránka bude dělat, je to průhlednější.

To je ale právě to, co mi na tom vadí. Ve WebForms můžu controller jakoby “poskládat z částí” - část je pro komentáře, část je pro články. Pokud budu články zobrazovat na jiné stránce, musím vytahování a předávání šabloně mít na více místech a mám opakující se kód. Komponenty ve WebForms jsou oproti MVC silnější, nahrazují opakující se kód v šabloně i v “controlleru”.

Ano, MVC asi víc programátory vede k tomu, aby psali čistěji. Controller je na jednom místě a není rozcamdaný na části v komponentách. Ve WebForms může neznalý člověk nadělat víc škody (ViewState je sice geniální věc, ale musí se používat tak, aby sloužil a rozhodně ne bezhlavě), v MVC se zase víc nadře a dá to víc práce. Na druhou stranu konkrétně v ASP.NET MVC nejde nějak rozumně zabránit programátorům, aby do View nedávali kód a logiku, která tam nepatří, nejde jim ani pořádně zabránit v tom, aby z View sahali do databáze, což jde proti konceptu a bohužel se to bude tak zneužívat, síla zvyku z PHP je síla zvyku a lidé, kteří dřív bastlili v PHP (a těch je hodně), budou teď bastlit v MVC.

Osobně mám ale raději WebForms. Možná to není tak čisté a v MVC je kontrola nad výstupním kódem, není tam ViewState, ale včerejší diskuse mě nepřesvědčila, spíš utvrdila v tom, že kdo zkusil a ovládl WebForms (tzn. naučil se je pořádně a do hloubky, což není záležitost jednoho týdne), na MVC pravděpodobně nepřejde.

Konkrétně ASP.NET MVC je podle mě krok zpět oproti WebForms, takový návrat k ASP či PHP, nelíbí se mi koncept View jakožto tupé šablony. Právě kvůli tomu jsem utekl od PHP k ASP.NET WebForms a budou muset vymyslet něco mnohem lepšího, aby mě přesvědčili. V každé technologii se dá prasit a v každé technologii se dá psát pořádně.

Odbočka - moje videotutoriály ASP.NET na MSTV.cz a best practices

Pokud sledujete můj videoseriál Začínáme s ASP.NET, který je určen pro lidi, kteří se chtějí s ASP.NET seznámit, nedělejte si iluze, že po jeho shlédnutí budete psát pořádné webové aplikace. ASP.NET se nedá naučit během 20x15 minut, tutoriály jsou k tomu, aby se mohli začátečníci s technologií seznámit a pochopit její principy, které jsou dost odlišné od technologií jiných.

Malé webové aplikace samozřejmě jde klidně psát tak, jak se to v tutoriálech učí, pomocí SqlDataSource atd. Tyto komponenty umožňují napsat jednoduchou stránku za 10 minut a bude to fungovat. Velké aplikace mají samozřejmě datovou a business vrstvu, takže se dají používat stejné komponenty (GridView, Repeater atd.), ale plnit se budou z modelu, ne přímo z databáze. Navíc SqlDataSource jde také dost proti konceptu - v definici vzhledu se definuje i aplikační logika - např. SQL dotazy.

Pokud se ale naučíte, jak funguje SqlDataSource, pochopíte styl a způsob, jakým ASP.NET funguje, pro začátečníky je to ideální. Je to také jediný přístup, který je všude stejný - v každé firmě se velké ASP.NET aplikace píšou jinak, někde mají zakoupené jiné komponenty, model všude vypadá jinak, není žádný společný základ. Navíc nikdo po začátečnících nemůže chtít, aby hned psali profesionálně vyvedené aplikace, důraz se klade na vysvětlení a pochopení principu, protože to je to důležité. Bez této znalosti pak programátoři dělají ty nejhorší chyby.


> Na začátek

 

Hodnocení:

Hlasů: 1
Zvolte své hodnocení

Tomáš Herceg

Autor pochází z Třebíče, kde vystudoval osmileté gymnázium, nyní je studentem druhého ročníku bakalářského studia Matematicko-fyzikální fakulty Univerzity Karlovy v oboru Informatika. Programování se věnuje velmi dlouho a kromě počítačů patří mezi jeho záliby také hra na klavír a matematika. V poslední době tráví většinu času psaním aplikací v jazyce C#, Visual Basic .NET a v ASP.NET.

Podpořte vznik dalších článků
RSS Feed RSS Feed

Diskuse

1 

komponenty

Datum: 4.6.2009 20:45
Autor: Michal Augustýn
Hodnocení autora: 5
Příspěvků: 35
Ohledně přidání komentářů - IMHO se v obou srovnávaných technologiích dělají ty samé kroky. Změna v modelu je stejná. Dále se ve WebForms změní markup, v MVC se změní View. Ve WebForms se změní code-behind, v MVC se změní controller.

Ohledně té komponentovosti. Když se srovnává WebForms a MVC, tak se porovnávají de facto dva různé patterny pro UI - MVP a MVC. Zjednodušeně řečeno, MVP je komponentové (tedy aplikace se rozsekává vertikálně), MVC rozsekává aplikaci horizontálně (striktně odděluje šablonu a prezentační logiku).

Proto je IMHO implementace komponent ve WebForms taková přímočařejší a intuitivnější. U ASP.NET MVC je to ještě "zkomplikováno" tím, že je to více close-to-metal framework než WebForms a vyžaduje větší úsilí pro to, aby se v něm dalo efektivně pracovat. Člověk si tedy musí obstarat nebo napsat různé nadstavby nad ASP.NET MVC, které se budou starat o server-side validaci, client-side validaci, DI container, systém pro správu widgetů, zavést správnou hierarchii view-modelů a jejich chování a další drobnosti, které člověku hodně usnadní práci. Samozřejmě si musí také zvyknout na jiný způsob práce než je u WebForms. Když už člověk má tuhle knownledge base, má de facto vlastní framework postavený nad ASP.NET MVC, ve kterém už může sekat weby jako Baťa cvičky ;-)

Zpět ke komponentám - jestli Tě zajímá, jak pěkně vyřešit widgety (komponenty) v ASP.NET MVC, tak v hlavě to už mám a nejpozději během měsíce to snad sepíšu a hodím na blog.

Jo a tomu, aby kóder nepsal nějaký fuj kód (ideálně aby tam nepsal žádný) do view, se dá v ASP.NET MVC zabránit poměrně jednoduše - použít view-engine, který používá nějaký čistě deklarativní jazyk :D

Abych to shrnul, WebForms a MVC vnímám tak, že v každé jde napsat vše - záleží jen na umu člověka. Pokud člověk skvěle ovládá WebForms a necítí se v něm nějak omezen, tak nevidím problém v tom, když u něj zůstane.
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: komponenty

Datum: 4.6.2009 21:27
Autor: Tomáš Herceg
Hodnocení autora: 999
Příspěvků: 2400
Pokud už ve WebForms mám komponentu napsanou, do code-behindu nic nepíšu, vlastnost s identifikací, k čemu se komentáře vzahují, jí přiřadím deklarativně pomocí databindingu.
Co se týče toho ASP.NET MVC, je to možná jen tím, že není tolik vestavných komponent a člověk si všechno musí řešit sám. Samozřejmě že v obou technologiích jde napsat všechno.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 4.6.2009 21:51
Autor: Michal Augustýn
Hodnocení autora: 5
Příspěvků: 35
Jasně - to je to, o čem jsem psal. ASP.NET MVC je closer-to-metal - tak o něm mluví i samotný Microsoft.

Hlavně MVC prostě není stavěné na komponenty, MVP je. Takže je třeba spíše specifikovat, co je komponenta v MVC světě. Existují dva hlavní přístupy.

Může to být buď "RenderAction" (či partial-request), což znamená, že view ví, že tady se má vyrenderovat nějaká komponenta, tak jakoby pošle lokálně request do MVC, který se o rendering postará. Nevýhodou může být zvýšená výpočetní náročnost a také to, že pokud chceme do komponenty něco předat, musíme to dělat poněkud obstruktivně - ale předat nějaké jednoduché nastavení není problém a více většinou nechceme.
Taková komponenta je pak tedy vlastně takovou malou aplikací - má vlastní controller, view-data i view (model beru jako samozřejmost).

Druhým přístupem (IMHO čistčím z hlediska MVC) je to, že view-model obsahuje kolekci nějakých partikulárních view-data pro jednotlivé komponenty (napadá mě analogie s Controls ve WebForms). View pak vyrenderuje komponentu pomocí RenderPartial a předá jí view-data z již zmíněné kolekce. Bindování probíhá deklarativně na úrovni action methods či rovnou celých controllerů pomocí action filters, které se starají o načtení partikulárních view-data. Komponenta v tomto případě se skládá z partial-view (*.ascx), definice view-dat a action filteru, který načítá data z modelu do view-modelu. Autor nějaké superuniverzální komponenty by měl tedy dodávat pouze *.ascx - třída view-modelu je implicitně jeho součástí. Místo partial-view lze ale také použít extensions metody. Pak stačí, když nám autor komponenty dodá statickou třídu obsahující extensions metody pro helpery a máme vystaráno. Takhle teď fungují např. DropdownListy - to jsou jen extensions methods, kterým se předává SelectList (to je ten mnou zmiňovaný partikulární view-data).

No nějak sem se rozepsal...bych mohl udělat CTRL+C CTRL+V a mám blogspot :D
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: komponenty

Datum: 4.6.2009 22:39
Autor: Jarda Jirava
Hodnocení autora: 5
Příspěvků: 6
Ahoj,
pokud jsi včera dával pozor, tak to docela dobře vystihl Karel Minařík. Vše by mělo být v modelu a stejně jako ty zmiňuješ, že do CodeBehing nic psát nebudeš v případě webforms, tak v MVC taktéž nic psát nemusíš. Důležité je, mít vhodně definovaný onen ViewModel (Model).

Poté by ti taktéž stačilo upravit jen View - šablonu. To jakým způsobem bude vypadat šablona již záleží na použitém ViewEngine. Třeba Aleš to představil tak, že by ona šablona mohla mít velice podobný vzhled jako komponenta ve webforms - byť za ní již nestojí onen codebehing, ale je to skutečně jen prezentační prvek.

Tím se nechci nikterak vymezovat vůči jedné implementaci MVC, na úkor implementace jiné webforms (PageController - taktéž MVC princip) http://msdn.microsoft.com/en-us/library/...

Pěkný den
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 4.6.2009 23:33
Autor: neregistrovaný (89.102.110.57)
Hodnocení autora: není
Příspěvků: 0
Tomáš to patrně myslí tak, že když máš 10 stránek s 10 Controllery a do všech potřebuješ přidat něco, s čím na začátku nebylo počítáno, budeš muset upravit 10 View a 10 Controllerů, aby ty View měly z čeho brát data (za předpokladu, že to "něco" nejde nějak triviálně získat z reference na Model, kterou už View mají).

V případě Web Forms vyvineš komponentu jednou, otevřeš 10 ASPX stránek a tuto komponentu vložíš.

Snad jsem to tak pochopil dobře. I ten druhý, zdánlivě jednodušší přístup, má ale problémy, jak zmínil Tomáš v článku nebo Vlasta při diskusi, takže jen konstatuji, nehodnotím :)
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 4.6.2009 23:36
Autor: neregistrovaný (89.102.110.57)
Hodnocení autora: není
Příspěvků: 0
Ups, nějak jsem si nevšiml, že to po mně nechce autora. Takže se podepíšu teď: Borek
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 5.6.2009 8:36
Autor: Tomáš Herceg
Hodnocení autora: 999
Příspěvků: 2400
Ano, přesně tak to bylo míněno.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 5.6.2009 9:39
Autor: Michal Augustýn
Hodnocení autora: 5
Příspěvků: 35
Ale i v ASP.NET MVC toto lze vyřešit takto pěkně komponentově. Vyvineš komponentu (ve formě extensions metody pro helper) a na deseti stránkách ji desetkrát použiješ (~vložíš).

I ve WebForms pak nějak musíš svázat komponentu s modelem a to v code-behind všech stránek (ať už naklikáním přes binding nebo ručním zápisem). V ASP.NET MVC je to stejné, jen se to děje tam, kde se připravují data, tedy v controlleru. Buď to naprasíš do všech action metod (~napsat to do code-behindu všech stránek) nebo uděláš action filter, který se stará o ládování dat, a ten aplikuješ na dané action metody (tj. přes atributy, tj. deklarativně).

Z hlediska komponentovosti mi tedy přijdou WebForms a MVC nastejno.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 5.6.2009 11:42
Autor: Tomáš Herceg
Hodnocení autora: 999
Příspěvků: 2400
Ve WebForms svážeš komponentu s modelem pomocí databindingu a jsi schopen to většinou udělat čistě v deklarativní syntaxi, nepotřebuješ na to code-behind. Je fakt, že databinding se nedá použít vždy, ale většinou ano.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 5.6.2009 12:56
Autor: Michal Augustýn
Hodnocení autora: 5
Příspěvků: 35
Však ano - to jsem také psal (nebo jsem to tak aspoň chtěl yvjádřit). Ale v ASP.NET MVC to lze také udělat čistě deklarativně - pomocí action filterů.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 5.6.2009 14:31
Autor: neregistrovaný (89.103.246.103)
Hodnocení autora: není
Příspěvků: 0
Možná byste si měli domluvit ukázkovou miniaplikaci, která by demonstrovala to, o čem se tady bavíme, a pak ji realizovat ve Web Forms a v MVC.

B.
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 5.6.2009 14:47
Autor: Michal Augustýn
Hodnocení autora: 5
Příspěvků: 35
Chystám se vytvořit takovou ukázkovou miniaplikaci, která bude demonstrovat většinu mně známých best-practices. Součástí ní by mělo být i několik varianty widgetování. To widgetování pravděpodobně ukážu na diskutovaném tématu "přidej komentáře". Ale je otázka, kdy si na to najdu čas :)
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...

Re: komponenty

Datum: 10.6.2009 12:01
Autor: neregistrovaný (213.151.94.139)
Hodnocení autora: není
Příspěvků: 0
Ano, v MVC se tomu myslím obecně říká view helper a ten si klidně může sáhnout do modelu
 
           [Odpovědět]
 
Hodnocení: 0 Čekejte, prosím...
1 
 

VBNET.CZ | © 2007 Tomáš Herceg, Tomáš Jecha | Kopírování a přejímání jakéhokoliv obsahu z tohoto webu je bez písemného svolení autorů zakázáno.