Uchování ViewState mimo asp.net stránku
O tom, že protokol http je bezstavový je jeho vlastnost se kterou se musí vypořádat nejeden vývojář webových aplikací. Microsoft přišel v asp.net s tím, používat pro uchování stavu požadavků mezi jednotlivými requesty klienta, ViewState. ViewState je ve výchozím nastavení webového projektu povolen a jeho uchování se děje na základě vloženého input prvku typu hidden do renderované HTML stránky.
Tento způsob uchování ViewState není jediný možný a již ve verzi asp.net 1.x byla možnost jej za pomoci přepsání dvou metod změnit. ASP.NET 2.0 však jde ještě dál a poskytuje přímo abstraktní třídu PageStatePersister, ve které stačí přepsat dvě metody pro uložení a načtení ViewState a ControlState a stav uložit dle návrhu aplikace. V tomto článečku ukáži, jak takový stav uložit do databáze.
Pro napsání tohoto příspěvku, s poměrně triviálním kódem, jsem se rozhodl z toho důvodu, že se opět rozbouřily vody kolem asp.net a jeho renderování výstupu HTML na klienta. Nejsem si jist, zda to rozpoutal Borber s uveřejněním své bakalářské práce, na kterou reagoval Jakub Vrána. Nebo to bylo až poté, co se DGX pozastavil nad výroky Marcuse, a kdy jsem se do debaty vložil také osobně?
Hnedka na úvod musím říci, že ViewState využívám, snažím se však o to, aby byl využívám účelně a jeho velikost zbytečně nebobtnala. Proto je vždy důležité zvolit správné UI kontroly a v případech kdy to jde, zakázat ViewState zcela. Jelikož píši z převážné většiny intranetové aplikace, nebráním se ViewState využívat. Avšak přišlo mi velice neefektivní jej přenášet při každém požadavku na klienta a zase zpět. Také proto jsem zvolil uchování stavu na serveru a to přímo v databázi - přeci jen v aplikacích je těch dotazů do db několik a jeden dotaz navíc je téměř zanedbatelný.
Vlastní implementace
Důležité je říci stránce, aby používala náš vlastní persister. V případě, že používáte vlastní poděděnou třídu Page jako výchozí pro všechny ostatní, což z vlastní zkušenosti doporučuji, je postačující přepsat property PageStatePersister
protected override PageStatePersister PageStatePersister {
get {
return new DbPagePersister(Page, "connectionStringKey");;
}
} Jestliže nemáte stránky navrženy výše uvedeným způsobem, nemusíte ještě zoufat. Můžete využít PageAdapter, a obdobně zde přepsat metodu GetStatePersister(), následně pomocí souboru .browser tento adaptér pro generování stránek přiřadit.
Dříve však než můžeme zaregistrovat vlastní persister, musíme si jej vytvořit. Vytvoříme tedy novou třídu a podědíme ji od abstraktní třídy PageStatePersister. Zde přepíšeme dvě metody pro uložení Save() a načtení Load() stavu. Předpokládám, že každý umí uložit data do databáze a tak tento krok přeskočím, nicméně je v přiložené ukázce implementován. Co je však důležité, jakým způsobem bude identifikována stránka, abychom mohli načíst její stav zpět. To je zajištěno pomocí registrace hidden pole a přiřazení unikátního řetězce Guid. Tento je jako jediný odeslán na výstup stránky a při zobrazení zdrojového kódu jej zde naleznete.
Pod čarou
Pokud se podíváte na výsledný zdrojový kód, možná vás překvapí, že se zde vyskytuje hidden pole nazvané __VIEWSTATE avšak je prázdné. Toto pole se mi však nepodařilo využít pro uložení jednoznačného identifikátoru, stejně tak se mi nepodařilo pole odstranit z finálního výstupu. Tím ovšem neříkám, že to ve výsledku nelze, ale o tom až příště.
Zdroje
Ukázka ke stažení.
Comments
rarouš
Bezva k napsání podobného clánku se premlouvám už dlouho, ale nevyzbyl mi cas. tak teD už nemusím :D
Jakub Müller
Koukal jsem se na ten kód, a není mi jasná jedna vec - jak se odstranují záznamy se ViewState od stránek, na kterých už nevzniknul PostBack?
Jestli se nepletu, tak se tímto zpusobem budou v DB množit záznamy s uloženým ViewState stránek, které už nikdy nebudou potreba.
2Jakub: Zde záleží na vytíženosti a zamerení stránek. V tabulce je uchována informace o vytvorení stavu, záleží pak na konkrétní situaci jak se bude odmazávání "neplatných" stavu rešit.
Pro intranetový projekt, kde jsem toto použil (ješte verze fw 1.0) se odmazávaly stavy vždy pres noc.
Toto muže být skutecne individuální a urcite ne všude je vhodné použít ukládání stavu do DB. Je klidne možné evidovat se stavem relace i SessionId a pri ukoncení relace celou historii vymazat. Tech variant je skutecne mnoho.
Jakub Müller
Diky, to jsem si myslel. Zajímalo me, jestli to náhodou nereší nejaká vychytávka "vedle", kterou neznám.
tz
Ukázka nejde stáhnout (Server Error in '/' Application).