Skip Navigation Links.
Skip Navigation Links.

.net student

microsoft

Vyhledávání v obsahu portálu


Přihlášení uživatele

Přihlášení uživatele

Členové:
  • Poslední nový uživatel Poslední: liborsky
  • Nový dnes Dnes nových 1
  • Nový včera Včera nových: 0
  • Počet uživatelů: Celkem: 4708
Lidé online:
  • Návštěvníci: Návštěvníků: 29
  • Registrovaných Členů: 0
  • Celkem Celkem: 29
Mapa Stranek

Ukládání ViewState do databáze

Udržení velikosti ViewState vyžaduje důkladnou znalost způsobu zpracování stránky ASP.NET a důsledné dodržování příslušných pravidel. Zejména u velkých projektů s mnoha vlastními komponentami se – v důsledku jejích nedodržení – může velikost ViewState vyšplhat do astronomických výšin. Přepsání takového projektu a odstranění prohřešků může být značně nákladné a rizikové, proto se jako nouzové řešení může hodit ukládat hodnotu ViewState do databáze a mezi klientem a serverem vyměňovat jen příslušný identifikátor. Právě o této úpravě pojednává tento článek.

Motivace

ViewState je technika, pomocí které ASP.NET přenáší informace o stavu webového formuláře (komponenty na formuláři a hodnoty jejích vlastností) mezi postbacky a přibližuje programování pro web stylu programování tlustých okenních klientů. Ve výchozím nastavení si hodnotu ViewState jednotlivé požadavky mezi sebou předávají pomocí skrytého pole v HTML s názvem __VIEWSTATE. Absence důsledného pochopení techniky ViewState dříve či později vede k neefektivitě, velkému přenosu dat a citlivosti výsledné aplikace na změny (i na první pohled přímo nesouvisející). Velikost ViewState u větších projektů, zejména se spoustou vlastních komponent, může dosáhnout i několika megabytů, což už pocítí i uživatelé rychlejších linek (o starších počítačích raději ani nemluvě).
Velikost ViewState lze pak efektivně stáhnout přepsáním projektu tak, aby splňoval pravidla pro psaní ASP.NET kódu a způsob práce s ViewState (ve smyslu hesla „Čím dřív, tím lépe." – hlavně při vytváření objektů a nastavování jejích vlastností). Zejména u rozsáhlých projektů toto přepsání znamená značné úsilí a alokaci velkého množství času, navíc se jedná o rizikovou změnu, která může zavléct mnoho chyb a vyžaduje opětovné důkladné otestování celé aplikace. Jako poměrně rychlé řešení může posloužit ukládání hodnoty ViewState do databáze a místo ní zasílat klientovi pouze příslušný identifikátor do databáze.
Článek se bude držet následujícího postupu. Nejdříve si připravíme projekt, následně vytvoříme potřebné třídy, databáze a tabulky. V dalším kroku naprogramujeme samotnou logiku pro ukládání a načítání ViewState. Na závěr zajistíme, aby se náš nový kód při ošetřování ViewState opravdu používal.  
Kód prezentovaný v tomto článku je kompatibilní s Microsoft .NET Framework 2.0, Microsoft Visual Studio 2005 a Microsoft SQL Server 2005 Express.

Příprava projektu

Ve Visual Studiu 2005 si vytvoříme prázdný projekt „Web Site“ (například pomocí File | New | Web Site). V projektu vytvoříme adresáře App_Code, App_Data a App_Browsers, které budeme potřebovat později. Výsledný strom by měl přiměřeně odpovídat následujícímu obrázku.
Připravený projekt 

Tvorba vlastního adaptéru

Ukládání a načítání ViewState zajišťuje v ASP.NET třída dědící System.Web.UI.Adapters.PageStatePersister. Ve zděděné třídě přetížíme její metody Save() a Load(). Instanci této třídy si ASP.NET vyžádá zavoláním metody GetStatePersister() z objektu dědícího z System.Web.UI.Adapters.PageAdapter. Vytvoříme tedy obě třídy, jak bylo nastíněno, metody Save() a Load() prozatím ponecháme prázdné. Na závěr také ponecháme zaregistrování našeho nového adaptéru ke stránce. Dosavadní výsledek zobrazuje následující kód.
using System;
using System.Web.UI;
 
namespace ViewStateExample
{
    public class DBPageStatePersister : PageStatePersister
    {
        public DBPageStatePersister(Page page)
            : base(page)
        {
        }
 
        public override void Save()
        {
        }
 
        public override void Load()
        {
        }
    }
 
    public class PageAdapter : System.Web.UI.Adapters.PageAdapter
    {
        public override PageStatePersister GetStatePersister()
        {
            return new DBPageStatePersister(Page);
        }
    }
}

Vytvoření databáze a tabulky

Naším cílem je ukládat ViewState v databázi, proto si ji nyní vytvoříme. V adresáři App_Data založíme novou databázi (Add New Item v kontextové nabídce, možnost SQL Database). V kontextové nabídce nově vytvořené databáze zvolíme Open a otevřeme tak databázi v panelu Server Explorer. Podobně vytvoříme novou tabulku (pravým tlačítkem na Tables, Add New Table) a v ní dva sloupce – ViewStateId (uniqueidentifier, odškrtnuté Allow Nulls) a ViewStateValue (text, odškrtnuté Allow Nulls). Tabulku uložíme pod názvem MyViewState. Výsledek ukazuje následující obrázek.

Připravená tabulka v databázi

Nyní si vytvoříme funkce pro práci s tabulkou. Známým způsobem vytvoříme nový soubor typu DataSet v adresáři App_Code a nazveme ho MyViewState.xsd. V průvodci nastavíme dotaz „SELECT ViewStateId, ViewStateValue FROM MyViewState WHERE (ViewStateId = @ViewStateId)“ a ujistíme se, že v kroku Choose Methods to Generates máme zaškrtnuté všechny tři boxíky. Blíže vše lépe popíší následující obrázky. Na závěr vše potvrdíme a počkáme na dokončení průvodce.

Průvodce konfigurací TableAdaptéru   

Průvodce konfigurací TableAdaptéru

Průvodce konfigurací TableAdaptéru

Samozřejmě můžete pro přístup k databázi využít i jiné způsoby, například kombinaci SqlConnection a SqlCommand. Tento článek používá DataSet a DataAdapter z důvodu snadnějšího výkladu.

Uložení ViewState do databáze

Uložení ViewState do databáze má na starosti funkce metoda Save() naší třídy DBPageStatePersister, kterou ASP.NET volá v závěrečných fázích zpracování stránky. Naším úkolem je uložit hodnoty vlastností ViewState a ControlState. Nejdříve tedy obě hodnoty spojíme v jeden objekt a výsledek serializujeme do řetězce. Poté si vymyslíme nové id a serializovanou hodnotu pod tímto id uložíme do databáze. Na závěr nastavíme id jako hodnotu ViewState, vynulujeme ControlState a požádáme třídu dodávanou s ASP.NET, aby nové hodnoty umístila do stránky ve formě známého skrytého pole __VIEWSTATE.
Poznámka: Nastíněné řešení není optimální. Bohužel se mi ale nepodařilo najít způsob, jak se obejít bez dodávané třídy – například HiddenFieldPageStatePersister. Po ručním vložení skrytého pole do stránky, přidal následně ASP.NET do stránky další instanci tohoto pole, které tím pádem přepsalo ručně vloženou hodnotu. Navíc nedocházelo u AJAXových skriptů ke správné aktualizaci ViewState. Podle mého pozorování se zdá, že ASP.NET – na rozdíl od implementace ASP.NET v projektu Mono – neexportuje všechny vlastnosti a funkce, které jsou potřebné k vytvoření plnohodnotné třídy pro ukládání ViewState. Samozřejmě, pokud přijdete na řešení, budu rád, pokud mi o něm dáte vědět.
public override void Save()
{
    if ((ViewState == null) && (ControlState == null))
        return;
 
    // Serializujeme originální hodnotu ViewState
 
    Pair states = new Pair(ViewState, ControlState);
    String viewState = StateFormatter.Serialize(states);
 
    // Vygenerujeme si nové id pro ViewState
   
    Guid newGuid = Guid.NewGuid();
 
    // Uložíme ViewState do databáze pod vygenerovaným id
 
    MyViewStateTableAdapters.MyViewStateTableAdapter adapter = new MyViewStateTableAdapters.MyViewStateTableAdapter();
    adapter.Insert(newGuid, viewState);
 
    // Zajistíme uložení našeho id do skrytého pole ve stránce místo originální hodnoty ViewState.
 
    HiddenFieldPageStatePersister hidden = new HiddenFieldPageStatePersister(Page);
    hidden.ViewState = newGuid.ToString();
    hidden.ControlState = null;
    hidden.Save();
}

Načtení ViewState z databáze

Načtení ViewState se v metodě Load() logicky provádí v opačném pořadí, než jeho ukládání. Nejdříve tedy požádáme dodanou třídu o vydolování id ze stránky a načteme si serializovaný objekt s ViewState z databáze. Pokud takový nenalezneme, můžeme skončit. V opačném případě deserializujeme hodnotu načtenou z databáze a rozdistribuujeme ji do vlastností ViewState a ControlState, ze kterých původně vznikla.
public override void Load()
{
    // Načteme id ViewState ze stránky
 
    HiddenFieldPageStatePersister hidden = new HiddenFieldPageStatePersister(Page);
    hidden.Load();
 
    Guid guid = new Guid(hidden.ViewState.ToString());
 
    // Načteme odpovídající originální hodnotu ViewState z databáze
 
    MyViewStateTableAdapters.MyViewStateTableAdapter adapter = new MyViewStateTableAdapters.MyViewStateTableAdapter();
    MyViewState.MyViewStateDataTable viewStateObject = new MyViewState.MyViewStateDataTable();
    adapter.Fill(viewStateObject, guid);
    if (viewStateObject.Rows.Count <= 0)
        return;
    String viewState = viewStateObject[0]["ViewStateValue"].ToString();
 
    // Obnovíme hodnotu ViewState v místech, kde ji ASP.NET očekává
 
    if (String.IsNullOrEmpty(viewState))
        return;
 
    Pair state = (Pair)StateFormatter.Deserialize(viewState);
 
    ViewState = state.First;
    ControlState = state.Second;
}

Registrace adaptéru

Zbývá nám ještě sdělit ASP.NET, aby používal náš nový adaptér s přetíženou metodou GetStatePersister(). Vytvoříme proto soubor MyViewState.browser v adresáři App_Browsers, který jsme si připravili na začátku. V souboru uvedeme, že adaptérem k objektu System.Web.UI.Page (třída reprezentující stránku v ASP.NET) je právě naše nová třída ViewStateExample.PageAdapter. Kompletní text souboru zobrazuje následující kód.
 
<browsers>
 <browser refID="Default" >
    <controlAdapters>
      <adapter
          controlType="System.Web.UI.Page"
          adapterType="ViewStateExample.PageAdapter" />
    </controlAdapters>
 </browser>
</browsers>

Shrnutí

V článku jsme si ukázali, jak naprogramovat vlastní způsob ukládání ViewState a nastavit jeho používání. Stačí nám tedy zdědit metodu System.Web.UI.Adapters.PageAdapter.GetStatePersister(), která vrátí instanci třídy dědící z System.Web.UI.Adapters.PageStatePersister. V této třídě implementujeme metody Save() a Load(), které provedou samotné ukládání a načítání ViewState.

Příloha

Kompletní zdrojový kód včetně funkčního příkladu (Visual Studio 2005 WebSite Project)

Autor: Martin Cetkovský (http://martin.alikuvkoutek.cz)

Martin Cetkovský :: 23. března 2008 :: 559 shlédnutí :: 2 komentářů
kategorie: Vývoj webových aplikací

Comments

By @ 27. března 2008 20:21
Zdravím,
možná by nebylo marný implementovat mazání starších záznamů.

Já jsem to před časem vyřešil podobně. Základní třída PSManager je odvozená od třídy HiddenFieldPageStatePersister - má tak rovnou přístup k údajům ze skrytého pole (identifikátor) a skutečné údaje předává persisterům pro DB, soubory a dalším. Ve výsledku je to vlastně totéž.
By Martin Cetkovský @ 27. března 2008 22:50
Mazani zaznamu povazuji za vhodne resit spise cronem, nez z popisovaneho kodu. Z duvodu udrzeni vypovidaci hodnoty prikladu jsem se touto zalezitosti zamerne nezabyval.
Musíte být přihlášen pro posílání komentářů. Přihlásit se můžete zde
Přehled posledních diskuzí

Přehled posledních diskuzí

  1. ASP.NET programátor zlín [12.16.2008 10:17 odp.]
    Dobrý den,v současné době hledáme programátora na pozici: ASP.NET / C# programátor - Zlín Požadavky: schopnost sam...
  2. RE: MS Fest video [12.08.2008 6:20 odp.]
    AhojVideo záznam bude, po večerech pilně pracujeme na jeho stříhání. Po dokončení se zde určitě vyskytne link na stažení...
  3. MS Fest video [12.04.2008 4:18 odp.]
    Existuje videozáznam z MS Festu konaneho (koncem listopadu 2008) o vikendu na Male Strane na fakulty MFF? Je nekde mozne...
  4. Práce pro programátora [11.25.2008 10:12 dop.]
    Hledám nadšeného programátora na vytvoření webstránek online tv/stream video. V případě zájmu pište na email: projekt@tr...
Novinky z klubů

Novinky z klubů

  1. Programátorské večery: F# 15. prosince 2008
    Ve čtvrtek 18.12.2008 se v rámci programátorských večerů uskuteční přednáška n...
  2. Programátorské večery: VSTO 10. prosince 2008
    Nad kancelářským balíkem MS Office se dají tvořit rozsáhlé aplikace. Od jednod...
  3. Programátorské večery: .NET 4.0 3. prosince 2008
    Zajímá Vás, na co se můžete těšit v nové verzi .NETu? Pak se přijďte podívat n...
  4. Záznamy z programátorských večerů 3. prosince 2008
    Záznamy z prog. večerů (prezentace+dema, občas i nějaké to video) můžete dočasně najít na http://ci...
Co se píše jinde

Co se píše jinde

Windows 7 Beta k dispozici pro MSDN předplatitele

Windows 7 Beta k dispozici pro MSDN předplatitele

Silverlight 2 úvod

Zajímá vás psaní webových aplikací na straně klienta ve vašem oblíbeném nástroji v .NETu? Slyšeli jste o Silverlightu...

PF 2009

Co tak popřát čtenářům programátorského blogu do nového roku? Snad abyste dostávali rozumná zadání a nemuseli tenkou ...

TypeConvertery

V tomto díle si vysvětlíme, co jsou TypeConvertery a k čemu se používají. To si také ukážeme na příkladu.

Atributy jmenného prostoru System.ComponentModel

V tomto článku si ukážeme jak efektivně využívat atributy z jmenného prostoru System.ComponentModel při vytváření vla...