页面状态保持机制(编辑中)

Web应用程序中,有很多状态需要在页面的反复回调中能够保持住,还有一些状态需要在页面之间保持。对于状态的保持,是一个值得研究的问题。状态处理不当是页面失效或错误的一个重要的原因。

对于ASPX页面来说,控件可以通过VIEWSTATE来保持状态。VIEWSTATE机制非常好用,有时甚至可以用来保存页面后台代码中属性变量的状态值:因为变量的状态在回调时是不保存的,但是控件的状态却可以保持,因此可以通过控件来保持变量的状态,把控件设置为隐藏状态就不影响页面显示了。

但是VIEWSTATE却不能包打天下,我们的很多页面处理,都是以URL调用的方式进行的,如分页浏览,每次通过分页器进行的跳转都是新开页面,无法使用VIEWSTATE。

分页处理中,使用了URL参数来传递状态,这种传递方式简单明了,但也存在问题:

1、复杂。需要在URL中把各种状态全部写进去,一个都不能少。参数数量众多,考虑不周往往容易遗漏,还不好找原因。

2、和其他方式之间的协调问题。因为页面本身可能有回调操作,比如查询,或者其他的需要回调页面的控件操作,URL参数和回调参数之间的协调必须要精确的处理好。

特别是第二点,在分页浏览中体现得非常明显:既要能在不指定查询条件的情况下浏览所有数据,又要能够支持在回调事件中处理查询操作,还要能够把查询条件传递给新的分页器。要实现这一要求,只能借助复杂的处理逻辑来实现了。

这种需要在URL中传递所有参数的方式,在构造分页器链接的时候需要把页面所需的参数都显式地进行传递。当页面还有其他参数,特别是和分页无关的参数的时候,就会很难控制。构造分页器时,要去解析和分页无关的参数,要进行参数集合重复性的判断以及决定究竟哪个参数有效等。这些操作对于分页处理程序而言,既不合理也是隐患多多的。

基于页面的参数保持机制

参数传递的种种不便之处,使人不禁想到,为什么非要使用URL呢?URL方式,适合传递一些变化的参数。而上述的问题,都是由于一些需要保持的参数的传递而引起的。对于参数的保持,还有更加合适的手段:如Session或者Cookie。

那么,究竟选择Cookie还是Session呢?Session是一个进程级别的状态保存机制,在整个浏览过程中,在打开的所有页面之间,Session保存的数据都会有效。但Session也存在不足:

1、Session存放在服务器端,占用服务器的资源;

2、多个页面公用Session变量,容易导致混乱,如果每个页面都分别创建Session变量,则又造成资源的浪费;

3、Session本身有失效周期,在一些需要长期打开工作的页面,带来页面失效问题。

而Cookie相对来说,正好没有Session的不足。首先,Cookie不占用服务器资源,其次,Cookie按键-值的方式存储,正好可以用每个页面的名称为key,存储每个页面的状态。

根据各种应用的需要,基于页面的状态保持机制应该达到如下的要求:

1、页面回调时保持状态

2、页面跳转时保持状态

3、以Cookie方式存储数据

4、通过索引器的方式访问

5、兼容各种状态机制,自动尝试从URL、Session、Cookie中获取需要的参数值

6、只要使用过的参数,自动保持到Cookie中

页面状态保存机制的实现

/// <summary>
/// WebPage 的摘要说明
///    用于网页的参数的缓存,可以将多种类型的参数缓存起来:以Url中的参数权限最高。URL中的参数会自动保存在Cookie(以网页名称命名)中,每次可以自动加载Cookie。
///    非缓存参数,可以用Querystring来访问。
/// </summary>
public class WebPara
{
	Page page;  //所在的网页
	private Dictionary<string, string> Paras = new Dictionary<string, string>();
	string strPage;
	/// <summary>
	/// 构造函数
	/// </summary>
	public WebPara()
	{
		page = (Page)HttpContext.Current.Handler;
		init();
	}
	/// <summary>
	/// 构造
	/// </summary>
	/// <param name="WebPage"></param>
	public WebPara(Page WebPage)
	{
		page = WebPage;
		init();
	}

	void init()  //初始化
	{
		strPage = System.Text.RegularExpressions.Regex.Match(page.Request.FilePath, "(?<=/)[^/]*Aspx", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Value.ToLower();  //页面统一为小写,cookie区分大小写

		//从cookie中加载所有的参数
		HttpCookie ParaCookie = page.Request.Cookies[strPage];  //以页面命名的Cookie
		if (ParaCookie != null)
		{
			for (int i = 0; i < ParaCookie.Values.AllKeys.Length; i++)
			{
				string parakey = ParaCookie.Values.AllKeys[i];
				Paras.Add(parakey.ToLower(),HttpUtility.UrlDecode(ParaCookie[parakey]));
			}
		}

		//从URL中覆盖加载参数
		for (int i = 0; i < page.Request.QueryString.Count; i++)
		{
			if (Paras.ContainsKey(page.Request.QueryString.GetKey(i).ToLower()))   //变量统一用小写
			{
				Paras[page.Request.QueryString.GetKey(i).ToLower()] = page.Request.QueryString[i];
			}
			else
				Paras.Add(page.Request.QueryString.GetKey(i).ToLower(), page.Request.QueryString[i]);
		}

		//回写所有参数到Cookie中
		foreach (KeyValuePair<string, string> kvp in Paras)
		{
			page.Response.Cookies[strPage][kvp.Key] = HttpUtility.UrlEncode(kvp.Value);
			page.Response.Cookies[strPage].Expires = DateTime.Now.AddDays(30);
		}
		//page.Response.Cookies[strPage].Expires = DateTime.Now.AddDays(1);  //保存一天
	}
	/// <summary>
	/// 参数索引。写入时,如果参数已经存在,则覆盖,否则创建
	/// </summary>
	/// <param name="ParaName"></param>
	/// <returns></returns>
	public string this[string ParaName]
	{   
		get
		{
			if (Paras.ContainsKey(ParaName.ToLower()))
			{
				return Paras[ParaName.ToLower()];
			}
			return "";
		}
		set  //有则覆盖,没有就添加
		{
			if (Paras.ContainsKey(ParaName.ToLower()))
			{
				Paras[ParaName.ToLower()] = value;
			}
			else
				Paras.Add(ParaName.ToLower(), value);

			//回写
			page.Response.Cookies[strPage][ParaName.ToLower()] = HttpUtility.UrlEncode(value);
			page.Response.Cookies[strPage].Expires = DateTime.Now.AddDays(30);

			//page.Response.Cookies[strPage][ParaName.ToLower()] = value;
		}
	}

	/// <summary>
	/// querystring中的变量,不存在则返回空
	/// </summary>
	/// <param name="ParaName"></param>
	/// <returns></returns>
	public string QueryString(string ParaName)
	{
		return StringUtil.ToStr(page.Request.QueryString[ParaName]);
	}
	/// <summary>
	/// 所有参数的信息
	/// </summary>
	/// <returns></returns>
	public string AllInfo()
	{
		string ret="";
		foreach (KeyValuePair<string, string> kvp in Paras)
		{
			ret += kvp.Key + ":" + kvp.Value + "\r\n";
		}
		return ret;
	}

}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏分布式系统和大数据处理

Asp.Net 用户验证(自定义IPrincipal和IIdentity)

前一段时间有两个朋友问我,为什么在HttpModule中无法获得到Session值,因为他们希望自定义一个HttpModule,然后在其中获取Session来进...

1973
来自专栏菩提树下的杨过

Asp.Net4.0/VS2010新变化(3):webform中也可以直接url路由

以前在做asp的时候,要把 /default.asp?id=123映射成/default/123,需要借助IISRewriter这个组件,到了asp.net以后...

19510
来自专栏hbbliyong

WCF浅尝

1.首先先建立一个WCF服务应用程序 ? 2.再建立一个宿主程序,这里用控制台,添加服务引用,这里会报错: ? 点击页面确定,回到添加服务页面 ? 点击箭头有如...

35810
来自专栏我的博客

安卓上传文件(绝对可以用)

说明:使用是httpclient+MultipartEntity,因此需要导入包:httpmime-4.1.1(这个包非常重要!务必导入!) 写在前面:我只是贴...

3775
来自专栏码农阿宇

.Net Core从命令行读取配置文件

最近在学习博客园腾飞(jesse)的.Net Core视频教程,收益匪浅,在此作推荐 : http://video.jessetalk.cn/ 言归正传,.Ne...

3004
来自专栏雪胖纸的玩蛇日常

python3+django2 开发易语言网络验证(中)

3457
来自专栏技术博客

Asp.Net MVC3.0网站统计登录认证的在线人数

  对于一个网站来说,统计在线人数是一个很重要的工作。平时也发现很多的网站论坛等都有在线人数的显示。对于一个网站如果在线人数很多,用户看到了这么个数字也是很了不...

1212
来自专栏分布式系统和大数据处理

HttpModule介绍

Http 请求处理流程 和 Http Handler 介绍 这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我们知道Http请求最终会由实现了...

713
来自专栏JadePeng的技术博客

asp.net MVC 权限设计

几点说明:     1、该权限系统是个网站用的,用户简单,因此不涉及到部门这些信息     2、基于将角色与controller、action相关联来判断...

4889
来自专栏更流畅、简洁的软件开发方式

【自然框架】QuickPager分页控件,新增一种分页方式——伪URL分页(Postback版)

适用场景   先说一下伪URL分页的适用场景。在网站的网页里实现查询功能,如果查询条件比较少的话,还比较好办,把查询条件放到URL里面传递即可。但是如果查...

2376

扫码关注云+社区