Pokud směřujete ViewState do Session pomocí SessionPageStatePersisteru, pak se dříve nebo později setkáte s problémem ztrát ViewState a s potřebou detekovat a řešit tuto situaci.
Ke ztrátě ViewState může dojít v následujících případech:
- v případě zániku/vyčištění Session, zejména při jejím timeoutování při nečinosti uživatele – uživatel si například nechá dlouho otevřenou stránku, vyprší mu mezi tím session, následně provede postback a problém je na světě, došlý postback nemá na serveru už ViewState,
- v případě ztráty InProc Session díky restartování aplikace (deployment nové verze, recyklace poolu, atp.)
- v případě vypadnutí stránky z fronty SessionPageStatePersisteru – persister omezuje totiž počet uložených ViewState a při uložení dalšího nejstarší vypadávají. Výchozí délka fronty je 9, je možné ji přenastavit na větší ve web.configu elementem sessionPageState, atributem historySize
- pokud si například uživatel otevře současně 10 oken aplikace, pak pokud se vrátí k prvnímu oknu a provede postback, opět chybí ViewState,
- pokud uživatel používá tlačítko Zpět browseru, např. pokud máme na stránce grid a každý řádek má na sobě tlačítko Detail, jehož obsluha události dělá redirect na stránku s detaily. Takový uživatel pokud klikne na detail prvního řádku, pak Zpět, druhého řádku, Zpět, … kliknutím na detail desátého řádku už způsobený postback na serveru nemá svůj ViewState (devět ViewState detailů vytlačilo z fronty ViewState stránky s gridem) a problém je zase na světě.
Jak takovou situaci detekovat? …overridováním metody LoadPageStateFromPersistenceMedium() v našich stránkách (obvykle pomocí společného předka všech stránek, nějakého PageBase):
protected override object LoadPageStateFromPersistenceMedium() { // base implementace vrací new Pair(pageStatePersister.ControlState, pageStatePersister.ViewState); object pageState = base.LoadPageStateFromPersistenceMedium(); // ztrátu ViewState můžeme tedy detekovat jako (pair.Second == null) // metoda LoadPageStateFromPersistenceMedium se volá jen pro IsPostBack Pair pair = pageState as Pair; if ((pair != null) && (pair.Second == null)) { Trace.Warn("ViewStateLost !!!"); FormsAuthentication.RedirectToLoginPage(); } return pageState; }
Základní (base) implementace metody LoadPageStateFromPersistenceMedium() totiž nedělá celkem nic jiného, než že z použitého persisteru získá ControlState, ViewState a udělá z nich Pair.
Situaci můžeme řešit například tím, že uživatele požádáme o nové přihlášení, či provedeme redirect kamsi do rootu nebo sami na sebe. ViewState už nikde nevydolujeme, musíme z toho nějak vybruslit, aniž bychom uživatele obšťastnili výjimkou NullReferenceException, InvalidFormatException a jinými podobnými, které v takových situacích nastávají.