第5章 ASP.NET常用对象和状态管理
ASP.NET中内置了大量用于获得服务器或客户端信息、进行状态管理、实现页面跳转、实现跨页传递数据的对象。这些对象由.NET Framework中封装好的类来实现,并且由于这些内置对象是全局的,它们在ASP.NET页面初始化请求时自动创建,可在应用程序的任何地方直接调用,而无须对所属类进行实例化操作。
5.1 Page对象
Page对象是由System.Web.UI命名空间中的Page类来实现的。Page类与ASP.NET网页文件(.aspx)相关联,这些文件在运行时被编译成Page对象,并缓存在服务器中。
5.1.1 Page对象的常用属性、方法和事件
1.Page对象的属性
Page对象提供的常用属性如表5-1所示。
表5-1 Page对象的常用属性
在访问Page对象的属性时可以使用this关键字。例如,Page.IsValid可以写成this.IsValid。在C#中this关键字表示当前在其中执行代码的类的特定实例。
Page对象的IsPostBack属性是最常用的属性之一,用于获取一个逻辑值,该值指示当前页面是否正为响应客户端回发而加载,或者它是否正在被首次加载和访问。其值为true,表示页面是为响应客户端回发而加载;其值为false,则表示页面是首次加载。
例如,下列代码用于在窗体装入时向下拉列表框DropDownList1中添加3个选项。首次打开页面时可以看到程序得到了正确的执行,如图5-1所示。但当页面由于用户的其他操作(如单击按钮等)引起回发时,DropDownList1中就会错误地出现重复选项,如图5-2所示。
图5-1 页面初次加载时
图5-2 页面回发刷新后
这是因为服务器回发引起的页面刷新同样会触发Pag_Load事件,导致向下拉列表框添加选项的3条语句被再次执行,而且是每回发一次,就会多出一组重复的选项。通过对Page对象的IsPostBack属性的判断,可以有效地解决这一问题。
将Page_Load事件代码改为以下所示,使程序只在Page对象的IsPostBack属性为false时(页面初次加载时)才执行向DropDownList1中添加供选项,当IsPostBack为true(服务器回发)时,不添加选项。
2.Page对象的常用方法和事件
Page对象的常用方法如表5-2所示。
表5-2 Page对象的常用方法
Page对象的常用事件如表5-3所示。
表5-3 Page对象的常用事件
Page对象的Init事件与Load事件主要有以下两点区别。
1)Page对象的Init事件和Load事件都发生在页面加载的过程中。Init事件发生在Load事件之前,也就是页面初始化之前。Init事件中的代码通常用于进行一些客户端检测、控件初始属性设置等操作。
2)在Page对象的生存周期中,Init事件只有在页面初始化时被触发一次,而Load事件在初次加载及每次回发中都会被触发。所以,如果希望初始化页面时的事件处理代码只在页面首次加载时被执行,则可将代码放在Init事件中。
5.1.2 Web窗体页面的生命周期
Web窗体页的生命周期代表着Web窗体页从生成到消亡所经历的各阶段,以及在各阶段执行的方法、使用的消息、保持的数据和呈现的状态等。掌握这些知识,会对理解和分析程序设计中出现的问题十分有利。Web页面的生命周期及各阶段执行的内容如下。
1)初始化:该阶段将触发Page对象的Init事件,并执行OnInit方法。该阶段在Web窗体的生存周期内仅此一次。
2)加载视图状态:该阶段主要执行LoadViewState方法,也就是从ViewState属性中获取上一次的状态,并依照页面的控件树结构,用递归来遍历整个控件树,将对应的状态恢复到每个控件上。
3)处理回发数据:该阶段主要执行LoadPostData方法,用来检查客户端发回的控件数据的状态是否发生了变化。
4)加载:该阶段将触发Load事件,并执行Page_Load方法。该阶段在Web窗体的生命周期内可能多次出现(每次回发都将触发Load事件)。
5)预呈现:该阶段要处理在最终呈现之前所做的各种状态更改。在呈现一个控件之前,必须根据它的属性来产生页面中包含的各种HTML标记。例如,根据Style属性设置HTML页面的外观。在预呈现之前可以更改一个控件的Style属性,当执行预呈现时就可以将Style值保存下来,作为呈现阶段显示HTML页面的样式信息。
6)保存状态:该阶段的任务是将当前状态写入ViewState属性。
7)呈现:该阶段将对应的HTML代码写入最终响应的流中。
8)处置:该阶段将执行Dispose方法,释放占用的系统资源(如变量占用的内存空间、数据库连接)等。
9)卸载:这是Web窗体生命周期的最后一个阶段,在这个阶段中将触发UnLoad事件,执行OnUnLoad方法,以处理Web窗体在消亡前的最后处理。在实际应用中,页面占用资源的释放一般都放在Dispose方法中完成,所以OnUnLoad方法也就变得不那么重要了。
5.2 Response对象
Response对象是从System.web命名空间中的HttpResponse类中派生出来的。当用户访问应用程序时,系统会根据用户的请求信息创建一个Response对象,该对象用于回应客户浏览器,告诉浏览器回应内容的报头、服务器端的状态信息,以及输出指定的内容等。
5.2.1 Response对象的常用属性和方法
Response对象常用的属性如表5-4所示。
表5-4 Response对象的常用属性
Response对象的常用方法如表5-5所示。
表5-5 Response对象的常用方法
5.2.2 使用Response对象输出信息到客户端
在编写ASP.NET应用程序代码时经常会用到Response对象,其中最常用的应用之一就是使用Response对象的Write方法或WriteFile方法,将信息写入HTML流,并显示到客户端浏览器。
1.使用Write方法
Write方法的语法格式如下。
Response.Write(string);
其中,参数string表示希望输出到HTML流的字符串,string不但可以是字符串常量或变量,也可以包含用于修饰输出信息的HTML标记或脚本。如果希望在字符串常量中包含英文双引号("),则应使用C#转义符“\"”。
下列代码演示了Response.Write方法的使用示例。
2.使用WriteFile方法
使用Response对象的WriteFile方法可以将指定的文件内容直接写入HTML输出流。其语法格式如下。
Response.WriteFile(filename);
其中,filename参数用于说明文件的名称及路径。
在使用WriteFile方法将文件写入HTML流之前,应使用Response对象的ContentType属性说明文件的类型或标准MIME类型。该属性值是一个字符串,通常用以下格式表示。
类型/子类型
常用的类型及子类型包括text/html(默认值)、image/gif、image/jpeg、appliction/msword、appliction/vnd.ms-excel和appliction/vnd.ms-powerpoint等。
例如,希望将一个保存在服务器端根站点下的文本文件1.txt的内容输出到客户端浏览器中,可使用以下代码。
Response.ContentType="text/html";
Response.ContentEncoding=System.Text.Encoding.GetEncoding("GB2312");
Response.WriteFile("1.txt");
说明:代码中使用Response对象的ContentEncoding属性指定了以GB2312为输出内容的编码方案。若没有这一句,输出时可能会在浏览器中出现乱码。
此外,WriteFile方法常被用于提供文件下载的应用中。例如,下列代码表示当用户单击页面中的按钮控件时弹出“文件下载”对话框,允许用户打开或保存站点根目录下的“1.doc”文件。
说明:代码中使用Page对象的MapPath方法指定了输出文件在服务器端的物理路径。从该语句可以看出,希望写入HTML流的文件不一定非要保存在本站点或其他任何站点内,这一点与HTML静态网页中的超链接有很大的不同。此外,使用WriteFile方法提供文件下载可以有效地避免多线程下载工具的使用,从而减轻因大量下载给服务器带来的压力。
5.2.3 使用Redirect方法实现页面跳转
Response对象的Redirect方法用于将客户端重定向到新的URL,实现页面间的跳转。该方法的语法格式如下。
Response.Redirect(url[,endResponse])
其中,字符串参数url表示新的目标URL地址,可选布尔参数endResponse表示是否终止当前页的执行。
例如,下列语句将使用客户端浏览器重定向到“百度”搜索引擎的主页。
Response.Redirect("http://www.baidu.com")
该方法常被用来根据某条件将用户引向不同页面的情况。例如,如果用户正确回答了口令,则可看到诸如视频点播、软件下载和资料阅读等页面,否则将被跳转到另一页面,看到拒绝进入的说明信息。
使用Response对象的Redirect方法时应注意以下几个问题。
1)使用该方法实现跳转时,浏览器地址栏中将显示目标URL。
2)执行该方法时,重定向操作发生在客户端,涉及两个不同页面或两个Web服务器之间的通信,第一阶段是对原页面的请求,第二阶段是对目标URL的请求。
3)执行该方法后,内部控件保存的所有信息都将丢失,因此当从A页面跳转到B页面后,在页面B中将无法访问A页面提交的数据。若需从A页面传递数据到B页面,只能通过url参数中的“?”来实现。举例如下。
string MyName=UserName.Text; //将文本框中的文本存入变量
//将变量值以Name为形参变量(也称为“查询字符串”)传送给目标页面welcome.aspx
Response.Redirect("welcome.aspx?Name="+MyName);
目标页面被打开后,可以使用Request对象的QueryString属性读取上一页传递来的数据。有关Request对象及QueryString属性的相关知识将在后面进行详细介绍。
5.3 Request对象
Request对象是ASP.NET中常用的对象之一,主要用于获得客户端浏览器的信息,例如使用Request对象的UserHostAddress属性可以得到用户的IP地址;使用QueryString属性可以接收用户通过URL地址中“?”传递给服务器的数据;使用Browser属性集合中的成员可以读取客户端浏览器的各种信息(例如,用户使用的浏览器名称及版本、客户机使用的操作系统、是否支持HTML框架,以及是否支持Cookie等);使用Form属性可以处理HTML表单。
5.3.1 Request对象的常用属性和方法
Request对象是ASP.NET中的常用对象之一,它与Response对象配合可以实现客户端与服务器端的数据交换。Request对象可以接收客户端通过HTML表单或查询字符串传递过来的数据,也可用于获取客户端其他环境变量(如浏览器版本、客户端IP及是否支持VB-Script及是否支持Cookie等)。总而言之,所有从前端浏览器通过HTML协议送往服务器端的数据,都需要借助Request对象来接收。
1.Request对象的常用属性
Request对象的常用属性如表5-6所示。
表5-6 Request对象的常用属性
2.Request对象的常用方法
Request对象的常用方法有以下两个。
1)MapPath(VirtualPath):该方法将当前请求的URL中的虚拟路径VirtualPath映射到服务器上的物理路径。参数VirtualPath用于指定当前请求的虚拟路径(可以是绝对路径,也可以是相对路径)。返回值为与VirtualPath对应的服务器端物理路径。
2)SaveAs(filename,includeHeaders):该方法将客户端的HTTP请求保存到磁盘。参数filename用于指定文件在服务器上保存的位置;布尔型参数includeHearders用于指示是否同时保存HTTP头。
例如,下列代码将用户请求页面的服务器端物理路径显示到页面中,将用户的HTTP请求信息(包括HTTP头数据)保存到服务器磁盘中。
//在页面中显示请求文件在服务器中的物理路径
Response.Write(Request.MapPath("default.aspx"));
//将用户的HTTP请求保存到abc.txt文件中
Request.SaveAs("d:\\abc.txt",true);//在C#中“\”表示转义符,所以在表示路径时应使用“\\”
3.通过查询字符串实现跨页数据传递
Request对象的QueryString属性用于接收来自用户请求URL地址中“?”后面的数据,通常将这些数据称为“查询字符串”,也称为“URL附加信息”,常被用来在不同网页中传递数据。
使用Response对象的Redirect属性可以同时传递多个参数,其语法格式如下。
Response.Redirect("目标网页?要传递的参数1&要传递的参数2&…&要传递的参数n");
举例如下。
string Var1="zhangsan";
string Var2="zhangsan@163.com";
Response.Redirect("result.aspx?Var="+Var1); //传递一个参数
或
Response.Redirect("result.aspx?VarA="+var1+"&VarB="+var2); //传递2个参数
上述语句等效于下列代码。
Response.Redirect("result.aspx?VarA=zhangsan&VarB=zhangsan@163.com");
在目标网页中使用Request对象的QueryString属性接收参数的语法格式如下。
string接收参数的变量=Request.QueryString["包含参数的变量"];
举例如下。
string My Var=Request.QueryString["VarA"]; //提取参数变量VarA的值赋给变量MyVar
4.使用Browser属性获取客户浏览器信息
Request对象的Browser属性包含众多子属性,用来返回客户端浏览器的信息和客户端操作系统的信息等。例如,下列语句将返回客户端用户使用的操作系统名称。
Response.Write("你使用的操作系统是:"+Request.Browser.Platform);
又如,下列语句将返回客户端浏览器是否支持HTML框架。
Response.Write("是否支持HTML框架:"+Request.Browser.Frames);
由于客户端使用的浏览器种类或设置不同,对各种HTML标记的支持也会有所不同。例如,可能有些浏览器不支持HTML框架、不支持VBScript脚本等,这导致同一页面在不同浏览器中显示出来的外观有所不同,甚至会出现错误。使用Request对象的Browser属性集可以在执行代码前对客户端浏览器的状况进行判断,以便有选择地执行某些代码,使所有客户端都能得到正确的页面效果。
Request对象的Browser属性集的常用成员如表5-7所示。
表5-7 Request对象的Browser属性常用成员
5.3.2 处理HTML表单
HTML表单用于向服务器端提交用户输入的数据,而这些数据在ASP.NET网站中可以使用Request对象的Form属性来获取、分析和处理。其语法格式如下。
Request.Form[元素标识|索引值]
其中,“元素标识”可以是ASP.NET服务器控件ID值或HTML元素的Name属性值。“索引值”为要检索的元素从0开始的索引号。例如索引值为3,则表示第4个元素。
【演练5-1】设计一个用户登录程序。要求用户输入界面Login.html由如图5-3所示的HTML表单构成;表单处理程序为Check.aspx,提交的数据由Request对象的Form属性获取,若用户名为zhangsan并且密码为123456,则跳转到如图5-4所示的Welcome.html页面,否则跳转到如图5-5所示的Error.html页面。
图5-3 HTML表单登录页面
图5-4 Welcome.html页面
图5-5 Error.html页面
程序设计步骤如下。
新建一个ASP.NET空网站,向网站中添加一个名为Check.aspx的Web窗体和3个HT-ML页面Login.html、Welcome.html和Error.html。
Login.html的代码如下。
Check.aspx.cs的代码如下。
Welcome.html和Error.html的代码只需要在<body>…</body>之间输入“欢迎访问本页面”或“用户名或密码错”即可。
从程序运行过程中可以看出,Check.aspx是一个典型的后台页面,不会显示到浏览器中,它的作用就是在后台对用户提交的数据进行处理,并根据处理结果安排页面跳转方向。
5.4 Server对象
Server对象派生自HttpServerUtility类,该对象提供了访问服务器的一些属性和方法,帮助程序判断当前服务器的各种状态。
5.4.1 Server对象的常用属性和方法
Server对象的常用属性有以下两个。
1)MachineName属性:该属性用于获取服务器的计算机名称。
2)ScriptTimeout属性:该属性用于获取或设置请求超时的时间(s)。
Server对象的常用方法如表5-8所示。
表5-8 Server对象的常用方法
5.4.2 Execute、Transfer和MapPath方法
除了前面介绍过的HTML超链接、Response对象的Redirect方法和ASP.NETWeb控件的PostBackUrl属性外,在ASP.NETWeb窗体页面中使用Server对象的Execute方法和Trans-fer方法,也可以实现从当前页面跳转到另一页面,而Server对象的MapPath方法则用于将虚拟路径转换成服务器端的物理路径。
1.Execute和Transfer方法
需要注意的是:Execute方法在新页面中的程序执行完毕后自动返回到原页面,继续执行后续代码;而Transfer方法在执行了跳转后不再返回原页面,后续语句也永远不会被执行,但跳转过程中Request、Session等对象中保存的信息不变,也就是说从A页面使用Transfer方法跳转到B页面后,可以继续使用A页面中提交的数据。
此外,由于Execute方法和Transfer方法都是在服务器端执行的,客户端浏览器并不知道已进行了一次页面跳转,所以其地址栏中的URL仍然是原页面的数据。这一点与Re-sponse对象的Redirect方法实现的页面跳转是不同的。
Execute方法的语法格式如下。
Server.Excute(url[,write]);
其中,参数url表示希望跳转到的页面路径;可选参数write是StringWrite或StreamWrite类型的变量,用于捕获跳转到的页面的输出信息。
Transfer方法的语法格式如下。
Server.Transfer(url[,saveval]);
其中,参数url表示希望跳转到的页面路径;可选参数saveval是一个布尔型参数,用于指定在跳转到目标页面后,是否保存当前页面的QueryString和Form集合中的数据。需要注意的是,写在Transfer方法语句之后的任何语句都将永不被执行。
2.MapPath方法
“虚拟路径”是一种相对路径的表示方法,虚拟路径的起点为站点文件夹。例如,“im-ages/pic.jpg”表示站点根目录下images文件夹中的pic.jpg文件。
在Web应用程序执行时可能需要访问存放在服务器中的某一文件,此时就需要将文件的虚拟路径转换成服务器端对应的物理路径。而Server对象的MapPath方法就是用来完成这一任务的。MapPath方法的语法格式如下。
Server.MapPath(虚拟路径);
例如,设D:\ASP.NET\WebSite1是某站点在服务器上的主目录(物理路径),则下列语句将返回D:\ASP.NET\WebSite1\admin\page1.aspx。
Server.MapPath("admin/page1.aspx");
在描述虚拟路径时,通常使用符号“~/”表示网站的根目录(相对虚拟路径);使用符号“./”表示当前目录(相对虚拟路径),使用符号“../”表示当前目录的上级目录(相对虚拟路径)。可以使用Request对象的FilePath属性返回当前页面的虚拟路径。
5.5 ASP.NET的状态管理
ASP.NET是一种无状态的网页连接机制,服务器处理客户端请求的网页后,与该客户端的连接就中断了。此外,到服务器端的每次往返都将销毁并重新创建网页,因此,如果超出了单个网页的生存周期,网页中的信息将不复存在。也就是说,默认情况下,服务器不会保存客户端再次请求页面和本次请求之间的关系和相关数据。这种无法记忆先前请求的问题,使得程序员在实现某些功能时遇到了困难。例如,经常需要将用户请求本页面时产生的某些变量数据保存下来,并传送给下一网页。在常见的登录页面中这一问题就十分突出,用户首先需要访问登录页面,输入用户名和相应的密码后,登录页面根据保存在数据库中的信息判断用户是否为合法用户,以及判断用户的级别等。这些判断结果全部需要保存下来,以便跳转到下一网页时作为判断用户是否登录成功的依据。
在C/S架构的应用程序中,使用全局变量即可很好地解决问题,而在ASP.NET环境(B/S架构)中则需要使用与状态管理相关的对象来保存用户数据。所谓“状态管理”,是指使用ASP.NET提供的Cookie、Session或PreviousPage对象保存并获取数据,在不同页面间实现数据共享。
5.5.1 创建和使用Cookie对象
Cookie是由服务器发送给客户机,并保存在客户机上的一些记录用户数据的文本文件。当用户访问网站时,Web服务器会发送一小段资料存放在客户机上,它会把用户在网站上所打开的网页内容、在页面中进行的选择或者操作步骤一一记录下来,当用户再次访问同一网站时(可能并不是相同的网页),Web服务器会首先查找客户机上是否存在上次访问网站时留下的Cookie信息,若有,则会根据具体Cookie信息发送特定的网页给用户。
在保存用户信息和维护浏览器状态方面,使用Cookie无疑是一种很好的方法。例如,可以将用户的登录状态(是否已成功登录)存放在Cookie中,这样就可以判断用户近一段时间内是否访问过该网站。某些网站的“10天内免登录”功能,就是通过Cookie实现的。用户访问网站时系统首先检查是否存在成功登录且在有效期内的Cookie信息,若有则绕过登录界面直接跳转到下一页面。
当然,为了保护用户的权益,大多数浏览器对Cookie的大小进行了限制,一般Cookie总量不能超过4096字节。除此之外,一些浏览器还限制了每个网站在客户机上保存的Cookie数量不能超过20个,若超过则最早期的Cookie将被自动删除。
更关键的是,用户可以自行设置自己的计算机是否接受由被访问网站发送来的Cookie数据。当用户关闭了Cookie功能之后,可能导致很多网站的个性化服务就不能使用了,甚至出现打开网页出现错误的现象。
1.创建Cookie
浏览器负责管理客户机上的Cookie,Cookie需要通过Response对象发送到浏览器,发送前需要将其添加到Cookie集合中。
Cookie有3个重要的参数:名称、值和有效期。如果没有设置Cookie的有效期,它仍可被创建,但不会被Response对象发送到客户端,而是将其作为用户会话的一部分进行维护,当用户关闭浏览器(会话结束)时该Cookie将被释放。这种Cookie十分适合用来保存只需要短暂保存或由于安全原因不能保存在客户机上的信息。
创建Cookie的语法格式如下。
Response.Cookies["名称"].Value=值;
例如,下列语句创建了一个名为MyCookie的Cookie并为其赋值OK。
Response.Cookies["MyCookie"].Value="OK";
设置Cookie有效期的语法格式如下。
Response.Cookies["名称"].Expires=到期时间;
例如,下列语句设置名为MyCookie的Cookie有效期为1天。
Response.Cookies["MyCookie"].Expires=DateTime.Now.AddDays(1);
Cookie被创建后保存在“C:\Users\cuimiao\AppData\Local\Microsoft\Windows\INetCook-ies”文件夹中(Windows 10环境)。图5-6所示为某个Cookie文件的内容,其中存放了来自同一服务器localhost的3条Cookie信息。从图中可以看到Cookie是以明文的形式保存的,所以Cookie不适合用来保存敏感数据。
图5-6 Cookie文件的内容
2.读取Cookie
使用Request对象的Cookies属性可以读取保存在客户机上指定Cookie的值,其语法格式如下。
变量=Request.Cookies["名称"].Value;
例如,下列语句可将名为MyCookie的Cookie值读出,并赋给变量GetCookie。
应当注意的是,任何一个Cookie一旦过期或被用户从客户机上删除,读取Cookie值的语句将会出错(读取了一个不存在对象的属性值),所以通常在读取前应判断目标Cookie是否还存在。
3.使用多值Cookie
前面介绍过对同一网站,客户端存储的Cookie数量不能超过20个,若需要存储较多的数据,可考虑使用多值Cookie。
例如,下列语句创建了一个名为Person的Cookie集合,其中包含3个子属性,对于浏览器来说,只相当于一条Cookie。
Response.Cookies["Person"]["P_Name"].Value="zhangsan";
Response.Cookies["Person"]["P_Email"].Value="zs@163.com";
Response.Cookies["Person"]["P_Home"].Value="北京";
使用下列语句可从上述多值Cookie中读取数据。
yr_name=Request.Cookies["Person"]["P_Name"].Value;
yr_email=Request.Cookies["Person"]["P_Email"].Value;
yr_home=Request.Cookies["Person"]["P-Home"].Value;
或
stringyr_name=Request.Cookies["Person"].Values[0];
stringyr_name=Request.Cookies["Person"].Values[1];
stringyr_name=Request.Cookies["Person"].Values[2];
【演练5-2】使用Cookie设计一个简单的网上投票管理程序,要求客户机在10分钟内不能再次投票。
访问网站时首先显示如图5-7所示的页面,用户在选择了最喜欢的书后单击“提交”按钮,屏幕弹出如图5-8所示的提示信息框。如果用户在10分钟内再次执行投票操作,屏幕将弹出如图5-9所示的信息框,提醒用户在10分钟之内不允许再次投票。单击“查看结果”按钮,屏幕将弹出如图5-10所示的信息框,显示总共投票人次、各书的得票数及百分比。
图5-7 投票页面
图5-8 投票成功
如果用户在无任何人投票前单击了“查看结果”按钮,将弹出如图5-11所示的无数据提示信息框。注意,若没有进行此种情况的判断,单击按钮时可能会因计算百分比时分母为零而导致整个程序运行出错。
图5-9 10分钟内禁止再次投票
图5-10 显示统计数据
图5-11 无数据提示
程序设计步骤如下。
(1)设计指导思想
用户首次访问网站并投票成功后,系统创建一个有效期为10分钟的Cookie保存在客户计算机上。如果用户再次执行投票操作,系统会判断是否存在前面创建的有效Cookie,若有则表明距上次投票操作没有超过10分钟,用户的投票操作无效,并给出提示信息。否则投票有效,进行票数累加。
(2)设计Web页面
新建一个ASP.NET网站,向页面中添加一个单选按钮组控件RadioButtonList1和两个按钮控件Button1、Button2。并向页面中添加必要的文字信息。
(3)设置对象属性
设置RadioButtonList1的ID属性为rbtnlBook,并通过其Items属性添加3本书的名称;设置Button1的ID属性为btnOK,Text属性为“提交”;设置Button2的ID属性为btnResult,Text属性为“查看结果”。各控件的其他初始属性将在页面载入事件中通过代码进行设置。
(4)编写事件代码
在所有事件过程之外声明静态变量。
//声明双精度静态变量,使之在所有事件过程中均可使用
//num1、num2、num3分别用于存放各书得票数,sum用于存放总投票数
staticdoublenum1,=num2,num3,sum;
1)页面载入时执行的事件处理程序代码如下。
2)“提交”按钮被单击时执行的事件处理程序代码如下。
3)“查看结果”按钮被单击时执行的事件代码如下。
有以下两点需要说明。
1)声明在所有事件处理程序之外的变量(Web窗体级变量)可以被所有事件访问,只有当Web窗体页面关闭或刷新时变量才被销毁。static静态变量中的数据能保持到页面关闭,不会因页面刷新而被销毁。需要注意的是,如果有多个用户同时访问页面,static变量对所有用户均有效。例如,A、B用户分别从不同的计算机上访问页面,每人投“三国演义”1票,则所有用户单击“查看结果”按钮时,都可以看到“三国演义”得到了2票。也就是说,static静态变量是一种共享型数据,可以被所有用户查看和修改。显然,static静态变量不适合保存个性化的数据(如用户名、用户级别和登录状态等),否则就会出现“串值”现象。在实际应用中各项的得票数应保存到数据库中。
2)演练本例前应确保使用的浏览器支持Cookie。IE的Cookie设置可在“Internet选项”下的“高级隐私”中进行。
5.5.2 创建和使用Session对象
由于使用Cookie时的种种限制,使其只能应用在一些简单的、数据量较小的场合。与Cookie不同,Session对象对存储数据量没有限制,也可以在其中保存更为复杂的数据类型。例如,可以在Session中保存数组、类对象和数据集等。
与Cookie对象一样,保存在Session中的数据可以跨网页使用,因此它可以用来在不同的网页中传递数据。此外,Session是一个存储在服务器端的对象集合,避免了Cookie信息保存在客户端的不安全因素,非常适合用户保存用户名、密码等敏感信息。
在ASP.NET中使用Session对象时,必须保证页面的@Page指令中EnableSessionState属性的值被设置为True(默认)或ReadOnly,并且在Web.config文件中对Session进行了正确的设置(默认设置为开启Session)。
1.Session的工作原理
当用户请求一个ASP.NET页面时,系统将自动创建一个Session(会话),退出应用程序或关闭服务器时该会话将被撤销。系统在创建会话时将为其分配一个长长的字符串(Ses-sionID)标识,以实现对会话进行管理和跟踪。该字符串中只包含URL中所允许的ASCII字符。SessionID具有的随机性和唯一性保证了会话不会冲突,也不能利用新SessionID推算出现有会话的SessionID。
通常情况下,SessionID会存放在客户端的Cookies内,当用户访问ASP.NET网站中的任何一个页面时,SessionID将通过Cookie传递到服务器端,服务器根据SessionID的值对用户进行识别,以返回对应该用户的Session信息。通过配置应用程序,可以在客户端不支持Cookies时将SessionID嵌套在URL中,服务器可以通过请求的URL获得SessionID值。
Session信息可以存放在ASP.NET进程、状态服务器或SQL Server数据库中。默认情况下Session的生存周期为20分钟,可以通过Session的Timeout属性更改这一设置。在Session的生存周期内Session是有效的,超过了这个时间Session就会过期,Session对象将被释放,其中存储的信息也将丢失。
2.Session对象的常用属性及方法
Session对象的常用属性如表5-9所示。
表5-9 Session对象的常用属性
Session对象的常用方法如表5-10所示。
表5-10 Session对象的常用方法
Session对象有以下两个事件。
1)Start事件:在创建会话时发生。
2)End事件:在会话结束时发生。需要说明的是,当用户在客户端直接关闭浏览器退出Web应用程序时,并不会触发Session_End事件,因为关闭浏览器的行为是一种典型的客户端行为,是不会被通知到服务器端的。Session_End事件只有在服务器重新启动、用户调用了Session_Abandon方法或未执行任何操作达到了Session.Timeout设置的值(超时)时才会被触发。
3.使用Session对象
(1)将数据保存到Session对象中
向Session对象中存入数据的方法十分简单,下列语句可使用户单击按钮时将两个字符串分别存入两个Session对象中。
由于Session对象中可以同时存放多个数据,所以需要用一个标识加以区分,如本例使用的MyVal1和MyVal2。需要注意的是,如果在此之前已存在MyVal1或MyVal2,则再次执行赋值语句将更改原有数据,而不会创建新的Session对象。
(2)从Session对象中取出数据
下列语句表示了当目标页面载入时如何从Session对象中取出数据的方法。
【演练5-3】设计一个包含Default.aspx和Welcome.aspx两个页面的网站。具体要求如下。
1)如图5-12所示,Default.aspx具有用户登录和注册两个功能。
2)新用户注册时不能使用已存在的用户名,且自行注册的用户只能是“用户”级别。
3)登录或注册失败要给出出错提示信息。
4)如图5-13所示,Main.aspx页面能根据用户级别显示不同的内容,且页面只能通过成功登录后跳转,不能通过直接输入URL的方法访问。单击“注销”链接按钮,可清除已登录的用户名和用户级别记录,返回到Default.aspx。
5)要求使用文本文件保存用户数据(用户名、密码和级别)。要求程序的主要功能通过类文件中的方法来实现。
图5-12 Default.aspx页面
图5-13 Welcome.aspx页面(管理员和用户)
程序设计步骤如下。
(1)创建ASP.NET网站
新建一个ASP.NET空网站,向页面中添加两个Web窗体Default.aspx和Main.aspx;添加一个类文件Manage.cs(添加类文件时系统将自动创建App_Code文件夹);添加一个用于存放数据文件的App_Data文件夹,在该文件夹中创建一个Data.txt文件。由于程序规定所有自行注册的用户级别均为普通“用户”,所以要按用户名、密码和级别顺序每行一个参数的格式手动添加一组管理员信息,如图5-14所示。注意要在文件的结尾留一个空行(最后一行处按<Enter>键)。
图5-14 添加管理员数据
(2)设计程序界面
向Default.aspx中添加一个用于布局的HTML表格,适当调整表格的行列数。向表格中添加需要的说明文字;添加两个文本框控件TextBox1、TextBox2和两个按钮控件Button1、Button2;添加一个用于显示提示信息的标签控件Label1。Default.aspx界面设计如图5-15所示。
向Main.aspx中添加一个用于显示欢迎信息的标签控件Label1;添加3个链接按钮控件LinkButton1、LinkButton2和LinkButton3。Main.aspx界面设计如图5-16所示。
图5-15 Default.aspx界面设计
图5-16 Main.aspx界面设计
(3)设置对象属性
1)Default.aspx页面中各控件的属性设置:TextBox1的ID属性为txtName;TextBox2的ID属性为txtPwd,TextMode属性为Password,使之表现为密码框;Button1的ID属性为btnLogin,Text属性为“登录”;Button2的ID属性为btnReg,Text属性为“注册”。
2)Main.aspx页面中各控件的属性设置:Label1的ID属性为lblWelcome;LinkButton1、LinkButton2和LinkButton3的ID属性分别为lbtnNormal、lbtnAdmin和lbtnCancel,Text属性分别为“修改个人信息”“管理所有用户”和“注销”。
(4)编写程序代码
1)Manage.cs的代码如下。
2)Default.aspx页面中“登录”按钮被单击时执行的事件处理代码如下。
3)Default.aspx页面中“注册”按钮被单击时执行的事件处理代码如下。
4)Main.aspx页面载入时执行的事件处理代码如下。
5)Main.aspx页面中“注销”链接按钮被单击时执行的事件处理代码如下。
说明:本例中将保存有用户名、密码和级别的Data.txt文件保存在ASP.NET专用的App_Data文件夹中,可以保证无法使用直接调用URL的方法下载数据文件。也就是说,用户直接在浏览器中输入“http://网站地址/App_Data/Data.txt”是无法下载和显示文件内容的。
如果Data.txt文件没有放在App_Data中,情况会如何?读者可以测试一下。
5.5.3 使用PreviousPage属性
PreviousPage是Page类公开的一个属性。当页面通过Server.Transfer方法或控件的Post-BackUrl属性从A页面跳转到同一ASP.NET应用程序的B页面时,可以在B中使用Previous-Page获取A中控件的属性值。也就是说,在同一应用程序中目标页中的PreviousPage属性包含对源页的引用。与Session对象相似,通过PreviousPage可以实现跨页面的数据传递。
1.PreviousPage与Session的比较
PreviousPage与Session相似,都可以实现跨页数据传递。二者主要的不同有以下两点。
1)PreviousPage主要用来传递控件的属性值。Session不仅可以传递控件属性值,也可以方便地传递变量值。
2)与Session相比,PreviousPage不需要一直占用服务器内存资源,特别适合跨页面传递较多数据的情况。
2.PreviousPage使用示例
【演练5-4】如图5-17所示,在Default.aspx中有一个包含10个复选框的CheckBox-List控件,用户进行选择后单击“确定”按钮(LinkButton)跳转到Result.aspx页面。在Result.aspx中可以通过PreviousPage属性获取用户的选择,并显示到标签控件中,如图5-18所示。
图5-17 Default.aspx页面
图5-18 Result.aspx页面
程序设计步骤如下。
(1)设计程序界面
新建一个ASP.NET空网站,向其中添加Default.aspx和Result.aspx两个Web窗体。向Default.aspx中添加一个复选框组控件CheckBoxList1和一个链接按钮控件LinkButton1。向Result.aspx中添加一个标签控件Label。
(2)设置对象属性
如图5-17所示,向CheckBoxList1中添加10个运动项目作为供选项,设置CheckBox-List1的CellPadding和CellSpacing属性并调整各项的间距;设置LinkButton1的Text属性为“确定”,PostBackUrl属性指向Result.aspx。
(3)编写程序代码
Default.aspx中无须编写任何事件处理代码。
Result.aspx页面载入时执行的事件处理代码如下。
需要强调的是,使用Server.Transfer方法或控件的PostBackUrl属性实现页面跳转时,才可以使用PreviousPage属性获取源页面中控件的属性值。源页面中的控件可以是常规可见控件,也可以是专门用于保存数据的“隐含字段”控件HiddenField。HiddenField控件的Value属性可以保存一个string类型的字符串数据。
5.6 实训——使用Cookie
5.6.1 实训目的
通过实训进一步理解Cookie的概念及使用方法。
5.6.2 实训要求
设计一个ASP.NET网站,向Default.aspx页面中添加一个按钮控件和一个标签控件。页面首次加载时创建一个名为MyCookie,有效期为1分钟的Cookie,并为其赋值OK,标签中显示Cookie到期时间和值。在Cookie有效期内单击按钮,标签中显示“Cookie有效”和Cookie值,过期后单击该按钮,标签中显示“Cookie已失效”。
5.6.3 实训步骤
新建一个ASP.NET空网站,向网站中添加一个Web窗体页面Default.aspx,向页面中添加一个命令按钮控件Button1和一个标签控件Label1。设置按钮控件的ID属性为btnOK,标签控件的ID属性为lblCookie。
1)页面载入时执行的事件代码如下。
2)“确定”按钮被单击时执行的事件代码如下。