日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ViewState机制的解析(转自csdn)

發(fā)布時間:2024/4/17 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ViewState机制的解析(转自csdn) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1???????? ViewState機(jī)制是什么?

ViewState機(jī)制是asp.net中對同一個Page的多次請求(PostBack)之間維持Page及控件狀態(tài)的一種機(jī)制。在WebForm中每次請求完,Page對象都會被釋放,對同一個Page的多次請求之間的狀態(tài)信息,如何進(jìn)行維護(hù)呢?WebForm中,每次請求都會存在客戶端和服務(wù)器之間的一個交互。如果請求完成之后將一些信息傳回到客戶端,下次請求的時候客戶端再將這些狀態(tài)信息提交給服務(wù)器,服務(wù)器端對這些信息使用和處理,再將這些信息傳回給客戶端。這樣是不是就可以對同一個Page的多次請求(PostBack)之間維持狀態(tài)了。對這就是ViewState的基本工作模式。ViewState的設(shè)計目的主要就是為了將必要的信息持久化在頁面中。這樣通過ViewState在頁面回傳的過程中保存狀態(tài)值,使原本沒有“記憶”的Http協(xié)議變得有“記憶”起來。

2???????? ViewState機(jī)制如何工作?

下面我們看看ViewState機(jī)制是如何具體的工作的。

2.1?客戶端:

我們先從客戶端看起,在客戶端的HTML源代碼中我們可以看到下面的代碼

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"

value="/wEPDwULLTE0MTAzNDUwNThkZKr77J2uy7fatyBou8PocG80X4Jt" />

這個就是ViewState在客戶端的保存形式,它保存在一個ID為__VIEWSTATE的Hidden中,它的Value是使用Base64編碼后的字符串。這個字符串實際上是一個對象(Pair類型)序列化之后的結(jié)果。這個對象保存了整個頁面的控件樹的ViewState。可以使用一些工具將這個字符串進(jìn)行解碼查看其內(nèi)容,比如ViewStateDecoder,ViewStateAnalyzer。

2.2?服務(wù)器端:

在服務(wù)器端和ViewState機(jī)制密切相關(guān)的有三個類Page,Control,StateBag。他們3者的關(guān)系如下圖所示:


圖1

Page繼承自Control,Control和StateBag是聚合關(guān)系,在Control中有一個StateBag的實例ViewState。這三個類互相協(xié)作完成ViewState機(jī)制的大概過程如下。Page對客戶端請求進(jìn)行處理,在處理的過程中先是將客戶端提交的_VIEWSTATE反序列化為對象,調(diào)用Control的相關(guān)方法給所有的控件裝載數(shù)據(jù),這些數(shù)據(jù)是上次請求結(jié)束后控件的狀態(tài)數(shù)據(jù)。在之后的一些事件中這些狀態(tài)數(shù)據(jù)可能被修改。在請求結(jié)束之前調(diào)用Control的相關(guān)方法得到所有控件的被修改過的狀態(tài)數(shù)據(jù),之后Page將其進(jìn)行序列化,并返回給客戶端。在Control中又具體調(diào)用StateBag類的方法完成狀態(tài)數(shù)據(jù)的加載和保存。

2.2.1?? Page中的處理


圖2 Page生命周期

1)???? InitRecursive

在Page的生命周期中有3處與ViewState相關(guān),在初始化階段調(diào)用Control. InitRecursive,它遞歸對所有的控件進(jìn)行初始化,其中調(diào)用了Control.TrackViewState。TrackViewState中打開跟蹤ViewState開關(guān)。

2)???? LoadAllState

在初始化完成之后會調(diào)用Page.LoadAllState,LoadAllState只有在PostBack的時候才會執(zhí)行,它的主要功能是將從頁面?zhèn)鬟f來的__VIEWSTATE的值反序列化為Pair類型的對象,然后將這個對象中存儲的ViewState的值加載到Page及所有控件中。實際上LoadAllState加載了ControlState(控件狀態(tài))及ViewState(視圖狀態(tài)),本文主要是討論ViewState,對ControlState部分的處理不進(jìn)行描述。

LoadAllState中主要有兩步:Page.LoadPageStateFromPersistenceMedium和Control.LoadViewStateRecursive。

在LoadPageStateFromPersistenceMedium中發(fā)生了如下的調(diào)用層次

Page.LoadPageStateFromPersistenceMedium

è??? HiddenFieldPageStatePersister.Load

è??? ObjectStateFormatter.Deserialize

以上完成的功能是將客戶端提交的_VIEWSTATE反序列化為一個類型為Pair的對象pair。

Control.LoadViewStateRecursive中將遞歸加載控件的ViewState,具體在下面進(jìn)行講解。

3)???? SaveAllState

SaveAllState它的操作和LoadAllState相反。SaveAllState中主要有兩步Control.SaveViewStateRecursive及Page SavePageStateToPersistenceMedium。

Control.SaveViewStateRecursive中將所有控件的ViewState屬性遞歸加載到一個Pair對象中,具體實現(xiàn)細(xì)節(jié)在下面講解。

Page SavePageStateToPersistenceMedium中發(fā)生如下的調(diào)用關(guān)系。

Page SavePageStateToPersistenceMedium

è??? HiddenFieldPageStatePersister.Save

è??? ObjectStateFormatter.Serialize

將Control.SaveViewStateRecursive生成的對象序列化為一個字符串,并賦值給Page.ClientState屬性。

在Render階段發(fā)生如下的調(diào)用關(guān)系:

HtmlForm.RenderChildren

è??? Page.BeginFormRender

è??? Page.RenderViewStateFields

最終將ClientState屬性中的值寫入到HTML頁面的_VIEWSTATE中。

在Control.InitRecursive中打開跟蹤開關(guān),打算對ViewState的值進(jìn)行跟蹤,在Page.LoadAllState中將客戶端提交的__VIEWSTATE的值裝載到各個控件的ViewState中,在Page.SaveAllState中將發(fā)生變化的ViewState序列化為一個字符串,在Render階段發(fā)送回客戶端。

4)???? ViewState序列化與反序列化

PageStatePersister 是一個抽象類,是表示將ViewState信息序列化及反序列化機(jī)制的基類。在Page.LoadPageStateFromPersistenceMedium中示意代碼如下:

protected internal virtual object LoadPageStateFromPersistenceMedium()

{

????????? PageStatePersister pageStatePersister = this.PageStatePersister;

????????? pageStatePersister.Load();

????????? return new Pair(pageStatePersister.ControlState, pageStatePersister.ViewState);

}

在Page.SavePageStateToPersistenceMedium中的示意代碼如下:

protected internal virtual void SavePageStateToPersistenceMedium(object state)

{

??? ??? PageStatePersister pageStatePersister = this.PageStatePersister;

??????? Pair pair = (Pair) state;

??????? pageStatePersister.ControlState = pair.First;

??????? pageStatePersister.ViewState = pair.Second;

??????? pageStatePersister.Save();

}

在Asp.net2.0中實現(xiàn)PageStatePersister這個抽象類,具體提供持久化機(jī)制的類是HiddenFieldPageStatePersister。它實現(xiàn)了Load和Save兩個方法,Load時將__VIEWSTATE反序列化為一個Pair對象,Save時將Pair對象序列化為一個字符串賦值給Page.ClientState。HiddenFieldPageStatePersister中采用的格式器是ObjectStateFormatter,其實現(xiàn)string Serialize(object state),和object Deserialize(string serializedState)這兩個方法,從而實現(xiàn)對Pair對象的序列化和反序列化。

public string Serialize(object state)中的示意代碼如下:

MemoryStream memoryStream = GetMemoryStream();

Serialize(memoryStream, state);

byte[] buf = memoryStream.GetBuffer();

if (RequiresViewStateEncryptionInternal)

{

?buf = MachineKeySection.EncryptOrDecryptData(true, buf, this.GetMacKeyModifier(), 0, length);

?length = buf.Length;

}

else if (EnableViewStateMac)

{

buf = MachineKeySection.GetEncodedData(buf, this.GetMacKeyModifier(), 0, ref length);

}

return Convert.ToBase64String(buf, 0, length);

將state序列化為內(nèi)存流,在將其轉(zhuǎn)換為字節(jié)流。如果需要加密則對其進(jìn)行加密處理,否則需要Mac則進(jìn)行Mac處理。最后將字節(jié)流進(jìn)行Base64編碼轉(zhuǎn)換為字符串。

public object Deserialize(string serializedState) 中的示意代碼如下:

byte[] buf = Convert.FromBase64String(serializedState);

int length = buf.Length;

if (ContainsEncryptedViewState)

{

buf = MachineKeySection.EncryptOrDecryptData(false, buf, this.GetMacKeyModifier(), 0, length);

?length = buf.Length;

}

else if (EnableViewStateMac)

{

buf = MachineKeySection.GetDecodedData(buf, this.GetMacKeyModifier(), 0, length, ref length);

}

MemoryStream memoryStream = GetMemoryStream();

memoryStream.Write(buf, 0, length);

return this.Deserialize(memoryStream);

將字符串進(jìn)行Base64解碼為字節(jié)流,如果需要解密則進(jìn)行解密處理,否則需要進(jìn)行需要Mac則進(jìn)行Mac處理,將字節(jié)流轉(zhuǎn)換為內(nèi)存流,進(jìn)行反序列化返回Pair對象。

?

ViewState機(jī)制由淺入深2

?

2.2.2?? Pair類及ViewState的存儲

Page及所有控件的ViewState、ControlState都是存儲在Pair類的實例中,了解Pair類及ViewState如何存儲在Pair類中很重要。Pair定義的System.Web.UI中具體定義如下:

public sealed class Pair

{

??? public object First;

??? public object Second;

??? public Pair();

??? public Pair(object x, object y);

}

可以看出Pair類是用作存儲兩個相關(guān)對象的基本結(jié)構(gòu)。Pair是一個工具類,使用它很容易形成一個樹的數(shù)據(jù)結(jié)構(gòu)。將__VIEWSTATE反序列化后就是一個Pair對象。這個對象即保存了控件之間的父子關(guān)系,也保存了ViewState信息。ViewState中的Key/Value對被轉(zhuǎn)換為一個ArrayList對象保存在Pair對象中。下面我們來看看它是如何存儲的。


圖3

圖3是對Pair的一種圖式表示方式,左邊表示First對象,右邊表示Second對象,根據(jù)這種圖式方式,圖4是利用Pair對象存儲ViewState的結(jié)構(gòu),對于ControlState沒有進(jìn)行具體的展開。從savedState(Pair)開始采用了遞歸的存儲方式,將所有控件的ViewState及關(guān)系存儲起來,在Pair對象的First中存儲ViewState數(shù)據(jù),在Second中存儲子控件的信息。

圖4

2.2.3?? Control中的處理

Page類繼承自Control類,在實現(xiàn)ViewState機(jī)制的時候Page類中主要是涉及序列化和反序列化的工作,ViewState的保存、裝載等功能都在Control類中實現(xiàn)由Page類來繼承,控件也都繼承自Control類,下面對Control類中和ViewState機(jī)制相關(guān)的屬性、方法進(jìn)行介紹。1)???? ViewState屬性ViewState是Page及控件的一個屬性,這個屬性并不是在Page或控件中定義,它定義在System.Web.UI.Control類中。它的聲明如下:

protected virtual StateBag ViewState{get}

由于所有服務(wù)器端的控件,用戶自定義控件,及Page類都是繼承自Control類,所以它們都會都具有一個protected的ViewState屬性。這個ViewState屬性在ViewState機(jī)制中很重要,它用來存儲控件需要記憶的一些數(shù)據(jù)。這些數(shù)據(jù)主要有兩類,一類是需要記憶的控件的屬性。另外一類是我們想利用ViewState機(jī)制來記住的一些數(shù)據(jù),比如我們在Web窗體中寫如下的代碼:

??? protected void Page_Load(object sender, EventArgs e)

??? {

??????? if (!this.IsPostBack)

??????? {

??????????? this.ViewState["Test"] = 0;

??????? }

??????? else

??????? {

??????????? this.ViewState["Test"]=int.Parse(this.ViewState["Test"].ToString()) + 1;

??? ????}

??? }因為我們創(chuàng)建的Web窗體都是繼承自Page類,所以在Web窗體中能否訪問Page類的protected的ViewState屬性。我們可以通過ViewState屬性利用ViewState機(jī)制,讓它幫助我們記住一些信息。ViewState屬性的主要作用還是用來記住一些控件的屬性值。ViewState屬性和控件的其他屬性有什么樣的聯(lián)系,才能夠利用ViewState屬性來記住他們呢?下面用Button類的Text屬性舉例來說明,Text屬性和ViewState屬性是什么關(guān)系。Button.Text的定義如下:

public string Text

{

??? get

??? {

??????? string str = (string) this.ViewState["Text"];

??????? if (str != null)

??????? {

??????????? return str;

??????? }

??????? return string.Empty;

??? }

??? set

??? {

??????? this.ViewState["Text"] = value;

??? }

}

通過上面的代碼我們可以看出Button.Text屬性的值實際上和ViewState中Key為“Text”的Value是關(guān)聯(lián)的。當(dāng)然Button類的其他屬性也是類似的方式,只是對應(yīng)ViewState中Key不同而已。這樣只要ViewState的值能夠被記憶,那么Button類的屬性也就能夠被記憶住了。記憶ViewState的方法就是在Page. SaveAllState中將所有控件的ViewState屬性生成一個對象(這是一個特殊的對象,它是一個樹狀態(tài)的存儲了所有控件的ViewState屬性),然后將這個對象序列化為字符串,發(fā)送到客戶端。在下次請求的時候,將這個字符串發(fā)送給服務(wù)器,在Page.LoadAllState中將這個字符串反序列化為一個對象,將這個對象中存儲的各個控件的ViewState屬性,加載給各個控件的ViewState屬性。當(dāng)我們訪問控件的屬性的時候就實現(xiàn)了對控件屬性的記憶,之前設(shè)置的控件屬性沒有丟失。2)???? LoadViewStateByID屬性

LoadViewStateByID的聲明如下:

protected bool LoadViewStateByID{get}

LoadViewStateByID獲取一個值,該值指示控件是否通過ID方式加載其視圖狀態(tài)。默認(rèn)情況下是通過索引方式加載視圖狀態(tài),索引方式是依賴子控件在父控件的Controls集合中位置。ID方式會根據(jù)ID查找控件,效率比較低些,但是有些情形必須使用這種方式比如延遲創(chuàng)建子控件時。

3)???? EnableViewState屬性EnableViewState是一個bool類型的屬性,來決定當(dāng)前控件的ViewState機(jī)制是否可用。其聲明如下:

public virtual bool EnableViewState{get,set}

4)???? LoadViewStateRecursiveLoadViewStateRecursive的聲明如下:internalvoid LoadViewStateRecursive(object savedState)Page.LoadAllState中調(diào)用Control.LoadViewStateRecursive,傳入的參數(shù)savedState是一個Pair類型的對象,Pair.Fisrt中保存當(dāng)前控件的ViewState,Pair.Second中保存子控件的ViewState。對于EnableViewState為true時,先通過調(diào)用Control.LoadViewState(savedState.First)裝載當(dāng)前控件的ViewState。之后根據(jù)LoadViewStateByID屬性,裝載子控件的ViewState。如果LoadViewStateByID屬性為true調(diào)用Control.LoadChildViewStateByID(savedState.Second),否則調(diào)用Control.LoadChildViewStateByIndex(savedState.Second)。savedState.Second是一個ArrayList類型的對象。

Control.LoadViewState的聲明如下:

protected virtual void LoadViewState(object savedState)在Control.LoadViewState中并沒有自己實現(xiàn)裝載當(dāng)前控件的ViewState,而是通過ViewState.LoadViewState(savedState)來實現(xiàn),下面會介紹StateBag的LoadViewState方法。LoadChildViewStateByID的聲明如下:internal void LoadChildViewStateByID(ArrayList childState)參數(shù)childState是ArrayList類型,childState中存儲了當(dāng)前控件的所有子控件的信息。它的格式是首先是一個控件的ID,其后是這個控件的Pair對象。對childState進(jìn)行循環(huán),循環(huán)中取得控件的ID,根據(jù)ID找到控件調(diào)用這個控件的LoadViewStateRecursive方法。示意代碼如下:

for (int i = 0; i < count; i += 2)

??? {

??????? string id = (string) childState[i];

??????? object savedState = childState[i + 1];

???????Control control = this.FindControl(id);

??????? control.LoadViewStateRecursive(savedState);

??? }

LoadChildViewStateByIndex的聲明如下:

internal void LoadChildViewStateByIndex(ArrayList childState)

childState的存儲格式是首先是一個控件的索引,其后是這個控件的Pair對象。根據(jù)索引訪問訪問這個控件,調(diào)用其LoadViewStateRecursive方法,示例代碼如下:

??? for (int i = 0; i < num2; i += 2)

??? {

??????? int num4 = (int) childState[i];

??????? object savedState = childState[i + 1];

??????? controls[num4].LoadViewStateRecursive(savedState);

???? }

5)???? LoadViewState

LoadViewState中直接調(diào)用ViewState的LoadViewState方法進(jìn)行ViewState的裝載,示意代碼如下:

this.ViewState.LoadViewState(savedState);

6)???? SaveViewStateRecursiveSaveViewStateRecursive的聲明如下:

internal object SaveViewStateRecursive()

對于EnableViewState為true時,先調(diào)用Control.SaveViewState返回一個包含當(dāng)前控件的ViewState信息的ArrayList類型對象x。之后對子控件進(jìn)行遞歸處理獲得一個ArrayList類型的對象z。它的格式是ID(String),savedState(Pair)或者Index(int)savedState(Pair)。最后創(chuàng)建一個Pair對象Pair(x, z)。示意代碼如下:

object x = this.SaveViewState();

ArrayList z = null;

ControlCollection controls = this._occasionalFields.Controls;

int count = controls.Count;

bool loadViewStateByID = this.LoadViewStateByID;

for (int i = 0; i < count; i++)

{

????????? Control control = controls[i];

????????? object obj4 = control.SaveViewStateRecursive();

????????? if (loadViewStateByID)

??????????????????? z.Add(control.ID);

????????? else

????????? ????????? ????????? z.Add(i);

????????? z.Add(obj4);

}

return new Pair(x, z);

7)???? SaveViewState

SaveViewState中直接調(diào)用ViewState的SaveViewState方法進(jìn)行ViewState的保存,示意代碼如下:

return this.ViewState.SaveViewState();

8)???? TrackViewState

在Control.InitRecursive中會調(diào)用Control.TrackViewState,因為Control.InitRecursive是被遞歸調(diào)用的,所以每個控件的TrackViewState都會在初始化階段被調(diào)用到。Control.TrackViewState中之間調(diào)用ViewState的TrackViewState方法,示意代碼如下:

this.ViewState.TrackViewState();

ViewState機(jī)制由淺入深3

?

2.2.4?? StateBag

ViewState是控件的一個屬性,用來使用控件具有記憶功能。在前邊的講述中,我們可以看到控件的一些屬性通過使用ViewState能夠恢復(fù)原來的值,保存本次的值,在Control類中很多方法的實現(xiàn)也是直接調(diào)用了ViewState的方法。ViewState的類型是StateBag,下面我們就了解一下在StateBag中是如何實現(xiàn)這些功能的。StateBag定義在System.Web.UI中聲明如下:

public sealed class StateBag : IStateManager, IDictionary, ICollection, IEnumerable

StateBag類可以理解為是一個具有狀態(tài)管理功能的字典,因為它實現(xiàn)了IStateManager, IDictionary 這兩個接口。StateBag類可以象字典那樣保存Key/Value對,其中Key是字符串而Value是對象。下面是一個使用StateBag的例子。

??? protected void Button2_Click(object sender, EventArgs e)

??? {

??????? StateBag TestSB = new StateBag();

??????? TestSB["b"] = "bbbbb";

??????? TextBox1.Text = TestSB["b"].ToString();

}

在上面的例子中使用StateBag保存一個Key為“b”,其值為“bbbbb”的Key/Value對。ViewState屬性也是StateBag的一個實例,當(dāng)然也就可以象上面那樣使用。在ViewState中保存了很多的Key/Value對(鍵值對),這些Key/Value對用來保存控件的屬性,這些Key/Value對是有ASP.Net來維護(hù)的。當(dāng)然我們也可以增加一些自己的Key/Value對,來保存一些信息。

StateBag還實現(xiàn)System.Web.UI.IStateManager接口,這樣它具有狀態(tài)管理功能。下面對StateBag如何提供狀態(tài)管理功能進(jìn)行說明。

1)???? StateItem

StateBag中保存Key/Value對,Key是String類型,Value是Object類型。但是在StateBag內(nèi)部保存Value不是Object類型,而是將Object類型轉(zhuǎn)換為StateItem類型然后保存,從StateBag中取出的時候再將StateItem類型轉(zhuǎn)換為Object類型,也就是說StateBag中的Key/Value對實際上是String/StateItem類型。轉(zhuǎn)換過程是在StateBag內(nèi)部實現(xiàn)客戶感覺不到。StateItem的聲明如下:

public sealed class StateItem

{

??? internal StateItem(object initialValue);

??? public bool IsDirty { get; set; }

??? public object Value { get; set; }

}

通過上面的代碼我們可以看出實際上多了一個IsDirty屬性,來標(biāo)記當(dāng)前的Value是否已經(jīng)被修改過。

2)???? Add

Add方法是將傳入的Key,Value保存到字典中,并處理IsDirty屬性。在StateBag.LoadViewState方法中會調(diào)用Add方法。其示意代碼如下:

public StateItem Add(string key, object value)

{

??? StateItem item = this.bag[key] as StateItem;

??? if (item == null)

??? {

??????? if ((value != null) || this.marked)

??????? {

??????????? item = new StateItem(value);

??????????? this.bag.Add(key, item);

??????? }

??? }

?? ?else

??? {

??????? item.Value = value;

??? }

??? if ((item != null) && this.marked)

??? {

??????? item.IsDirty = true;

??? }

??? return item;

}

雖然函數(shù)的名稱是Add,其實也包括了更新。如果當(dāng)前的項在字典中不存在則新增,否則更新。新增時新建一個StateItem類型的對象item,將Key和item增加到字典中。如果Item不為null,并且跟蹤狀態(tài)標(biāo)記為true,則item的IsDirty為true。什么情況下會調(diào)用Add方法呢?主要有兩種情形一種是StateBag.LoadViewState,在下面會具體介紹到。還有一種情況就是對控件的屬性賦值的時候,比如Button.Text=”button”,此時會調(diào)用Text屬性的Set,在Set中執(zhí)行的代碼this.ViewState["Text"] = value,這個代碼實際上執(zhí)行this.ViewState.Add("Text",value)。

3)???? LoadViewState

還原以前保存的ViewState。將傳入的ArrayList對象加載到字典中。示意代碼如下:

internal void LoadViewState(object state){??????? ArrayList list = (ArrayList) state;??????? for (int i = 0; i < list.Count; i += 2)??????? {??????????? string key = ((IndexedString) list[i]).Value;??????????? object obj2 = list[i + 1];?????????? ?this.Add(key, obj2);??????? }

}

我們知道在初始化階段StateBag.TrackViewState都已經(jīng)被調(diào)用過了,也就是說marked為true了,這樣在StateBag.LoadViewState中調(diào)用Add方法第一次加載完ViewState的數(shù)據(jù)后,所有的StateItem的IsDirty屬性都是true。

4)???? SaveViewState

將字典中已經(jīng)修改過的Key/Value存放在一個ArrayList對象中返回。

internal object SaveViewState(){?? ArrayList list = null;?? IDictionaryEnumerator enumerator = this.bag.GetEnumerator();?? while (enumerator.MoveNext())?? {??????????? StateItem item = (StateItem) enumerator.Value;??????????? if (item.IsDirty)??????????? {??????????????? list.Add(new IndexedString((string) enumerator.Key));??????????????? list.Add(item.Value);??????????? }??????? }??? }??? return list;

}

在SaveViewState中只會將字典中item.IsDirty=true的項目返回,哪些項的IsDirty=true呢?通過上面對Add方法及LoadViewState的分析我們知道,當(dāng)我們第一次設(shè)置了控件的某個屬性后會調(diào)用Add方法,這個屬性對應(yīng)的StateItem的屬性IsDirty會被設(shè)置為true,在SaveViewState時會保存這個item。在下次請求時在LoadViewState中也會將IsDirty設(shè)置為true,在SaveViewState是會保存這個item。總之只要控件屬性的被修改過和默認(rèn)值不一致都會一直被保存,即使這個屬性的值僅僅被修改過一次,之后保存不不變,也會在多次PostBack之間保存起來。

5)???? TrackViewState

在TrackViewState方法中,設(shè)置跟蹤標(biāo)記為True,其目的就是開始狀態(tài)跟蹤了。示意代碼如下:

internal void TrackViewState()

{

??? this.marked = true;

}

3???????? ViewState與ControlState

ControlState是一個自定義的狀態(tài)保持機(jī)制,也就是說保持狀態(tài)的機(jī)制需要開發(fā)人員自己去完成,而不像ViewState,它有自己默認(rèn)的狀態(tài)保持機(jī)制。既然已經(jīng)有了ViewState為什么還需要ControlState呢?因為ViewState是可以被禁用的,而ControlState卻不能被禁用,對于有些必須保存的信息,就可以使用ControlState。ControlState的實現(xiàn)思路基本上與ViewState類似,ControlState需要保存的信息也被序列化后保存在__VIEWSTATE中。使用ControlState,需要在OnInit 方法中調(diào)用 RegisterRequiresControlState向頁面注冊,而且要重寫SaveAdapterControlState,LoadAdapterControlState這兩個方法自己,實現(xiàn)要保存什么,怎樣保存。

4???????? ViewState的使用

4.1?ViewState的優(yōu)缺點

使用ViewState首先要了解ViewState與其他的保持狀態(tài)機(jī)制相比有什么優(yōu)缺點。

使用ViewState具有以下優(yōu)點:

一、耗費的服務(wù)器資源較少(與Application、Session相比)。因為,視圖狀態(tài)數(shù)據(jù)都寫入了客戶端計算機(jī)中。

二、易于維護(hù)。默認(rèn)情況下,DotNet系統(tǒng)自動啟用對狀態(tài)數(shù)據(jù)的維護(hù)。

三、因為它不使用服務(wù)器資源、不會超時,并且適用于任何瀏覽器。

使用視圖狀態(tài)具有以下缺點:

一、性能問題。由于視圖狀態(tài)存儲在頁本身,因此如果存儲較大的值,用戶顯示頁和發(fā)送頁時的速度仍然可能減慢。ViewState 增加了發(fā)送到瀏覽器的頁面的大小,同時也增加了回傳的窗體的大小,因此不適合存儲大量數(shù)據(jù)

二、設(shè)備限制。移動設(shè)備可能沒有足夠的內(nèi)存容量來存儲大量的視圖狀態(tài)數(shù)據(jù)。

三、潛在的安全風(fēng)險。視圖狀態(tài)存儲在頁上的一個或多個隱藏域中。雖然視圖狀態(tài)以哈希格式存儲數(shù)據(jù),但它可以被篡改。如果直接查看頁輸出源,可以看到隱藏域中的信息,盡管 ViewState 數(shù)據(jù)已被編碼,并且可以選擇對其進(jìn)行加密,但始終不將數(shù)據(jù)發(fā)送到客戶端才是最安全的。

4.2?ViewState安全性

ViewState將一些信息保存在客戶端,而且默認(rèn)情況下客戶端的數(shù)據(jù)僅僅是進(jìn)行了Base64編碼了,很容易被看到原文。當(dāng)然ViewState還有一些安全性措施來改善這一點。ViewState 安全性對于處理和呈現(xiàn) ASP.NET 頁面所需的時間有直接的影響。簡單地說,安全性越高,速度越慢。因此如果不需要,不要為 ViewState 添加安全性。

4.2.1?? MAC

MAC是message authentication check的簡寫即消息驗證檢查。MAC可以防止ViewState數(shù)據(jù)被篡改。可以通過設(shè)置EnableViewStateMAC="true"屬性來啟用消息驗證檢查。可以在頁面級別上設(shè)置 EnableViewStateMAC,也可以在應(yīng)用程序級別上設(shè)置。有一點需要特別說明的是在MSDN中說EnableViewStateMAC的默認(rèn)值是Flase,但是實際上發(fā)現(xiàn)EnableViewStateMAC的默認(rèn)值是True,這一點大家可以Page_Load中輸出EnableViewStateMAC屬性來驗證。也就是說默認(rèn)情況下都是對ViewState進(jìn)行防篡改處理的。下面的描述結(jié)合“2.2.1Page中的處理”中的“4)ViewState序列化與反序列化”進(jìn)行理解。

ObjectStateFormatter中進(jìn)行序列化的時候如果EnableViewStateMAC="true",則在MachineKeySection.GetEncodedData根據(jù)字節(jié)流buf計算出一個20位的字節(jié)表示Hash值,增加在buf字節(jié)流的后邊,形成一個新的字節(jié)流。

ObjectStateFormatter中進(jìn)行反序列化的時候如果EnableViewStateMAC="true",則在MachineKeySection.GetDecodedData中取buf的前(length-20)位計算出一個20位的字節(jié)表示Hash值,將這個Hash值與buf的最后20位進(jìn)行比較,如果不一直則說明ViewState被篡改了則拋出異常。

默認(rèn)情況下,.NET框架使用SHA1算法來生成ViewState散列代碼。此外,也可以通過在machine.config文件中設(shè)置<machineKey>來選擇 MD5 算法,如下所示:<machineKey validation="MD5" />。MD5算法的性能要比SHA1算法好一些,但是同樣不夠安全。

4.2.2加密

默認(rèn)情況下__VIEWSTATE中存儲的值僅僅僅進(jìn)行了Base64編碼,并沒有進(jìn)行加密,如果ViewState中有一些敏感信息需要增加安全性,我們也可以對ViewState進(jìn)行加密。我們可以設(shè)置ViewStateEncryptionMode的值來決定是否加密,其值是“Auto”,“Always”,“Never”,默認(rèn)值是“Auto”。“Always”表示進(jìn)行加密,“Never”表示不進(jìn)行加密,“Auto”時如果調(diào)用了RegisterRequiresViewStateEncryption方法后則進(jìn)行加密。ViewStateEncryptionMode屬性不能在代碼中設(shè)置page指令或者配置文件中使用。

4.2.3設(shè)置ViewStateUserKey

設(shè)置 ViewStateUserKey 屬性有助于防止您的應(yīng)用程序受到惡意用戶的點擊式攻擊。必須在頁處理的 Page_Init 階段設(shè)置此屬性。具體的信息可以MSDN中的說明,鏈接如下:

http://msdn2.microsoft.com/zh-cn/library/ms972969.aspx

4.3?ViewState的禁用

因為ViewState會一定程度上影響性能所以在不需要的時候禁用 ViewState。默認(rèn)情況下 ViewState 將被啟用,并且是由每個控件(而非頁面開發(fā)人員)來決定存儲在 ViewState 中的內(nèi)容。有時,這一信息對應(yīng)用程序并沒有什么用處。盡管也沒什么害處,但卻會明顯增加發(fā)送到瀏覽器的頁面的大小。因此如果不需要使用 ViewState,最好還是將它關(guān)閉,特別是當(dāng) ViewState 很大的時候。通過將對象的EnableViewState屬性設(shè)置為False禁用ViewState。可以針對單個控件、整個頁面或整個應(yīng)用程序禁用ViewState,如下所示:

每個控件(在標(biāo)記上)<asp:datagrid EnableViewState="false" ?/>

每個頁面(在指令中) <%@ Page EnableViewState="False" ?%>

每個應(yīng)用程序(在 web.config 中) <Pages EnableViewState="false" ?/>

以下情況將不再需要ViewState:(1)控件未定義服務(wù)器端事件(這時的控件事件均為客戶端事件且不參加回送的);(2)控件沒有動態(tài)的或數(shù)據(jù)綁定的屬性值。

轉(zhuǎn)載于:https://www.cnblogs.com/PeterYao/archive/2009/10/13/1582829.html

總結(jié)

以上是生活随笔為你收集整理的ViewState机制的解析(转自csdn)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。