ViewState机制由浅入深1
1???????? ViewState機制是什么?
ViewState機制是asp.net中對同一個Page的多次請求(PostBack)之間維持Page及控件狀態的一種機制。在WebForm中每次請求完,Page對象都會被釋放,對同一個Page的多次請求之間的狀態信息,如何進行維護呢?WebForm中,每次請求都會存在客戶端和服務器之間的一個交互。如果請求完成之后將一些信息傳回到客戶端,下次請求的時候客戶端再將這些狀態信息提交給服務器,服務器端對這些信息使用和處理,再將這些信息傳回給客戶端。這樣是不是就可以對同一個Page的多次請求(PostBack)之間維持狀態了。對這就是ViewState的基本工作模式。ViewState的設計目的主要就是為了將必要的信息持久化在頁面中。這樣通過ViewState在頁面回傳的過程中保存狀態值,使原本沒有“記憶”的Http協議變得有“記憶”起來。
2???????? ViewState機制如何工作?
下面我們看看ViewState機制是如何具體的工作的。
2.1?客戶端:
我們先從客戶端看起,在客戶端的HTML源代碼中我們可以看到下面的代碼
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPDwULLTE0MTAzNDUwNThkZKr77J2uy7fatyBou8PocG80X4Jt" />
這個就是ViewState在客戶端的保存形式,它保存在一個ID為__VIEWSTATE的Hidden中,它的Value是使用Base64編碼后的字符串。這個字符串實際上是一個對象(Pair類型)序列化之后的結果。這個對象保存了整個頁面的控件樹的ViewState。可以使用一些工具將這個字符串進行解碼查看其內容,比如ViewStateDecoder,ViewStateAnalyzer。
2.2?服務器端:
在服務器端和ViewState機制密切相關的有三個類Page,Control,StateBag。他們3者的關系如下圖所示:
圖1
Page繼承自Control,Control和StateBag是聚合關系,在Control中有一個StateBag的實例ViewState。這三個類互相協作完成ViewState機制的大概過程如下。Page對客戶端請求進行處理,在處理的過程中先是將客戶端提交的_VIEWSTATE反序列化為對象,調用Control的相關方法給所有的控件裝載數據,這些數據是上次請求結束后控件的狀態數據。在之后的一些事件中這些狀態數據可能被修改。在請求結束之前調用Control的相關方法得到所有控件的被修改過的狀態數據,之后Page將其進行序列化,并返回給客戶端。在Control中又具體調用StateBag類的方法完成狀態數據的加載和保存。
2.2.1?? Page中的處理
圖2 Page生命周期
1)???? InitRecursive
在Page的生命周期中有3處與ViewState相關,在初始化階段調用Control. InitRecursive,它遞歸對所有的控件進行初始化,其中調用了Control.TrackViewState。TrackViewState中打開跟蹤ViewState開關。
2)???? LoadAllState
在初始化完成之后會調用Page.LoadAllState,LoadAllState只有在PostBack的時候才會執行,它的主要功能是將從頁面傳遞來的__VIEWSTATE的值反序列化為Pair類型的對象,然后將這個對象中存儲的ViewState的值加載到Page及所有控件中。實際上LoadAllState加載了ControlState(控件狀態)及ViewState(視圖狀態),本文主要是討論ViewState,對ControlState部分的處理不進行描述。
LoadAllState中主要有兩步:Page.LoadPageStateFromPersistenceMedium和Control.LoadViewStateRecursive。
在LoadPageStateFromPersistenceMedium中發生了如下的調用層次
Page.LoadPageStateFromPersistenceMedium
è??? HiddenFieldPageStatePersister.Load
è??? ObjectStateFormatter.Deserialize
以上完成的功能是將客戶端提交的_VIEWSTATE反序列化為一個類型為Pair的對象pair。
Control.LoadViewStateRecursive中將遞歸加載控件的ViewState,具體在下面進行講解。
3)???? SaveAllState
SaveAllState它的操作和LoadAllState相反。SaveAllState中主要有兩步Control.SaveViewStateRecursive及Page SavePageStateToPersistenceMedium。
Control.SaveViewStateRecursive中將所有控件的ViewState屬性遞歸加載到一個Pair對象中,具體實現細節在下面講解。
Page SavePageStateToPersistenceMedium中發生如下的調用關系。
Page SavePageStateToPersistenceMedium
è??? HiddenFieldPageStatePersister.Save
è??? ObjectStateFormatter.Serialize
將Control.SaveViewStateRecursive生成的對象序列化為一個字符串,并賦值給Page.ClientState屬性。
在Render階段發生如下的調用關系:
HtmlForm.RenderChildren
è??? Page.BeginFormRender
è??? Page.RenderViewStateFields
最終將ClientState屬性中的值寫入到HTML頁面的_VIEWSTATE中。
在Control.InitRecursive中打開跟蹤開關,打算對ViewState的值進行跟蹤,在Page.LoadAllState中將客戶端提交的__VIEWSTATE的值裝載到各個控件的ViewState中,在Page.SaveAllState中將發生變化的ViewState序列化為一個字符串,在Render階段發送回客戶端。
4)???? ViewState序列化與反序列化
PageStatePersister 是一個抽象類,是表示將ViewState信息序列化及反序列化機制的基類。在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中實現PageStatePersister這個抽象類,具體提供持久化機制的類是HiddenFieldPageStatePersister。它實現了Load和Save兩個方法,Load時將__VIEWSTATE反序列化為一個Pair對象,Save時將Pair對象序列化為一個字符串賦值給Page.ClientState。HiddenFieldPageStatePersister中采用的格式器是ObjectStateFormatter,其實現string Serialize(object state),和object Deserialize(string serializedState)這兩個方法,從而實現對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序列化為內存流,在將其轉換為字節流。如果需要加密則對其進行加密處理,否則需要Mac則進行Mac處理。最后將字節流進行Base64編碼轉換為字符串。
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);
將字符串進行Base64解碼為字節流,如果需要解密則進行解密處理,否則需要進行需要Mac則進行Mac處理,將字節流轉換為內存流,進行反序列化返回Pair對象。
轉載于:https://www.cnblogs.com/hobe/archive/2008/03/25/1122203.html
總結
以上是生活随笔為你收集整理的ViewState机制由浅入深1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka SCRAM和PLAIN实战
- 下一篇: SQL Server死锁问题:事务(进程