ASP.NET网站开发技术ASP.NET网站开发技术第五章学习情境:使用ASP.NET状态管理实现购物车5.1学习情境引入5.2基础知识:ASP.NET的状态管理5.3基本知识2:跨页面数据传递5.4决策与计划5.5实施5.6检查与评价5.7训练ASP.NET网站开发技术5.1学习情境引入5.1.1网上书店的购物车功能需求和主要问题5.1.2网上书店购物车功能展示5.1.3网上书店购物车技术分解ASP.NET网站开发技术5.1.1网上书店的购物车功能需求和主要问题1功能需求网上书店需要购物车功能,先购书,然后下订单,由于下订单需要数据库操作,本章只介绍购书部分网上书店系统::会员网上书店系统搜索图书查看某图书详细信息购买该图书查看、管理购物车信息********图5-1会员购书行为的详细描述会员的购书行为如图5-1,结合前面网上书店系统的展示,购书过程描述为:会员在主页搜索到了某些图书;通过主页书名超链接到该图书的详细信息页面,填入购买数量,将其加入购物车;在购物车页面中浏览刚才的购物车数据(也可以删除购物车数据)。ASP.NET网站开发技术5.1.1网上书店的购物车功能需求和主要问题1.主要问题(1)问题描述记录多次购书数据:每个用户可以连续重复上述的购书过程,以购买不同的图书,而在个人购物车中,可以看到每次购买得到的图书数据。也就是图书详细信息页面能够记录每次的购书数据。记录多用户购书数据:一个网站可能多个用户同时访问,每个用户都将在个人购物车中看到自己的购物数据。也就是图书详细信息页面在记录购书数据时能够区分用户。跨页传递购书数据:购物车页面能够获得图书详细信息页面的购物数据,用来浏览和管理。即可以在两个页面请求之间记住购物车信息。问题分析以我们桌面程序设计的经验来看,这根本不应成为问题,只需要加一些变量,每次用户单击时记录一些值就可以实现。但在网站程序中却成为了问题,因为HTTP协议是没有“记忆”的,它本身不会记住是哪个用户曾经访问过哪个网页,对于“无记忆”的HTTP协议而言,某个用户第一次访问页面BookDetails.aspx和第二次访问页面BookDetails.aspx之间没有什么联系,它不知道这是两次不同的购书。同样,也不知道是否不同的用户来访问。让我们看例5-1。ASP.NET网站开发技术5.1.1网上书店的购物车功能需求和主要问题例5-1设置页面字段变量,无法实现计数的反面例子。在一个新的Web窗体页中,添加一个Button,修改其Text为“提交”,并编写如下的后台代码:);publicpartialclass_Default:System.Web.UI.Page{intrequestTimes=0;protectedvoidPage_Load(objectsender,EventArgse){requestTimes=requestTimes+1;Response.Write(requestTimes}}在浏览器中查看本页面,多次点击“提交”按钮,查看网页显示的数值。结果与分析:由于HTTP协议没有“记忆”,默认情况下,ASP.NET每次收到请求都会重新实例化对应的页面类,造成requestTimes变量的值每次都初始化为0,因此该页面总是显示1。为什么ASP.NET要每次都重新实例化对应的页面类?这是因为我们设计的是动态网页,可能有许多用户同时访问我们的网站,即使单个用户也可能多次和网页交互,这些用户即使都访问页面BookDetails.aspx,也可能看到不同的页面BookDetails.aspx:比如用户甲在浏览图书1的详细信息,用户乙则在浏览图书2的详细信息等等。所以不能事先实例化好页面BookDetails类,等待用户来请求,那会导致给他们响应有同样数据的页面实例。而只能是收到一个请求,就根据用户请求实例化所请求的页面,如果不加处理,每次请求所得的页面实例成员都是初始状态,字段变量值总是初始值。看来,要避免这种“狗熊掰棒子”的结果,必须让HTTP协议变得有“记忆”。要让HTTP协议变得有“记忆”,实际上是一个保持状态的问题,也就是服务器在收到请求时,要能够得到上次请求的状态(包括网页的数据和客户端的标识等)。ASP.NET中有丰富的状态保持方法,适用于各种场合。保持了状态,就可以解决前面提到的问题了。ASP.NET网站开发技术5.1.2网上书店购物车功能展示从教材网站下载BookStoreWebSite源码,在本机调试运行。从首页以“test”用户名登录,单击某书名链接,则会打开图书详细信息页面,如图5-1所示,输入购买数量,单击“购买”按钮。重复此过程若干次,以建立多条购书数据。单击页面上部“购物车”链接查看购物车,如图5-2。重新打开一个IE程序窗口(不能是选项卡),以另一个用户名“ee”登录,按照前述过程,购买不同的若干图书。再查看其购物车,如图5-3,比较两图可知,“ee”用户、“test”用户能够分别保存每次的购物数据。ASP.NET网站开发技术5.1.3网上书店购物车技术分解1.技术分解开发实现购物车的技术方案并不唯一,但总是要既保持购物车数据状态,并进行跨页传递,所以,ASP.NET中有以下两部分相关技术:(1).ASP.NET的状态管理ASP.NET采用多种技术来保持页面级别的状态,以及其他级别的状态,使得动态网站的开发变得简单而灵活,这是ASP.NET的核心技术。对于程序员,使用ASP.NET提供的状态,是很容易的,但要灵活运用它们,就需要了解aspx页面的生命周期,熟悉了页面生命周期后,ASP.NET网站开发中的许多问题就可以迎刃而解,这也是我们把状态管理作为ASP.NET的核心技术的理由之一。ASP.NET网站开发技术图5-2图书详细信息页面ASP.NET网站开发技术图5-3“test”用户的购物车ASP.NET网站开发技术图5-4“ee”用户的购物车ASP.NET网站开发技术(2).ASP.NET跨页面数据传递技术在页面之间传递数据的技术也很多,有的完全是传统的HTTP协议所支持的,有的只在ASP.NET的支持下才能使用,这也是与页面生命周期有关的常用技术。2.学习安排学习ASP.NET状态管理、跨页数据传递的相关知识后,实现购物车功能,并进行检查和评价,是本章的主要内容。页面生命周期知识部分,理解起来有一定的难度,对初学者列为选学内容。但要成为一个熟练的ASP.NET开发者,页面生命周期是必须掌握的内容,建议初学者在实施中遇到问题后,反复查阅此部分内容,以将其逐步掌握。ASP.NET网站开发技术5.2基本知识1:ASP.NET的状态管理5.2.1视图状态5.2.2应用程序状态5.2.3会话状态5.2.4Cookie状态(选学)5.2.5自测5.2.6演练ASP.NET网站开发技术5.2.1视图状态视图状态(ViewState),是使HTTP协议变得“有记忆”的关键技术,深入了解了视图状态,就能理解ASP.NET基于事件编程的许多重要工作原理。在每次请求发生(包括原始请求)后,视图状态数据由ASP.NET在服务器端生成,默认情况下,存放在页面中的“_VIEWSTATE”隐藏域中,该隐藏域数据和页面的其他数据一起,随HTTP响应数据发送给客户端浏览器,隐藏域数据对用户不可见,也就不会因用户的正常操作而改变,当用户再次请求本网页时,随HTTP请求的Post数据一起,再发回服务器端,由ASP.NET处理。视图状态的这个处理过程,是由ASP.NET自动完成的。默认情况下,所保存的数据也是自动筛选的,这些数据涉及Web窗体内几乎所有服务器控件,HTML控件不被保存。除了自动筛选的视图状态数据,ASP.NET也提供给程序员将自定义数据(ViewState变量)保存在视图状态中的功能。视图状态只能在本网页与服务器的往返中保持,而不能在不同网页之间传递,这是和其它状态所不同的地方。关于视图状态,要学会ViewState变量使用的基本技能,要在理解视图状态和页面生命周期事件的关系的基础上,掌握何时可以禁用自动的视图状态。ASP.NET网站开发技术1.视图状态隐藏域隐藏域并不是ASP.NET的新技术,而属于传统的HTML技术,是客户端页面代码中的一个inputtype=”hidden”标记,浏览器并不将其呈现给用户,所以称为隐藏域。ASP.NET中用于存放视图状态数据的隐藏域是自动生成、经过编码的HTML标记,程序员和用户都不参与该区域的数据读写,在网页回发时,隐藏域数据随着HTTP请求发回服务器,由ASP.NET处理。例5-2展示了视图状态隐藏域,例5-3展示了视图状态隐藏域数据随着HTTP请求回发的情况。ASP.NET还提供了HiddenField服务器控件,也会生成客户端隐藏域标记,程序员可以用HiddenField控件保存自定义信息,在网页回发时,程序员还可以通过读取该控件的值,从而取得HTTP协议的“记忆”。例5-4利用HiddenField控件“记忆”对本页的请求次数。另外,由于HiddenField控件也可以在浏览器中被客户端程序访问,因此可以用来充当服务器端和客户端的中间变量,在服务器C#程序和客户端Javascript程序之间交换数据。ASP.NET网站开发技术例5-2查看ASP.NET的视图状态隐藏域。在网站项目解决方案管理器中,右击网站根结点,选择“添加新项”,添加一个“Web窗体”,按F5调试运行项目,在IE8浏览器中,选择“页面”按钮下的“查看源文件”,可以看到如下页面HTML原始源代码:inputtype=hiddenname=__VIEWSTATEid=__VIEWSTATEvalue=/wEPDwUJNzgzNDMwNTMzZGTe0eesNzYuihpAHggRVfxGxli7QQ==/分析:本例在服务器端只包含一个“空”页面,但ASP.NET生成的客户端网页代码中,自动产生了视图状态数据的隐藏域,value属性中的值是经过编码的,保存了本页面中ASP.NET认为需要“记忆”的数据。ASP.NET网站开发技术例5-3查看视图状态隐藏域数据随着HTTP请求回发。在例5-2中的Web窗体页上,放上一个Button控件,修改其ID为“ButtonSubmit”,Text为“提交”,编写其Click事件委托函数如下:protectedvoidButtonSubmit_Click(objectsender,EventArgse){Request.SaveAs(c:\\request.txt,true);}在浏览器中查看本页面,按照例5-2中的方法在浏览器中查看源文件,可看到自动生成的视图状态隐藏域标记:inputtype=hiddenname=__VIEWSTATEid=__VIEWSTATEvalue=/wEPDwUKMTQ2OTkzNDMyMWRkmN60Y81Lx0LZIGBNhhmeMMu7oco=/再点击页面的“提交”按钮,然后打开C盘的request.txt文件,可以看到视图状态数据也被回发,相关数据如下:__VIEWSTATE=%2FwEPDwUKMTQ2OTkzNDMyMWRkmN60Y81Lx0LZIGBNhhmeMMu7oco%3D分析:比较例5-2和例5-3中的input标记,可以看到它们value属性不同,这是因为例5-3中的Web窗体页多了一个Button按钮,所以视图状态数据不同。“提交”按钮的Click事件委托函数,用Request对象的SaveAs方法,实现了将HTTP请求数据保存在C盘的request.txt文件中的功能。比较例5-3中源文件中的和回发请求中的视图状态数据,可以发现在回发请求中,分别用“%2F”、“%3D”代替了源数据中的“/”和“=”字符,这是HTTP协议所规定的,除此之外,回发前后的视图状态数据并未发生变化。ASP.NET网站开发技术例5-4利用ASP.NET的HiddenField控件,使HTTP协议“