← Zpět na články

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

Comment 1

Anonymous - on Sep 20 2006 at 6:13 PM

Bezva k napsání podobného článku se přemlouvám už dlouho, ale nevyzbyl mi čas. tak teĎ už nemusím :D

Comment 2

Anonymous - on Nov 23 2006 at 3:53 PM

Koukal jsem se na ten kód, a není mi jasná jedna věc - jak se odstraňují záznamy se ViewState od stránek, na kterých už nevzniknul PostBack?

Jestli se nepletu, tak se tímto způsobem budou v DB množit záznamy s uloženým ViewState stránek, které už nikdy nebudou potřeba.

Comment 3

Anonymous - on Nov 23 2006 at 4:12 PM

2Jakub: Zde záleží na vytíženosti a zaměření stránek. V tabulce je uchována informace o vytvoření stavu, záleží pak na konkrétní situaci jak se bude odmazávání "neplatných" stavů řešit.

Pro intranetový projekt, kde jsem toto použil (ještě verze fw 1.0) se odmazávaly stavy vždy přes noc.

Toto může být skutečně individuální a určitě ne všude je vhodné použít ukládání stavu do DB. Je klidně možné evidovat se stavem relace i SessionId a při ukončení relace celou historii vymazat. Těch variant je skutečně mnoho.

Comment 4

Anonymous - on Nov 27 2006 at 5:54 PM

Diky, to jsem si myslel. Zajímalo mě, jestli to náhodou neřeší nějaká vychytávka "vedle", kterou neznám.

Comment 5

Anonymous - on Feb 23 2008 at 5:32 PM

Ukázka nejde stáhnout (Server Error in '/' Application).