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í.