ASP.NET状态管理的总结
阅读目录
∙ 开始
∙ hidden-input
∙ QueryString
∙ Cookie
∙ ApplicationState
∙ ViewState,ControlState
∙ Session
∙ Profile
∙ 各种状态管理的对比与总结
∙ 会话状态的选择
∙ 改变开发方式,发现新方法
由于HTTP协议的无状态特性,导致在ASP.NET编程中,每个请求都会在服务端从头到执行一次管线过程, 对于ASP.NET页面来说,Page对象都会重新创建,所有控件以及内容都会重新生成, 因此,如果希望上一次的页面状态能够在后续页面中保留,则必需引入状态管理功能。
ASP.NET为了实现状态管理功能,提供了8种方法,可帮助我们在页面之间或者整个用户会话期间保留状态数据。 这些方法分为二类:视图状态、控件状态、隐藏域、Cookie 和查询字符串会以不同方式将数据发送到客户端上。 而应用程序状态、会话状态和配置文件属性(Profile)则会将数据存储到服务端。 虽然每种方法都有不同的优点和缺点,对于小的项目来说,可以选择自己认为最容易使用的方法, 然而,对于有着较高要求的程序,尤其是对于性能与扩展性比较关注的程序来说, 选择不同的方法最终导致的差别可能就非常大了。
在这篇博客中,我将谈谈自己对ASP.NET状态管理方面的一些看法。
注意:本文的观点可能并不合适开发小型项目,因为我关注的不是易用性。
注意:本文的观点可能并不合适开发小型项目,因为我关注的不是易用性。
回到顶部
hidden-input
hidden-input 这个名字我是取的,表示所有type="hidden"的input标签元素。 在中文版的MSDN中,也称之为 隐藏域 。 hidden-input通常存在于HTML表单之内,它不会显示到页面中, 但可以随表单一起提交,因此,经常用于维护当前页面的相关状态,在服务端我们可以使用Request.Form[]来访问这些数据。
一般说来,我通常使用hidden-input来保存一些中间结果,用于在多次提交中维持一系列状态, 或者用它来保存一些固定参数用来提交给其它页面(或网站)。 在这些场景中,我不希望用户看到这些数据,因此,使用hidden-input是比较方便的。
关于表单的更多介绍可参考我的博客:细说 Form (表单)
在ASP.NET WebForm框架中,我们可以使用HiddenField控件来创建一个hidden-input控件,并可以在服务端操作它, 还可以直接以手写的方式使用隐藏域,例如:
<input type="hidden" name="hidden-1" value="aaaaaaa" />
<input type="hidden" name="hidden-2" value="bbbbbbb" />
<input type="hidden" name="hidden-3" value="ccccccc" />
另外,我们还可以调用ClientScript.RegisterHiddenField()方法来创建隐藏域:
ClientScript.RegisterHiddenField("hidden-4", "ddddddddd");
输出结果:
<input type="hidden" name="hidden-4" id="hidden-4" value="ddddddddd" />
这三种方法对于生成的HTML代码来说,主要差别在于它们出现位置不同:
1. HiddenField控件:由HiddenField的出现位置来决定(在form内部)。
1. HiddenField控件:由HiddenField的出现位置来决定(在form内部)。
2. RegisterHiddenField方法:在form标签的开头位置。
3. hidden-input:你写在哪里就是哪里。
3. hidden-input:你写在哪里就是哪里。
优点:
1. 不需要任何服务器资源:隐藏域随页面一起发送到客户端。
2. 广泛的支持:几乎所有浏览器和客户端设备都支持具有隐藏域的表单。
3. 实现简单:隐藏域是标准的 HTML 控件,不需要复杂的编程逻辑。
1. 不需要任何服务器资源:隐藏域随页面一起发送到客户端。
2. 广泛的支持:几乎所有浏览器和客户端设备都支持具有隐藏域的表单。
3. 实现简单:隐藏域是标准的 HTML 控件,不需要复杂的编程逻辑。
缺点:
1. 不能在多页面跳转之间维持状态。
2. 用户可见,保存敏感数据时需要加密。
1. 不能在多页面跳转之间维持状态。
2. 用户可见,保存敏感数据时需要加密。
回到顶部
QueryString
查询字符串是存在于 URL 结尾的一段数据。下面是一个典型的查询字符串示例(红部分文字):
www.abc/demo.aspx?k1=aaa&k2=bbb&k3=ccc
查询字符串经常用于页面的数据过滤,例如:
1. 给列表页面增加分页参数,list.aspx?page=2
2. 给列表页面增加过虑范围,Product.aspx?categoryId=5
3. 显示特定记录,ProductInfo.aspx?page=3
1. 给列表页面增加分页参数,list.aspx?page=2
2. 给列表页面增加过虑范围,Product.aspx?categoryId=5
3. 显示特定记录,ProductInfo.aspx?page=3
关于查询字符串的用法,我补充二点:
1. 可以调用HttpUtility.ParseQueryString()来解析查询字符串。
2. 允许参数名重复:list.aspx?page=2&page=3,因此在修改URL参数时,使用替换方式而不是追加。
关于参数重名的读取问题,请参考我的博客:细说 Request[]与Request.Params[]
1. 可以调用HttpUtility.ParseQueryString()来解析查询字符串。
2. 允许参数名重复:list.aspx?page=2&page=3,因此在修改URL参数时,使用替换方式而不是追加。
关于参数重名的读取问题,请参考我的博客:细说 Request[]与Request.Params[]
优点:
1. 不需要任何服务器资源:查询字符串的数据包含在每个URL中。
2. 广泛的支持:几乎所有的浏览器和客户端设备均支持使用查询字符串传递参数值。
3. 实现简单:在服务端直接访问Request.QueryString[]可读取数据。
1. 不需要任何服务器资源:查询字符串的数据包含在每个URL中。
2. 广泛的支持:几乎所有的浏览器和客户端设备均支持使用查询字符串传递参数值。
3. 实现简单:在服务端直接访问Request.QueryString[]可读取数据。
4. 页面传值简单:<a href="url">或者 Response.Redirect(url) 都可以实现。
缺点:
1. 有长度限制。
2. 用户可见,不能保存敏感数据。
1. 有长度限制。
2. 用户可见,不能保存敏感数据。
回到顶部
Cookie
由于HTTP协议是无状态的,对于一个浏览器发出的多次请求,WEB服务器无法区分它们是不是来源于同一个浏览器。所以,需要额外的数据用于维护会话。 Cookie 正是这样的一段随HTTP请求一起被传递的额外数据。 Cookie 是一小段文本信息,它的工作方式就是伴随着用户请求和页面在 Web 服务器和浏览器之间传递。Cookie 包含每次用户访问站点时 Web 应用程序都可以读取的信息。
与hidden-input, QueryString相比,Cookie有更多的属性,许多浏览器可以直接查看这些信息:
由于Cookie拥有这些属性,因此在客户端状态管理中可以实现更多的功能,尤其是在实现客户端会话方面具有不可替代的作用。
关于Cookie的更多讲解,请参考我的另一篇博客:细说Cookie
优点:
1. 可配置到期规则:Cookie可以在客户端长期存在,也可以在浏览器关闭时清除。session和application的区别
2. 不需要任何服务器资源:Cookie 存储在客户端。
3. 简单性:Cookie 是一种基于文本的轻量结构,包含简单的键值对。
4. 数据持久性:与其它的客户端状态数据相比,Cookie可以实现长久保存。
5. 良好的扩展性:Cookie的读写要经过ASP.NET管线,拥有无限的扩展性。
1. 可配置到期规则:Cookie可以在客户端长期存在,也可以在浏览器关闭时清除。session和application的区别
2. 不需要任何服务器资源:Cookie 存储在客户端。
3. 简单性:Cookie 是一种基于文本的轻量结构,包含简单的键值对。
4. 数据持久性:与其它的客户端状态数据相比,Cookie可以实现长久保存。
5. 良好的扩展性:Cookie的读写要经过ASP.NET管线,拥有无限的扩展性。
这里我要解释一下Cookie 【良好的扩展性】是个什么概念,比如:
1. 我可以实现把Cookie保存到数据库中而不需要修改现有的项目代码。
2. 把SessionId这样由ASP.NET产生的临时Cookie让它变成持久保存。
1. 我可以实现把Cookie保存到数据库中而不需要修改现有的项目代码。
2. 把SessionId这样由ASP.NET产生的临时Cookie让它变成持久保存。
缺点:
1. 大小受到限制。
2. 增加请求头长度。
3. 用户可见,保存敏感数据时需要加密。
1. 大小受到限制。
2. 增加请求头长度。
3. 用户可见,保存敏感数据时需要加密。
回到顶部
ApplicationState
应用程序状态是指采用HttpApplicationState实现的状态维持方式,使用代码如下:
Application.Lock();
Application["PageRequestCount"] = ((int)Application["PageRequestCount"]) + 1;
Application.UnLock();
对于这种方法,我不建议使用,因为:
1. 与使用静态变量差不多,直接使用静态变量可以不需要字典查。
2. 选择强类型的集合或者变量可以避免装箱拆箱。
1. 与使用静态变量差不多,直接使用静态变量可以不需要字典查。
2. 选择强类型的集合或者变量可以避免装箱拆箱。
回到顶部
ViewState,ControlState
视图状态,控件状态,二者是类似,在页面中表现为一个hidden-input元素:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="......................" />
控件状态是ASP.NET 2.0中引入,与视图状态相比,它不允许关闭。
由于它们使用方式一致,而且视图状态是基于控件状态的实现逻辑,所以我就不区分它们了。
由于它们使用方式一致,而且视图状态是基于控件状态的实现逻辑,所以我就不区分它们了。
在ASP.NET的早期,微软为了能帮助广大开发人员提高开发效率,引用入一大批的服务端控件,并为了能将事件编程机制引入ASP.NET中,又发明了ViewState。
这种方式虽然可以简化开发工作量,然而却有一些限制和缺点:
1. 视图状态的数据只能用于回发(postback)。
2. 视图状态的【滥用】容易导致生成的HTML较大,这会引起一个恶性循环:
a. 过大的ViewState在序列化过程中会消耗较多的服务器CPU资源,
b. 过大的ViewState最终生成的HTML输出也会很大,它会浪费服务端网络资源,
c. 过大的ViewState输出导致表单在下次提交时,会占用客户端网络资源。
d. 过大的ViewState数据上传到服务端后,反序列化又会消耗较多的服务器CPU资源。
1. 视图状态的数据只能用于回发(postback)。
2. 视图状态的【滥用】容易导致生成的HTML较大,这会引起一个恶性循环:
a. 过大的ViewState在序列化过程中会消耗较多的服务器CPU资源,
b. 过大的ViewState最终生成的HTML输出也会很大,它会浪费服务端网络资源,
c. 过大的ViewState输出导致表单在下次提交时,会占用客户端网络资源。
d. 过大的ViewState数据上传到服务端后,反序列化又会消耗较多的服务器CPU资源。
因此,整个交互过程中,用户一直在等待,用户体验极差。
在ASP.NET兴起的年代,ViewState绝对是个了不起的发明。
然而,现在很多关于ASP.NET性能优化的方法中,都会将【关闭ViewState】放在头条位置。
为什么会这样呢,大家可以自己思考一下了。
然而,现在很多关于ASP.NET性能优化的方法中,都会将【关闭ViewState】放在头条位置。
为什么会这样呢,大家可以自己思考一下了。
有些人认为:我现在做的程序只是在局域网内使用,使用ViewState完全没有问题!
然而,那些人或许没有想过:
1. 未来用户可能会把它部署在互联网上运行(对于产品来说就是遇到大客户了)。
2. 项目早期的设计与规划,对后期的开发与维护来说,影响是巨大的,因为许多基础部分通常是在早期开发的。
当这二种情况的任何一种发生时,想再禁用ViewState,可能已经晚了。
然而,那些人或许没有想过:
1. 未来用户可能会把它部署在互联网上运行(对于产品来说就是遇到大客户了)。
2. 项目早期的设计与规划,对后期的开发与维护来说,影响是巨大的,因为许多基础部分通常是在早期开发的。
当这二种情况的任何一种发生时,想再禁用ViewState,可能已经晚了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论