Reklama

zonerbooks.cz | zoner.cz | czechia.com | regzone.cz | inshop.cz | inmail.cz | zonerpress.cz | zonerantivirus.com | zonerama.cz

interval.cz

ViewState v ASP.NET aplikacích - změna implementace ukládání

10. 06. 2004 | Zdeněk Drlík | ASP.NET | Komentáře: 0

V předchozím článku byly popsány principy ViewState, ukázány možnosti jeho použití a vyjmenovány jeho výhody i nevýhody. Pro řešení některých popisovaných problémů je nutné změnit výchozí konfiguraci ViewState, řešení některých problémů však vyžaduje změnu výchozí implementace ukládání. V tomto článku se proto zaměříme na popis vlastní implementace ukládání ViewState, která umožní ukládat ViewState nejen do skrytého pole v generované HTML stránce, ale také nově do databáze, adresáře v souborovém systému nebo paměťové cache serveru.

Vlastní implementace ukládání

Navržená implementace vychází z požadavků na možnost volby z více typů úložišť podle požadavků konkrétní aplikace a na snadné rozšíření o další typy úložišť. Přiložený příklad obsahuje ukládání ViewState do relační databáze, do souborového systému a paměťové cache.

Vlastní implementace ukládání je založena na překrytí metod SavePageStateToPersistenceMedium a LoadPageStateFromPersistenceMedium třídy System.Web.UI.Page. Tyto metody mají na starost (jak je to ostatně čitelné z jejich názvu), uložení a načtení hodnoty ViewState do a z konkrétního úložiště. Na následujícím obrázku je pro ilustraci uveden zjednodušený diagram tříd navrženého řešení:

Zjednodušený diagram tříd navržené implementace
Zjednodušený diagram tříd (plná velikost, cca 15 kB)

Zavedení vlastní bázové třídy stránek

Pro usnadnění implementace v aplikačních stránkách je zavedena vlastní bázové třída stránky BasePage, ve které jsou překryty zmíněné metody pro ukládání ViewState a z tohoto důvodu je vyžadováno dědění všech aplikačních stránek z této bázové stránky. Toho dosáhneme tak, že ve zdrojovém textu nově vytvořené stránky přepíšeme standardního předka System.Web.UI.Page na BasePage:

public class FirstPage : BasePage

Jazyk C# nepodporuje vícenásobnou dědičnost, takže pokud již v aplikaci bázovou třídu pro stránky používáme, je nutné implementaci vložit do ní.

Konfigurace ukládání

Načítání konfiguračních parametrů je implementováno statickou třídou Configuration. Konfigurační údaje třída načítá z aplikačního souboru web.config a umožňuje konfigurovat následující parametry:

  • Type - typ použitého úložiště, možné hodnoty jsou HiddenField (výchozí implementace), Database (uložení do databáze), File (adresář v souborovém systému) a Cache (paměťová cache)
  • ObjectExpiration - doba expirace objektů v úložišti
  • DeleteExpiredPeriod - perioda pro automatické odstraňování záznamů z úložiště
  • Directory - adresář pro ukládání záznamů, použije se pouze pokud je zvolen typ úložiště File
  • ConnectionString - připojovací řetězec k databázi, použije se pouze pokud je zvolen typ úložiště Database

Třída Configuration poskytuje statické vlastnosti pro načítání všech konfiguračních parametrů. Její metody jsou implementovány tak, aby v případě nenalezení parametru v konfiguraci vrátily výchozí hodnotu pro parametr. Například vlastnost pro zjištění jména adresáře je implementována jako:


public static string Directory
{
  get {
    try
    {
      return GetConfigValue("Directory");
    }
    catch
    {
      return string.Empty;
    }
  }
}

Třídy pro typy úložišť

Pro třídy implementující jednotlivé typy úložišť existuje společná abstraktní bázová třída BasePersistor. Ta deklaruje společné metody pro implementaci ukládání a také pomocné chráněné metody využívané v potomcích - pro serializaci ViewState a podobně. Tato bázová třída zavádí abstraktní metody:

  • GetViewState - pro načtení záznamu ViewState
  • SaveViewState - pro uložení záznamu
  • DeleteAppliactionViewStates - pro vymazání všech záznamů v úložišti
  • DeleteExpiredViewStates - pro vymazání expirovaných záznamů z úložiště

S výjimkou výchozího typu ukládání (HiddenField) je pro každý typ úložiště vytvořena třída zděděná z BasePersistor. Pro ukládání do databáze je implementována třída DatabasePersistor, pro ukládání do souborového systému slouží FilePersistor a pro paměťovou cache CachePersistor. Pro výchozí typ HiddenField je v překrytých metodách stránky použita funkčnost metod předka, není tedy nutné pro tento typ implementovat vlastní třídu.

Jedním z cílů řešení je možnost snadného rozšiřování o další typy úložišť. Vytvoření dalšího typu úložiště lze provést vytvořením potomka třídy BasePersistor a implementací výše uvedených abstraktních metod. Pokud nová třída bude pro svoji funkci vyžadovat vlastní konfigurační údaje, je nutné je přidat jako parametry do souboru web.config a přidat pro ně odpovídající statické vlastnosti ve třídě Configuration.

Identifikace záznamu v úložišti

Pro jednoznačnou identifikaci záznamu je použita proměnná typu GUID, která se ukládá do generované stránky prostřednictvím skrytého pole s názvem "__VIEWSTATE_KEY". Výchozí implementace ukládá hodnoty do skrytého pole "__VIEWSTATE", přičemž přítomnost tohoto pole ve stránce je pro správnou funkci vyžadována. Toto pole v případě použití serverových typů úložišť ponecháváme prázdné, přičemž v generování pole existuje drobný rozdíl mezi implementací v .NET Frameworku verze 1.0 a 1.1, kdy ve verzi 1.0 není toto pole automaticky generováno do stránky, zatímco ve verzi 1.1 ano. Kvůli vyžadované přítomnosti tohoto pole je pro aplikace pracující s .NET Frameworkem verze 1.0 nutné toto pole vygenerovat v metodě SavePageStateToPersistenceMediumprogramově:


if (Environment.Version.Major == 1 && Environment.Version.Minor == 0)
{
  RegisterHiddenField("__VIEWSTATE", "");
}
RegisterHiddenField("__VIEWSTATE_KEY", viewStateID.ToString());

Překrytí metod pro uložení a načtení ViewState

Máme již připraveny potřebné třídy, které umožní překrytí implementace metod SavePageStateToPersistenceMedium a LoadPageStateFromPersistenceMedium. Základní funkce algoritmu obou metod je stejná:

  1. pomocí třídy Configuration je zjištěn typ úložiště

    EViewStateStore configuredStore = Configuration.ViewStateStore;

  2. pokud se jedná o výchozí implementaci, tak je pouze zavolána metoda bázové třídy:

    base.SavePageStateToPersistenceMedium(viewStateBag);
    respektive "return base.LoadPageStateFromPersistenceMedium();"

  3. pokud jsou použita serverová úložiště, je podle nakonfigurovaného typu vytvořena instance odpovídající třídy a případně jsou načteny vyžadované konfigurační parametry pro tento typ (příklad pro adresář v souborovém systémy):

    string configuredDirectory = Configuration.Directory;
    usedPersistor=new FilePersistor(configuredDirectory, configuredExpiration);

Uložení záznamu

Metoda pro uložení zajistí vygenerování nebo načtení již existujícího identifikátoru záznamu...


Guid viewStateID = Guid.Empty;
if (Request.Form["__VIEWSTATE_KEY"] != null)
{
  viewStateID = new Guid(Request.Form["__VIEWSTATE_KEY"]);
}
else
{
  viewStateID = Guid.NewGuid();
}

...a uložení záznamu do úložiště:


usedPersistor.SaveViewState(
  viewStateID,
  viewStateBag);

Následně metoda zaregistruje skryté pole s identifikátorem do stránky, případně ještě zajistí výše zmiňované generování povinného pole __VIEWSTATE:


if (Environment.Version.Major == 1 && Environment.Version.Minor == 0)
{
  RegisterHiddenField("__VIEWSTATE", "");
}
RegisterHiddenField("__VIEWSTATE_KEY", viewStateID.ToString());

Načtení záznamu

Metoda pro načtení zjistí hodnotu identifikátoru záznamu...

Guid viewStateID = new Guid(Request.Form["__VIEWSTATE_KEY"]);

...a poté načte záznam a vrátí ho jako návratovou hodnotu metody:

return usedPersistor.GetViewState(viewStateID);

Odstranění záznamů z úložiště

Pro kompletní implementaci ukládání záznamů ViewState do úložišť na serveru schází pouze zajištění odstranění již neplatných záznamů z úložiště. Za tuto činnost odpovídá třída StoreCleaner. Třída implementuje dva způsoby mazání záznamů - výmaz všech záznamů a výmaz záznamů s dobou posledního přístupu vyšší než nastavená hodnota životnosti záznamu. Metoda pro vymazání všech záznamů je použitelná pouze v době, kdy je zajištěno, že žádný záznam z úložiště není a nebude využíván, tedy typicky při startu nebo ukončení aplikace (metoda Application_Start nebo Application_End v souboru global.asax).

Druhá metoda vyžaduje periodické spouštění, proto třída StoreCleaner implementuje časovač, který v nastavené periodě vymaže všechny expirované záznamy z úložiště. Tento časovač se spouští pomocí metody StartAutomaticExpiredDeletion a zastavuje metodou StopAutomaticExpiredDeletion. Místem pro start časovače je logicky také doba startu aplikace, konkrétně například metoda Application_Start. Protože je však nutné zajistit automatickou kontrolu nastavené doby životnosti objektu vzhledem k délce trvání Session (hodnota životnosti objektu nemůže být nižší než hodnota doby životnosti Session), je nutné start časovače umístit do Session_Start a programově zajistit, aby bylo možné časovač spustit maximálně jednou (toto zajišťuje třída StoreCleaner pomocí principu vycházejícího z návrhového vzoru Singleton).

Konkrétní implementace v metodách global.asax je tedy následující:


protected void Application_Start(Object sender, EventArgs e)
{
  StoreCleaner.DeleteApplicationViewStates();
}
protected void Session_Start(Object sender, EventArgs e)
{
  StoreCleaner.StartAutomaticExpiredDeletion();
}
protected void Application_End(Object sender, EventArgs e)
{
  StoreCleaner.StopAutomaticExpiredDeletion();
  StoreCleaner.DeleteApplicationViewStates();
}

K dispozici je vám rovněž příklad v podobě archivu kompletní sady zdrojových kódů, které můžete využít ve vlastních aplikacích.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.


Reklama


Další aktuální články na interval.cz

Tematicky související články

Dejte vědět i ostatním o článku

Diskuse (počet komentářů: 0)

Buďte prvním návštěvníkem, který přidá nový komentář.

Přidat nový komentář

Jméno a e-mail jsou nepovinné. Příspěvky obsahující odkaz jsou moderovány.

Zoner AntiVirus Free pro Android
zabezpečte si svůj smartphone, zdarma
Profesionální eshop Zoner inShop od 990 Kč.
Reklama
Reklama

Syndikace

hledáme nové autory | redakce interval.cz | reklama na interval.cz

© ZONER software, a.s., všechna práva vyhrazena, interval.cz dodržuje právní předpisy o ochraně osobních údajů. Powered by WordPress.