摘要ASP
NET为保持用户请求之间的数据提供了多种不同的途径
你可以使用Application对象
cookie
hidden fields
Sessions或Cache对象
以及它们的大量的方法
决定什么时候使用它们有时很困难
本文将介绍了上述的技术
给出了什么时候使用它们的一些指导
尽管这些技术中有些在传统ASP中已经存在
但是有了
NET框架组件后该在什么时候使用它们发生了变化
为了在ASP
NET中保持数据
你需要调整从先前的ASP中处理状态中学习到的知识
随着Web时代的到来在无状态的HTTP世界中管理状态成为Web开发者的一个大问题最近出现了几种存储和检索数据的不同技术本文我将解释ASPNET开发者能怎样通过页面请求维护或传递状态
在ASPNET中有几种保持用户请求间数据的途径实际上太多了使没有经验的开发者对在哪个特定的环境下使用哪个对象很困惑为了回答这个问题需要考虑下面三个条件
◆ 谁需要数据?
◆ 数据需要保持多长时间?
◆ 数据集有多大?
通过回答这些问题你能决定哪个对象为保持ASPNET应用程序请求间数据提供了最佳的解决方案图列出了不同的状态管理对象并描述了什么时候使用它们ASPNET中添加了四个新的对象CacheContextViewState和WebConfig文件
ASPNET也支持传统的ASP对象包括Application Cookie有隐藏字段的 Form Post QueryString和Sessions注意这五个数据容器的正确使用方法发生了改变因此有经验的程序员在考虑这些熟悉的对象时也许需要学习一些知识
保持方法谁需要数据保持多长时间数据量大小Application所有用户整个应用程序生命期任意大小Cookie一个用户可以很短
如果用户不删除也可以很长小的
简单数据Form Post 一个用户到下一次请求(可以跨越多个请求重复使用)任意大小QueryString一个或一组用户到下一次请求(可以跨越多个请求重复使用)小的
简单数据Sessions一个用户用户活动时一直保持+一段时间(一般
分钟)可以是任何大小
但是因为用户有单独的Sessions 存储
所有它应该最小Cache所有用户或某些用户根据需要可大可小
可简单可复杂Context一个用户一个请求可以保持大对象
但是一般不这样使用ViewState一个用户一个Web窗体最小Config file 所有用户知道配置文件被更新可以保持大量数据
通常组织小的字符串和XML结构表
ASP
NET中的数据容器对象
Application
让我们通过回答上面的状态问题判定条件来说明该对象谁需要数据?所有的用户需要访问它需要保持数据多长时间?永久保持或在应用程序生存期中保持数据多大?可以是任何大小在任何给定的时刻只有数据的一个副本存在
在传统ASP中Application对象提供了一个保存频繁使用但很少改变的数据片的位置例如菜单内容和参考数据尽管在ASPNET 中Application依然作为数据容器存在但是有其它一些更适合以前保存在传统ASP应用程序的Application集合中的数据的对象
在传统的ASP中如果被保存的数据在应用程序的生存期中根本不会改变(或很少改变例如只读数据和大多数情况下是读操作的数据)Application对象是理想的选择连接字符串就是保存在Application变量中的一个最普通的数据片但是在ASPNET中类似的配置数据最好保存在Webconfig文件中如果使用Application对象一个需要考虑的问题是任何写操作要么在Application_OnStart事件(globalasax)中要么在ApplicationLock部分中完成尽管使用ApplicationLock来确保写操作正确地执行是必要的但是它串行化了对Application对象的请求而这对于应用程序来说是个严重的性能瓶颈图演示了怎样使用Application对象它包括一个Web窗体和它的代码文件
Applicationaspx
<form id=Application method=post runat=server>
<asp:validationsummary id=valSummary Runat=server>
</asp:validationsummary>
<table>
<tr>
<td colSpan=>Set Application Variable:</td>
</tr>
<tr>
<td>Name</td>
<td><asp:textbox id=txtName Runat=server></asp:textbox>
</td>
<td><asp:requiredfieldvalidator id=nameRequired
runat=server Display=Dynamic ErrorMessage=Name is
required ControlToValidate=txtName>*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td>Value</td>
<td><asp:textbox id=txtValue Runat=server>
</asp:textbox></td>
<td><asp:requiredfieldvalidator id=valueRequired
Runat=server Display=Dynamic ErrorMessage=Value is
required ControlToValidate=txtValue>*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td colSpan=><asp:button id=btnSubmit Runat=server
Text=Update Value></asp:button></td>
</tr>
</table>
<asp:Label ID=lblResult Runat=server />
</form>
Applicationaspxcs
private void btnSubmit_Click(object sender SystemEventArgs e)
{
if(IsValid)
{
ApplicationLock();
Application[txtNameText] = txtValueText;
ApplicationUnLock();
lblResultText = The value of <b> + txtNameText +
</b> in the Application object is <b> +
Application[txtNameText]ToString() + </b>;
}
}
代码段在ASPNET中访问Application对象
它的输出如下图所示
图 Application对象的内容
注意图中Application对象的内容是追蹤输出的显示追蹤是个伟大的调试工具但是在某个点被打开的有追蹤的页面可能出现在产品环境中如果出现这种情况你肯定不希望显示敏感的信息这就是为什么Application对象从来不是推荐的存放敏感信息(例如连接字符串)的位置的主要原因之一
Cookies
当特定的用户需要特定的数据片并且需要把数据在某个可变的时段中保持的时候cookie就非常方便它的生命周期可能与浏览器窗体的一样短也可以长达数月数年cookie可以小到只有几个字节的数据因为它们在每个浏览器请求中传递它们的内容需要尽可能的小
Cookie提供了一条灵活的强大的维护用户请求间数据的途径这就是为什么Internet上大多数动态站点使用它们的原因因为cookie可以存储的数据量很受限制最好只在cookie中保存键字段其它的数据保存在数据库或其它的服务器端数据容器中但是由于不是所有的浏览器都支持cookie并且它可以被用户禁止或删除因此它们也不能用于保存关键数据你应该很好地处理用户的cookie被删除的情况最后cookie作为简单的明文文本保存在用户的计算机中因此在它里面不能保存敏感的未加密的数据
图单值和多值cookie
有种特殊的cookie可以保存单个值或名称/值对的集合图显示了单个和多个值cookie的示例通过ASPNET的内建追蹤特性输出这些值可以在ASPNET页面中使用RequestCookies和ResponseCookies集合来维护这在代码段中演示
Cookiesaspxcs
//使用HttpCookie类是指cookie的值和/或子值
HttpCookie cookie;
if(RequestCookies[txtNameText] == null)
cookie = new HttpCookie(txtNameText txtValueText);
else
cookie = RequestCookies[txtNameText];
if(txtSubValueNameTextLength > )
cookieValuesAdd(txtSubValueNameText txtSubValueValueText);
cookieExpires = SystemDateTimeNowAddDays(); // tomorrow
ResponseAppendCookie(cookie);
//检索cookie的值
if(!RequestCookies[txtNameText]HasKeys)
lblResultText = The value of the <b> + txtNameText + </b>
cookie is <b> + RequestCookies[txtNameText]ValueToString() +
</b>;
else
{
lblResultText = The value of the <b> + txtNameText + </b>
cookie is <b> + RequestCookies[txtNameText]ValueToString() +
</b> with subvalues:<br>;
foreach(string key in RequestCookies[txtNameText]ValuesKeys)
{
lblResultText += [ + key + = +
RequestCookies[txtNameText]Values[key]ToString() + ]<br>;
}
}
删除Cookie
// 把的值设置为空并把终止时间设置为过去某个时刻
ResponseCookies[txtNameText]Value = null;
ResponseCookies[txtNameText]Expires =
SystemDateTimeNowAddMonths(); //上个月
代码段Accessing 在ASPNET中访问Cookies
Form Post / 隐藏的窗体字段
特定的用户需要窗体的数据并且它需要在单个请求到应用程序终止的任何阶段都保持这些数据事实上可以是任意大小的它随着每个form post在网络上向前和向后发送
在传统的ASP中这是在应用程序中暴露状态的通常的途径特别是在多页面窗体应用程序中但是在ASPNET中这种技术不太适合了因为只要你使用postback模型(也就是页面发回给自己)Web控件和ViewState自动处理了这些操作ViewState是ASPNET对这种技术的实现我将在本文的后部分讨论它访问通过POST发送的窗体值是使用HttpRequest对象的窗体集合完成的在图中一个ASPNET页面设置了某个用户的ID在这以后它保持在一个隐藏的窗体字段中后面的向任何页面的请求保留这个值直到页面使用Submit按钮链接到其它的用户
Formaspx
<h>Form </h>
<form id=Application method=post runat=server>
<p>Your username:
<asp:Label ID=lblUsername Runat=server />
</p>
<asp:Panel Runat=server ID=pnlSetValue>
<asp:validationsummary id=valSummary Runat=server>
</asp:validationsummary>
<TABLE>
<TR>
<TD colSpan=>Set Hidden Form Username Variable:</TD></TR>
<TR>
<TD>Username</TD>
<TD>
<asp:textbox id=txtName Runat=server></asp:textbox></TD>
<TD>
<asp:requiredfieldvalidator id=nameRequired runat=server
ControlToValidate=txtName ErrorMessage=Name is required
Display=Dynamic>*</asp:requiredfieldvalidator></TD></TR>
<TR>
<TD colSpan=>
<asp:button id=btnSubmit Runat=server Text=Set Value>
</asp:button></TD></TR></TABLE>
</asp:Panel>
<asp:Label ID=lblResult Runat=server />
</form>
<form action=formaspx method=post name=form id=form>
<input type=hidden name=username value=<%# username %> >
<input type=submit value=Go to Formaspx
</form>
Formaspxcs
private void Page_Load(object sender SystemEventArgs e)
{
if(!IsPostBack) // 新的请求或者来自formaspx的请求
{
// 检查窗体集合
if(RequestForm[username] == null)
pnlSetValueVisible = true;
else
{
//需要设置用户名值
pnlSetValueVisible = false;
username = RequestForm[username]ToString();
lblUsernameText = username;
//数据绑定到隐藏的窗体字段值
thisDataBind();
}
}
}
private void btnSubmit_Click(object sender SystemEventArgs e)
{
if(IsValid)
{
//隐藏窗体来设置值
pnlSetValueVisible = false;
username = txtNameText;
lblResultText = Username set to + txtNameText + ;
lblUsernameText = username;
thisDataBind();
}
}
Formaspx
<h>Form </h>
<form id=Application method=post runat=server>
<p>Your username: <asp:Label ID=lblUsername Runat=server /></p>
</form>
<form action=formaspx method=post id=form name=form>
<input type=hidden name=username value=<%# username %> >
<input type=submit value=Go to Formaspx
</form>
Formaspxcs
private void Page_Load(object sender SystemEventArgs e)
{
if(RequestForm[username] != null)
{
username = RequestForm[username]ToString();
lblUsernameText = username;
thisDataBind();
}
}
代码段在ASPNET中使用隐藏窗体字段
在ASPNET中一个页面上只能存在一个服务器端窗体并且该窗体必须提交返回到自身(仍然可以使用客户端窗体没有限制)隐藏窗体字段再也没有用于在NET框架组件上建立的应用程序间传递数据的主要原因之一是NET框架组件控件都可以使用ViewState自动维护自己的状态ViewState简单地把使用隐藏窗体字段设置和检索值所包含的工作封装进一个使用简单的集合对象中
QueryString
QueryString对象中保存的数据由单独的用户使用它的生命周期可能只有一个请求那么短也可能有用户使用应用程序的时间那么长(如果构造正确的话)这类数据一般小于KBQueryString中的数据在URL中传递对于用户来说是可见的因此你能猜到使用这种技术时敏感的数据或可用于控制应用程序的数据需要加密
也就是说QueryString是在ASPNET Web窗体间发送信息的一条很好的途径例如如果有一个含有产品列表的数据表格(DataGrid)并且在表格上有一个链接导向产品的细节页面使用QueryString就是理想的可以把产品的ID包含在链接到产品细节页面的QueryString中(例如productdetailsaspx?id=)使用QueryStrings的另一个好处是页面的状态包含在URL中这意味着用户可以把某个通过QueryStrings建立的窗体放入他的收藏夹中当它们作为收藏返回到页面时将与作收藏的时候一样很明显这只在页面不依赖QueryString外的所有状态和不作任何改变的时候有作用
敏感数据以及任何不希望用户操作的变量应该避免出现在此处(除非加密使用户不能阅读)并且URL中不合法的字符必须使用ServerUrlEncode编码如图所示当处理单个ASPNET页面时对维护状态来说ViewState是比QueryString好的选择对于长期的数据存储CookieSessions或Cache都比QueryStrings更加适于作为数据容器
Querystringaspx
<form id=Querystring method=post runat=server>
<asp:validationsummary id=valSummary Runat=server>
</asp:validationsummary>
<table>
<tr>
<td colSpan=>Set Querystring Variable:</td>
</tr>
<tr>
<td>Name</td>
<td><asp:textbox id=txtName Runat=server></asp:textbox>
</td>
<td><asp:requiredfieldvalidator id=nameRequired
runat=server Display=Dynamic ErrorMessage=Name is
required ControlToValidate=txtName>*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td>Value</td>
<td><asp:textbox id=txtValue Runat=server>
</asp:textbox></td>
<td><asp:requiredfieldvalidator id=valueRequired
Runat=server Display=Dynamic ErrorMessage=Value is
required ControlToValidate=txtValue>*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td colSpan=><asp:button id=btnSubmit Runat=server
Text=Update Value></asp:button></td>
</tr>
</table>
<asp:Label ID=lblResult Runat=server />
<a href=querystringaspx?x=>Set querystring x equal to </a>
</form>
Querystringaspxcs
private void Page_Load(object sender SystemEventArgs e)
{
// 检索cookie的值
if(RequestQueryStringHasKeys())
{
lblResultText = The values of the <b> + txtNameText +
</b> querystring parameter are:<br>;
foreach(string key in RequestQueryStringKeys)
{
lblResultText += [ + key + = +
RequestQueryString[key]ToString() + ]<br>;
}
}
}
private void btnSubmit_Click(object sender SystemEventArgs e)
{
if(IsValid)
{
string url = querystringaspx?;
foreach(string key in RequestQueryStringKeys)
{
url += key + = + RequestQueryString[key]ToString() + &;
}
ResponseRedirect(url + txtNameText + = +
ServerUrlEncode(txtValueText));
}
}
代码段在ASPNET中使用QueryStrings传递数据
Sessions
Sessions数据对于特定的用户是特定的它的生存期是用户持续请求的时间加上后来一段时间(一般是分钟)Sessions可以保持或大或小的数据量但是如果应用程序用于成百上千的用户那么总共的存储应该保持最小
不幸的是在传统的ASP中Sessions对象的名声很不好因为它把应用程序约束到特定的计算机上阻碍了用户分组和Web范围的可伸缩性在ASPNET中几乎没有这些问题因为改变Sessions保存的位置很简单在默认情况下(性能最好的情况)Sessions数据仍然保存在本地Web服务器的内存中但是ASPNET支持使用外部状态服务器或数据库管理Sessions数据
使用Sessions对象很简单并且它的语法与传统ASP相同但是Sessions对象是保存用户数据的方法中效率很低的一种因为即使用户停止使用应用程序后它仍然保持在内存中一段时间这对于非常繁忙的站点的可伸缩性有严重的影响其它的选择允许对释放内存的更多的控制例如Cache对象也许更适合大量的大数据值并且在默认情况下ASPNET Sessionss依赖于cookie因此如果用户禁止或不支持cookieSessionss就不能工作但是可以配置Sessionss支持cookie无关对于小的数据量Sessionss对象是保存只需要在用户当前对话中保持的特定数据的极好位置下面的例子演示了怎样设置和从Sessionss对象中检索值
private void btnSubmit_Click(object sender SystemEventArgs e)
{
if(IsValid)
{
// 设置Sessions值
Sessions[txtNameText] = txtValueText;
//读取和显示刚才的设置
lblResultText = The value of <b> + txtNameText + </b> in the Sessions object is <b> + Sessions[txtNameText]ToString() + </b>;
}
}
该Web窗体与Application对象中使用的几乎相同当允许页面追蹤时Sessions集合的内容也是可见的
你需要记住的是即使没有使用Sessionss也会有应用程序开销把Sessionss状态设置为只读的也可以优化只需要读而不需要写数据的页面可以使用下面两种途径之一来配置Sessionss
<%@ Page EnableSessionsstate=false %>
<%@ Page EnableSessionsstate=readonly %>
ASPNET Sessionss可以在Webconfig或Machineconfig中的Sessionsstate元素中配置下面是在 Webconfig中的设置的例子
<Sessionsstate timeout= cookieless=false mode=Inproc />