现在的位置: 首页 > 综合 > 正文

ViewState介绍和总结(2)——–ViewState的使用和优缺点

2013年11月18日 ⁄ 综合 ⁄ 共 5426字 ⁄ 字号 评论关闭

1.     ViewState的使用

ViewState的使用比较简单,主要是赋值和取值两步操作:

赋值:ViewState[key] = value;

取值:value = ViewState[key];

最主要的作用就是可以在当前页面保存值,ASP.NET的页面状态维护就是使用ViewState来实现的,基本上每一个ASPX页面都可以看到如下类似的html代码:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTkwNjc4NTIwMWRkyv4ncofW5vaWXdXRtXfXn3RYQR4="/>也就是说ViewState中的值实际上都是通过一个hidden(隐藏域)来保存的,hidden(隐藏域)的name__VIEWSTATE,那么如果页面上有另外一个控件的名称也叫:__VIEWSTATE的话,会导致页面出错,因为同一个页面上不允许有两个相同ID的控件。其实在我们进行页面开发或者进行自定义控件开发的时候,都可以使用ViewState,用来保存当前页面的一些状态值,这样是非常方便的。ViewStateASP.NET中特有的,相对于Session来说,它保存的值只能在当前页面使用,并且保存的只能是已经序列化的类,比如.NET中的strings, integers, Booleans, arrays, ArrayList, hashtableDataTableList<T>等。那么如何将自定义的类放入ViewState中呢,这个就涉及到序列化的问题了:序列化简单来说就是把一个对象转化成一种可以持久保存的数据,当下次需要使用时再把之前保存的数据反序列化成一个对象。当然在.NET中提供了简便的方法进行序列化的操作

下面我以一个简单的例子来说明:

3.  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。它实现了LoadSave两个方法,Load时将__VIEWSTATE反序列化为一个Pair对象,Save时将Pair对象序列化为一个字符串赋值给Page.ClientStateHiddenFieldPageStatePersister中采用的格式器是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对象。

4.  ViewState的优缺点:

(1)优点:

    耗费的服务器资源较少(与ApplicationSession相比)。因为,视图状态数据都写入了客户端计算机中。

    易于维护。默认情况下,DotNet系统自动启用对状态数据的维护。

    因为它不使用服务器资源、不会超时,并且适用于任何浏览器。

(2)缺点:

         性能问题。由于视图状态存储在页本身,因此如果存储较大的值,用户显示页和发送页时的速度仍然可能减慢。ViewState 增加了发送到浏览器的页面的大小,同时也增加了回传的窗体的大小,因此不适合存储大量数据。

设备限制。移动设备可能没有足够的内存容量来存储大量的视图状态数据。

潜在的安全风险。视图状态存储在页上的一个或多个隐藏域中。虽然视图状态以哈希格式存储数据,但它可以被篡改。如果直接查看页输出源,可以看到隐藏域中的信息,尽管 ViewState 数据已被编码,并且可以选择对其进行加密,但始终不将数据发送到客户端才是最安全的。

5.       ViewState的安全性:

ViewState将一些信息保存在客户端,而且默认情况下客户端的数据仅仅是进行了Base64编码了,很容易被看到原文。当然ViewState还有一些安全性措施来改善这一点。ViewState 安全性对于处理和呈现 ASP.NET 页面所需的时间有直接的影响。简单地说,安全性越高,速度越慢。因此如果不需要,不要为 ViewState 添加安全性。

(1)  MAC

MACmessage authentication check的简写即消息验证检查。MAC可以防止ViewState数据被篡改。可以通过设置EnableViewStateMAC="true"属性来启用消息验证检查。可以在页面级别上设置 EnableViewStateMAC,也可以在应用程序级别上设置。有一点需要特别说明的是在MSDN中说EnableViewStateMAC的默认值是Flase,但是实际上发现EnableViewStateMAC的默认值是True,这一点大家可以Page_Load中输出EnableViewStateMAC属性来验证。也就是说默认情况下都是对ViewState进行防篡改处理的。在ObjectStateFormatter中进行序列化的时候如果EnableViewStateMAC="true",则在MachineKeySection.GetEncodedData中根据字节流buf计算出一个20位的字节表示Hash值,增加在buf字节流的后边,形成一个新的字节流。

ObjectStateFormatter中进行反序列化的时候如果EnableViewStateMAC="true",则在MachineKeySection.GetDecodedData中取buf的前(length-20)位计算出一个20位的字节表示Hash值,将这个Hash值与buf的最后20位进行比较,如果不一直则说明ViewState被篡改了则抛出异常。

默认情况下,.NET框架使用SHA1算法来生成ViewState散列代码。此外,也可以通过在machine.config文件中设置<machineKey>来选择 MD5 算法,如下所示:<machineKey validation="MD5" />。MD5算法的性能要比SHA1算法好一些,但是同样不够安全。

(2)  ViewState加密

默认情况下__VIEWSTATE中存储的值仅仅仅进行了Base64编码,并没有进行加密,如果ViewState中有一些保密信息需要增加它的安全性,这样我们可以对ViewState进行加密。我们可以设置ViewStateEncryptionMode的值来决定是否加密,其值是“Auto”,“Always”,“Never”,默认值是“Auto”。“Always”表示进行加密,“Never”表示不进行加密,“Auto”时如果调用了RegisterRequiresViewStateEncryption方法后则进行加密。ViewStateEncryptionMode属性不能在代码中设置page指令或者配置文件中使用。

(3)  设置ViewStateUserKey

设置 ViewStateUserKey 属性有助于防止您的应用程序受到恶意用户的点击式攻击。必须在页处理的 Page_Init 阶段设置此属性。具体的信息可以参照MSDN中的说明:http://msdn2.microsoft.com/zh-cn/library/ms972969.aspx

(4)  ViewState的禁用

因为ViewState会一定程度上影响性能所以在不需要的时候禁用 ViewState。默认情况下 ViewState 将被启用,并且是由每个控件(而非页面开发人员)来决定存储在 ViewState 中的内容。有时,这一信息对应用程序并没有什么用处。尽管也没什么害处,但却会明显增加发送到浏览器的页面的大小。因此如果不需要使用 ViewState,最好还是将它关闭,特别是当 ViewState 很大的时候。通过将对象的EnableViewState属性设置为False禁用ViewState。可以针对单个控件、整个页面或整个应用程序禁用ViewState,如下所示:

每个控件(在标记上)<asp:datagrid EnableViewState="false" />

每个页面(在指令中) <%@ Page EnableViewState="False" %>

每个应用程序(在 web.config 中) <Pages EnableViewState="false" />

以下情况将不再需要ViewState:(1)控件未定义服务器端事件(这时的控件事件均为客户端事件且不参加回送的);(2)控件没有动态的或数据绑定的属性值。

(5)  ViewState的优化

ViewState优缺点并存,有些人支持使用,有些人反对使用,也有人提出了对ViewState的优化,主要是压缩ViewState减少传输量及修改ViewState的存储位置。

 

抱歉!评论已关闭.