ViewState v ASP.NET aplikacích – změna implementace ukládání
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 (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ě SavePageStateToPersistenceMedium
programově:
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á:
- pomocí třídy Configuration je zjištěn typ úložiště
EViewStateStore configuredStore = Configuration.ViewStateStore;
- pokud se jedná o výchozí implementaci, tak je pouze zavolána metoda bázové třídy:
base.SavePageStateToPersistenceMedium(viewStateBag);
respektive „return base.LoadPageStateFromPersistenceMedium();“ - 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.
Mohlo by vás také zajímat
-
Gaming na HDR monitoru: Stojí to za to?
12. srpna 2024 -
Responzivní design: Proč by ho neměl ignorovat žádný vývojář?
27. listopadu 2023 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024