• 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对象。

  • 相关阅读:
    03_已解决 [salt.master :2195][ERROR ][6219] Failed to allocate a jid. The requested returner 'mysql' could not be loaded.
    02_已解决 [salt.minion :1758][ERROR ][52886] Returner mysql.returner could not be loaded: 'mysql' __virtual__ returned False: Could not import mysql returner; mysql python client is not installed.
    05_centos7安装python3
    04_mysql安装
    03_mysql-python模块, linux环境下python2,python3的
    02_pip区别: linux环境下python2,python3的
    01 salt平台,软件架构图
    01_初识redis
    list_for_each_entry()函数分析
    趣解什么是网关
  • 原文地址:https://www.cnblogs.com/hobe/p/1122203.html
Copyright © 2020-2023  润新知