`
sogotobj
  • 浏览: 618970 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

用 ASP.NET 2.0 改进的 ViewState 加快网站速度

阅读更多

用 ASP.NET 2.0 改进的 ViewState 加快网站速度

发布日期: 2006-1-13 |
本文讨论:

ViewState 如何工作

ASP.NET 2.0 ViewState 的改进

使用控件状态维护功能

性能考虑

本文使用以下技术:
ASP.NET、C#

代码下载:
ViewState.exe(122KB)

*
本页内容
 ViewState 基本原理 ViewState 基本原理
 ViewState 问题 ViewState 问题
ASP.NET 2.0 中的 ViewState 改进 ASP.NET 2.0 中的 ViewState 改进
控件状态 控件状态
声明性数据源和 ViewState 声明性数据源和 ViewState
小结 小结

如果您是个经验丰富的 ASP.NET 开发人员,一提起 ViewState ,您可能会不寒而栗,因为您想到的是大量通过“鸡尾酒吸管”吸入的 Base64 编码数据。除非采取步骤进行预防,否则大部分 ASP.NET 页面将有大量辅助数据被存储在一个名为 __VIEWSTATE 的隐藏字段中,多数情况下,甚至不需要这个字段。浏览用 ASP.NET 生成的您喜爱的站点,查看页面源代码,计算隐藏在 __VIEWSTATE 字段中的字符数。我尝试了一下,数量为 800 到 7,800 个字符。

当然, ViewState 在 ASP.NET 中有个重要的角色。如果使用恰当,它能够简化页面开发,改进用户与站点的交互。如果置之不理,它能够显著增加站点响应大小,在连接速度慢的情况下,使您的响应时间更加缓慢。ASP.NET 2.0 的发布带来了 ViewState 机制的一些改进,这使得 ViewState 使用更简单,又不会防碍站点性能。这些改进包括:减少编码数量,采用控件状态从内容中分离出行为状态,以及智能集成数据绑定控件。

ViewState 基本原理


在介绍 ASP.NET 2.0 ViewState 的改进之前,简要总结目前版本中 ViewState 的用途和实现是适宜的。 ViewState 为 ASP.NET 开发人员解决了一个特定问题 — 保留服务器端不形成元素的控件的状态。这很重要,因为 ASP.NET 中的大部分服务器端控件模型是根据这样一个假设生成的,那就是 — 如果用户回发到相同页面,所有控件保持其状态不变。也就是说,如果在处理请求期间修改任何控件的内容,任何后续 POST 请求回到相同页面时,您可以依赖于那些仍然存在的修改。作为一个活动的 ViewState 示例,尝试运行图 1 显示的页面。

每次按下 Submit 按钮时,_sum 范围值递增。因为 ViewState 在请求期间保持以前的值,因此它将从上一次显示的值开始,显示 1、2、3、4 等等。如果想知道 ViewState 不可用时发生的事情,尝试添加 enableviewstate='false' 作为范围元素的一个属性。因为以前的范围值在请求处理时没有传播,所以不论页面发布多少次,都将显示值为 1。

在 ASP.NET 中, ViewState 完成基于控件的编程模型。如果没有 ViewState ,一些控件(如文本框和下拉列表)在 POST 请求期间保持状态,而其他控件不保持,使用这些状态各异的控件记录一些特殊的情况是令人沮丧的体验。使用 ViewState ,开发人员能够专注于编程模型和用户界面,而不用担心状态保持。还能对 ViewState 进行哈希或加密,以防止用户篡改或解码。关于这个主题的更多信息,请参见在线书籍 Securing Your ASP.NET Application and Web Services 的第 19 章。

使用 ViewState 的另一个重要之处是在控件中发布服务器端更改事件。如果用户改变了文本框中的值或切换了下拉列表中的选定元素,您就能够注册一个事件处理程序,引发事件时,执行代码。这些控件比较其当前值与以前值,如果有任何过程预订更改事件,以前值隐式存储在 ViewState 中。如果禁用一个控件的 ViewState ,而您正在处理该控件的更改通知事件,因为总是假定以前值与窗体默认值相同,所以更改通知事件不会正确激发。

ViewState 问题


正如我早前指出的,在 ASP.NET 1.x 中, ViewState 有很多问题。默认情况下,它是启用的,除非您知道在不需要使用时找到并禁用它,否则它能显著增加页面呈现的数据量。当使用数据绑定控件时,所有控件都使用 ViewState 保存回发后的状态,这将变得异常痛苦。作为一个简单而生动的示例,考虑图 2 所示的 ASP.NET 页面。

这个页面有一个 DataGrid 控件,该控件绑定对 pubs 数据库中 authors 表格进行简单查询的结果。如果运行这个页面(对连接字符串做出必要改正),查看 ViewState 字段,您可能吃惊地发现里面有超过 12,000 个字符。当查看页面内容,意识到显示浏览器中整个表格内容所需的实际字符数量大约是 1,600,您会更加吃惊。造成这个结果的原因之一是 ViewState 不仅编码数据,而且编码数据类型(元数据);同样,Base64 编码一般要增加大约 33 % 的空间系统开销。而且,大量的系统开销只是为了保留 POST 请求后的控件状态,这似乎与时间不成比例,必须竭尽全力避免发生。

很明显,如果您关心响应大小,那么决定何时禁用控件的 ViewState 是重要的。刚才的示例就是一个典型的情况,传播了 ViewState ,但是从未使用,这是优化站点的 ViewState 使用时建议采用的主要规则:如果每次请求页面时填充控件内容,禁用该控件的 ViewState 一般是安全(而明智)的。

另一方面,您可能决定利用 ViewState 保留控件状态这一实事,并且只在页面的首次 GET 请求时,填充控件内容(只是贯穿后续 POST 请求)。这省去了使用的任何后端数据源的往返行程。通过修改我的页面来利用这一结论,我更改了 OnLoad 方法,使它在填充 DataGrid 前检查 IsPostBack 标志,如图 3 所示。

当然,有一些其他可能更好的选择,例如缓存服务器的查询结果,每次发出请求时重新绑定控件。由您权衡状态存储的位置和特定体系结构与应用程序的重要性。

您可能注意到我曾小心提过,如果每次请求页面时填充控件内容,那么禁用 ViewState “一般”是安全的。例外情况是,一些控件既使用 ViewState 保留行为,也保留一般状态。如前所述,下拉列表和文本框控件使用 ViewState 存储以前的值来正确发布服务器上的更改通知事件。同样地,DataGrid 类使用 ViewState 发布分页、编辑和排序事件。遗憾的是,如果您想要使用 DataGrid 中诸如排序、分页或编辑的功能,则不能禁用其 ViewState 。对于尝试生成快速有效站点的开发人员来说,服务器端控件 ViewState 的非全有即全无的状况,是 ASP.NET 1.x 的服务器端控件模型另人沮丧的一面。

ASP.NET 2.0 中的 ViewState 改进


既然我概述了这些问题,是时候讨论 ASP.NET 2.0 中的所有改进了。第一个是 ViewState 序列化时的总大小。在 ASP.NET 1.x 中,两个字符串进入 ViewState 缓冲区中的序列化如下所示:

<p<l<string1;>;l<string2;>>;>;

ASP.NET 1.x 中使用的 ViewState 序列化格式是元组格式,由三个一组的层次集合和使用大于号和小于号的序列对组成。大于号之前的字母代表存储对象的类型(t=triplet,p=pair,i=integer,l=ArrayList,等)。大于号和小于号内的每个子元素由分号分隔。这是有趣的序列化格式,有点像一个压缩的 XML。但是,如果您关心空间,那么它不是最有效的序列化格式(只是比 XML 稍好一点)。

ASP.NET 2.0 改变了这种序列化格式。在 ASP.NET 2.0 中,相同的两个字符串进入 ViewState 缓冲区的序列化如以下代码行所示:

[][]string1[]string2

至少,这很像浏览器呈现的格式。方括号实际上是非打印字符,如果我们使用 Unicode 字符引用来重写,则变成了以下显示的编码:

&#15;&#5;string1&#5;string2

ASP.NET 2.0 使用一些非打印字符标识对象的起始并表述对象的类型,而非使用可打印字符集(“<”、“>”、“;”、“l”、“i”、“p”等)来分割 ViewState 流中的对象。

使用非打印字符分割 ViewState 中存储的对象有两个目的。第一个目的是改进解析 ViewState 字符串时进行词法分析的效率,因为此时不再需要匹配字符或解析标记。第二个,也是更重要的目的是它减少了为 ViewState 中的对象编码所使用的字符数量。在为两个字符串编码的简单示例中,第一种编码方法使用了 16 个分割字符,而 2.0 格式使用了 3 个。这种作用很快地复合而产生了重大的影响。

例如,如果我们在窗体上放置一个 DataGrid,将其绑定到 pubs 数据库的 authors 表格,如图 3所示,则 1.x 中的 ViewState 字符串大小是 12,648 个字符。如果在 2.0 中也这样做, ViewState 大小减少到 6,728 个字符,几乎减少了一半。图 4 显示 ASP.NET 1.x、ASP.NET 2.0 中 ViewState 所需的空间对比,以及不同输入大小在页面实际呈现的字符数。在这种情况下,authors 表格在 500 行处增加了额外的行,达到了 2,000 行。


图 4 ViewState 大小对比


随着 ASP.NET 2.0 版本的发布,您能够期望立即减小 ViewState 大小,而无需做任何特别的工作。这不意味着您应该停止考虑控件正常工作是否需要 ViewState ,这是因为它仍然对响应大小有很大影响,在图 4 中表现的很明显。然而, ViewState 的下一个改进能潜在地节省更多。

控件状态


我先前提过,ASP.NET 1.x 中使用服务器端控件最另人沮丧的一面是关于 ViewState 的非全有即全无的状态。控件的行为方面,如 DataGrid 中的分页或文本框中的选定更改通知,需要启用 ViewState 来正常运行。我确定在任何 DataGrid 中启用 ViewState 的前景令所有人十分沮丧。在 ASP.NET 2.0 中,Microsoft 通过将 ViewState 分割成两个独立不同的类别解决了这一特殊问题: ViewState 和控件状态。

控件状态是另一类隐藏的状态,专门为维护控件的核心行为功能而保留,而 ViewState 只包含维护控件内容 (UI) 的状态。从技术上来说,控件状态存储在与 ViewState 相同的隐藏字段中(只是在 ViewState 层次结构末端的另一个叶子节点),但是如果禁用一个特定控件或整个页面的 ViewState ,控件状态仍然传播。实现这一技术好的一面是,现在我们能够改进 ASP.NET 2.0 优化 ViewState 的原始原则,使之更强健:如果在每次请求页面时传播控件内容,您应该禁用该控件的 ViewState 。

只要控件生成器将其状态正确划分成行为状态(为了维护核心功能)和 UI 状态(为了保留内容),就应该坚定地遵守这个原则。我建议您现在使用 ASP.NET 2.0 时开始遵循这个原则,但是 DataGrid 还未重构以保留控件状态中的行为状态。幸运的是,新的 GridView 是 DataGrid 的逻辑继承者,它像 TextBox 和 DropDownList 控件的新版本一样正确使用控件状态。图 5 显示的是目前使用控件状态的控件列表及其存储的属性,供您参考。随着 ASP.NET 2.0 的最终发布,这个列表可能会作出变动。

如果您愿意进一步研究 ASP.NET 2.0 的新控件如何使用控件状态和 ViewState ,可以使用我编写的一个叫做 View State Decoder 的实用工具,它用来显示给定页面上所有的 ViewState 和控件状态。图 6 显示的是活动的实用工具的一个屏幕快照。您能够从本文顶端的链接下载该程序。注意,这个应用程序依赖于目前 ViewState 使用的编码字符,在最终版本发布前可能会改变。

对于您的那些生成控件,控件状态的使用模型不像 ViewState 一样方便。您必须重写 LoadControlState 和 SaveControlState 虚方法,手动管理您那部分映射到控件状态中的对象集合,而非提供一个带有索引的状态包用来插入和移除选项。另一件您必须做的事情是在初始化期间调用 Page.RegisterRequiresControlState 方法,使页面能够在正确的时间询问控件状态。在控件状态中存储选项比在 ViewState 中更难可能是一件好事,因为用户无法禁用它(控件状态有一个选择模型也有性能方面的好处)。开发人员在存储任何状态前应该认真考虑,因为它总是添加到呈现的页面中。图 7 显示在控件状态中存储一个字符串的自定义控件(本例中是它的颜色)。

当您决定控件状态和 ViewState 各存储什么内容时,请记住行为状态与内容或者 UI 状态应该有分别。诸如属性和数据集一样的内容一般应存储在 ViewState 中,而不是迁移到控件状态。触发服务器端事件的状态是存储在控件状态中最典型的一类状态。

声明性数据源和 ViewState


应用我们的 ViewState 优化原则有一个小问题 — 您经常不知道每次请求时是否正在填充控件内容。在 ASP.NET 2.0 中采用声明性数据源意味着将数据绑定到一个控件不再需要将数据源属性显式连接至 DataReader 或 DataSet,并调用 DataBind。而是在页面上声明性地放置一个数据源,并将控件指向该数据源。例如,使用绑定到 pubs 数据库中 authors 表格的新 GridView 类和与之相关的 SqlDataSource(参见 图 8)。如果运行这个页面,您将发现它正好有效。GridView 及其相应的数据源能够了解何时进行交互。在页面呈现之前,GridView 充满数据源的数据,并且很可能在客户端呈现整个 authors 表格。

在这个简单的情况中,我们还未禁用 GridView 的 ViewState ,因此您可能会认为,我们再一次仅仅使用 ViewState 存储了从未使用的数据。幸运的是,ASP.NET 2.0 引擎作了正确的事情,当控件上的 ViewState 可用时,它将不厌其烦地返回到数据库。

同样地,如果禁用 GridView 上的 ViewState ,数据绑定到数据源将发生在每次请求发生的时候,包括 POST back 请求。DataBoundControl 基类中置入了这一功能,其中的 AdRotator、BulletedList、CheckBoxList、DropDownList、ListBox、RadioButtonList、GridView、DetailsView 和 FormView 控件继承了该功能。这些控件展示了 ViewState 在绑定到声明性数据源时表现的智能使用。

小结


ASP.NET 的下一个版本对 Web 开发人员承诺了许多改进,不只是更有可能晚上好好休息,不会做 Base64 编码数据淹没了 Web 窗体的噩梦。使用更紧凑的序列化格式、行为状态和 UI 状态的分离以及数据绑定控件和声明性数据源的智能交互,那些 ViewState 的噩梦仅可能变成美梦。

分享到:
评论

相关推荐

    asp.net 2.0中通过压缩ViewState

    asp.net 2.0中通过压缩ViewState 支持ajax压缩ViewState

    ASP.NET 2.0+SQL Server 2005全程指南-源代码

    ASP.NET 2.0+SQL Server 2005全程指南 目录 基础篇 第1章 ASP.NET概述及环境配置 1.1 认识ASRNET 1.1.1 .NET Framework框架 1.1.2 ASP.NET功能与特性 1.1.3 ASP.NET与ASP的区别 1.2 搭建ASP.NET开发环境 1.2.1...

    2.ASP.NET.2.0.高级编程(第4版) [1/7]

    2.ASP.NET.2.0.高级编程(第4版) [1/7] 原书名: Professional ASP.NET 2.0 原出版社: Wrox 作者:(美)Bill Evjen, Scott Hanselman, Farhan Muhammad [同作者作品] [作译者介绍] 译者: 李敏波[同译者作品] ...

    asp.net教程 ASP.NET 参考手册

    ASP.NET 维持 ViewState 本文讲解如何维持 ViewState。 ASP.NET 文本框控件 本章阐述 ASP 的基础:文本框控件。 ASP.NET 按钮控件 本章阐述 ASP 的基础:按钮控件。 ASP.NET Binding ASP.NET 数据绑定 本文...

    ASP.NET2.0高级编程(第4版)1/6

    本书全面介绍了ASP.NET各种编程技能和2.0版中的巨大变化,并详细阐述了2.0版中的每个新特性。书中提供了大量的实例,可帮助读者快速掌握如何在.NET平台下开发功能强大的ASP.NET应用程序。本书适合有一些基础的ASP...

    基于 ExtJS 的专业 ASP.NET 2.0 控件库.zip

    ExtAspNet - 基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果 ExtAspNet 是一组基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果。 ExtAspNet 是为了...

    如何封装JS和CSS文件为服务器端控件---ASP.NET 2.0

    如何封装JS和CSS文件为服务器端控件---ASP.NET 2.0 我们以封装一个JS的日期控件为列子,将它和服务器的TextBox结合在一起做成一个服务器控件,以达到直接托上去就可以使用的效果。其实很简单,大家共同学习。先看看...

    asp.net2.0系列教程第5章_第1节

    5章_第1节 第一节ViewState HiddenField的原理和应用

    asp.net2.0系列教程第5章_第2节

    第5章第二节ViewState HiddenField的原理和应用(续)Cookie的原理和应用

    asp.net知识库

    ASP.NET2.0 ObjectDataSource的使用详解(2) TextDataSource(1) — DataSourceControl内幕 TextDataSource(2) — 翠花,上“数据” ASP.NET2.0 ObjectDataSource的使用详解(3) ASP.NET2.0 快速入门 ----默认...

    ASP.NET 2.0 中收集的小功能点(转)

    1.asp.net 2.0中的MaxPageStateFieldLength 属性 在asp.net 2.0中,可以强制对viewstate进行分段传输了,使用的是Page.MaxPageStateFieldLength 属性,可以设置viewstate中,每个页面状态字段的最大字节数。...

    asp.net页面中的viewstate内容解析器

    有些asp.net中使用viewstate,那里的内容是base64编码,此工具是把viewstate 内容给解析成原来内容,里面包括1.0,1.1,2.0三种版本的工具

    ASP.NET常见问题集锦.zip

    ASP.NET ViewState 初探.doc ASP.NET Web 方法中的 XmlElement 参数的功能.d ASP.NET 中 Cookie 的基本知识.doc ASP.NET 页面对象模型.doc asp.net200问-专家门诊—ASP.NET开发答疑 ASP.NetWebPage深入探讨....

    Test-Drive ASP.NET MVC

    ASP.NET MVC 2.0 is C# on the web done right. No more fiddling around with Viewstate, IsPostBack(), and drag-and-drop coding. Microsoft has addressed the shortcomings of ASP.NET and created a framework...

    FineUI_v3.2.0_source_all.zip_extjs 6_fineui_opera_web UI CSHARP

    FineUI - 基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果 FineUI 是一组基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果。 FineUI 是为了创建没有 ...

    ASP.NET教学讲义,完整章节

    3.4 ASP.NET2.0新增控件 54 3.5 客户端处理 61 3.6验证控件 63 3.7自定义验证控件 71 3.8验证总结控件 73 第四章:ASP.NET内置对象 76 4.1内置对象概述 76 4.2 Response对象和Request对象 76 4.3、HttpServerUtility...

    ASP.NET2.0服务器控件之自定义状态管理

     自定义视图状态管理 在介绍视图状态时,我们曾经提到过:对于简单属性,例如,String、Int等类型,.NET执行引擎将自动启用默认视图状态管理机制,以便完成相应的功能。然而,如果开发人员在ViewState中保存的是...

    asp.net教学讲义

    3.4 ASP.NET2.0新增控件 45 3.4.1 ImageMap控件 45 3.4.2 FileUpload控件 48 3.5 客户端处理 52 3.5.1 第一种方式示例: 52 3.5.2第二种方式:动态注册javascript指令块 53 3.6验证控件 54 3.6.1验证控件简介 54 ...

    基于Extjs的开源控件库ExtAspNet英文版 v3.1.9

    ExtAspNet - 基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果 ExtAspNet 是一组基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果。 ExtAspNet 是为了创建...

    基于Extjs的开源控件库ExtAspNet中文版 v3.1.9

    ExtAspNet - 基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果 ExtAspNet 是一组基于 ExtJS 的专业 ASP.NET 2.0 控件库,拥有完善的 AJAX 支持和丰富的界面效果。 ExtAspNet 是为了创建...

Global site tag (gtag.js) - Google Analytics