V předchozím článku jsme se podívali na technologii ViewState a na to, jak se dá využívat ve vlastních ovládacích prvcích. A také jsem psal, že se na ni nemůžeme spolehnout, protože ji programátor může vypnout, na úrovni aplikace, stránky nebo konkrétního prvku. Pokud přesto chceme uchovávat nějaké údaje napříč postbacky, musíme použít technologii ControlState.

V první generaci ASP.NET (1.0, 1.1) jste měli na výběr: ViewState zapnout a užívat si funkčnosti všech prvků a platit za to obrovským objemem dat a nebo ho vypnout a rozloučit se s mnohou pokročilou funkčností. Proto v ASP.NET 2.0 Microsoft ViewState rozdělil na dvě velmi podobné technologie. Tou druhou je tzv. ControlState. Technicky je to v zásadě totéž, co ViewState: data se serializují a uchovají ve skrytém poli formuláře. Význam ControlState spočívá v tom, že nejde vypnout.

Předpokládá se tedy, že do ViewState si uložíte hodnoty, které byste sice rádi měli, ale obejdete se bez nich. A může jich být v zásadě docela dost. Do ControlState byste měli ukládat jenom ty hodnoty, bez kterých se v žádném případě neobejdete – a mělo by jich být co možná nejméně.

Jak ve svém prvku používat ControlState

V případě ViewState je použití snadné – máme k dispozici kolekci ViewState a do ní ukládáme co se nám zlíbí. Control state je na použití poněkud komplikovanější. Umí uložit jenom jednu serializovatelnou hodnotu. Pokud chceme uložit hodnot více, musíme si vytvořit serializovatelnou třídu, která bude sloužit jako kontajner. Budu pokračovat v příkladu SampleStateControl z předchozího článku a budu tedy ukládat jenom jednu hodnotu – čas prvního načtení stránky – a bez kontajneru bych se v zásadě obešel, ale z výukových důvodů jej přesto vytvořím a použiji. Bude jím třída jménem StateContainer, s jedinou vlastností FirstLoadTimeCS.

Pokud chce prvek využívat ControlState, musí o tom včas spravit svou hostitelskou stránku – a to tak, že ve fázi Init zavolá její metodu RegisterRequiredControlState. Potom můžete přepsat metody SaveControlState a LoadControlState, které jednoduše předají ke zpracování hodnotu vaší kontajnerové třídy.

Zde je rozšířený zdrojový kód třídy SampleStateControl z předchozího článku:

using System;

using System.Web;

 

namespace MyControls {

 

    public class SampleStateControl : System.Web.UI.Control {

 

        #region ViewState implementation

 

        public SampleStateControl() {

            // Nastavení výchozí hodnoty

            this.FirstLoadTimeVS = DateTime.MinValue;

        }

 

        public DateTime FirstLoadTimeVS {

            get { return (DateTime)this.ViewState["FirstLoadTimeVS"]; }

            set { this.ViewState["FirstLoadTimeVS"] = value; }

        }

 

        #endregion

 

        #region ControlState implementation

 

        [Serializable]

        private class StateContainer {

            public DateTime FirstLoadTimeCS { get; set; }

        }

 

        private StateContainer stateContainer = new StateContainer();

 

        public DateTime FirstLoadTimeCS {

            get { return this.stateContainer.FirstLoadTimeCS; }

            set { this.stateContainer.FirstLoadTimeCS = value; }

        }

 

        protected override void OnInit(EventArgs e) {

            base.OnInit(e);

 

            // Zaregistrovat se k použtí control state

            this.Page.RegisterRequiresControlState(this);

        }

 

        protected override object SaveControlState() {

            return this.stateContainer;

        }

 

        protected override void LoadControlState(object savedState) {

            this.stateContainer = (StateContainer)savedState;

        }

 

        #endregion

 

        protected override void OnLoad(EventArgs e) {

            base.OnLoad(e);

 

            if (!this.Page.IsPostBack) {

                // Jedná se o první dotaz, ne o postback

                this.FirstLoadTimeVS = DateTime.Now;

                this.stateContainer.FirstLoadTimeCS = DateTime.Now;

            }

        }

 

        protected override void Render(System.Web.UI.HtmlTextWriter writer) {

            if (!this.Page.IsPostBack) {

                // Jedná se o první dotaz, ne o postback

                writer.Write("<p>Toto je první dotaz.</p>");

            }

            else {

                // Jedná se o postback

                writer.Write("<p>ViewState: první dotaz nastal v {0}.</p>", this.FirstLoadTimeVS);

                writer.Write("<p>ControlState: první dotaz nastal v {0}.</p>", this.FirstLoadTimeCS);

            }

        }

 

    }

 

}

Funkcionalitu, kterou jsme dříve realizovali pomocí ViewState jsme nyní zduplikovali pomocí ControlState. Vyzkoušejte si na testovací stránce z minulého příkladu, jak to celé funguje. ViewState můžeme vypnout (a část funkcionality na něm závislá přestane fungovat), ale ControlState vypnout nelze. Proto jej prosím používejte s mírou.

V příštím článku se ViewState a ControlState podíváme na zoubek poněkud důkladněji. Podíváme se na obsah oněch Base64 kódovaných polí a také na to, jak jej lze chránit před neoprávněnou modifikací a nebo dokonce i pouhým čtením.