网页发送到服务器时,都会创建网页类的一个新实例。在传统的 Web 编程中,这通常意味着在每一次往返行程中,与该页及该页上的控件相关联的所有信息都会丢失。例如,如果用户将信息输入到文本框,该信息将在从浏览器或客户端设备到服务器的往返行程中丢失。为了解决传统的 Web 编程的固有限制,ASP.NET 包括了几个选项,可帮助您按页保留数据和在整个应用程序范围内保留数据。这些功能如下所示:
- 视图状态
- 控件状态
- 隐藏域
- Cookie
- 查询字符串
- 应用程序状态
- 会话状态
- 配置文件属性
视图状态、控件状态、隐藏域、Cookie 和查询字符串均会涉及以不同方式将数据存储到客户端上。而应用程序状态、会话状态和配置文件属性都将数据存储到服务器上的内存中。每个选项都有不同的优点和缺点,具体取决于相应的方案。
-
Cookie
Cookie 是一小段文本信息,存储在客户机,Cookie 与网站关联,而不是与特定的页面关联。因此,无论用户请求站点中的哪一个页面,浏览器和服务器都将交换 Cookie 信息。大多数浏览器支持最大为 4096 字节的 Cookie。浏览器还限制站点可以在用户计算机上存储的 Cookie 的数量。大多数浏览器只允许每个站点存储 20 个 Cookie;如果试图存储更多 Cookie,则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 Cookie 总数作出绝对限制,通常为 300 个。您可能遇到的 Cookie 限制是用户可以将其浏览器设置为拒绝接受 Cookie。
- 写单值Cookie
Response.Cookies["userName"].Value = "patrick";
Response.Cookies["userName"].Expires = DateTime.Now.AddDays(1);
HttpCookie aCookie = new HttpCookie("lastVisit");
aCookie.Value = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
- 写多值Cookie
Response.Cookies["userInfo"]["userName"] = "patrick";
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
HttpCookie aCookie = new HttpCookie("userInfo");
aCookie.Values["userName"] = "patrick";
aCookie.Values["lastVisit"] = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
- 将 Cookie 限制到某个文件夹或应用程序
HttpCookie appCookie = new HttpCookie("AppCookie");
appCookie.Value = "written " + DateTime.Now.ToString();
appCookie.Expires = DateTime.Now.AddDays(1);
appCookie.Path = "/Application1";
Response.Cookies.Add(appCookie);
- 限制 Cookie 的域范围
Response.Cookies["domain"].Value = DateTime.Now.ToString();
Response.Cookies["domain"].Expires = DateTime.Now.AddDays(1);
Response.Cookies["domain"].Domain = "support.contoso.com";
- 取 Cookie
Label1.Text = Server.HtmlEncode(Request.Cookies["userInfo"]["userName"]);
Label2.Text = Server.HtmlEncode(Request.Cookies["userInfo"]["lastVisit"]);
- 遍历Cookie
for (int i = 0; i < Request.Cookies.Count; i++)
{
aCookie = Request.Cookies[i];
output.Append("Name = " + aCookie.Name + "<br />");
if (aCookie.HasKeys)
{
for (int j = 0; j < aCookie.Values.Count; j++)
{
subkeyName = Server.HtmlEncode(aCookie.Values.AllKeys[j]);
subkeyValue = Server.HtmlEncode(aCookie.Values[j]);
output.Append("Subkey name = " + subkeyName + "<br />");
output.Append("Subkey value = " + subkeyValue +
"<br /><br />");
}
}
else
{
output.Append("Value = " + Server.HtmlEncode(aCookie.Value) +
"<br /><br />");
}
}
Label1.Text = output.ToString();
- 删除Cookie
string subkeyName;
subkeyName = "userName";
HttpCookie aCookie = Request.Cookies["userInfo"];
aCookie.Values.Remove(subkeyName);
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
-
视图状态
视图状态是 ASP.NET 页框架用于在往返过程之间保留页和控件值的方法。在呈现页的 HTML 标记时,必须在回发过程中保留的页和值的当前状态将被序列化为 Base64 编码字符串。然后,此信息将被放入一个或多个视图状态隐藏字段。
-
会话状态
当用户在 Web 应用程序中导航 ASP.NET 页时,ASP.NET 会话状态使您能够存储和检索用户的值。HTTP 是一种无状态协议。这意味着 Web 服务器会将针对页面的每个 HTTP 请求作为独立的请求进行处理。服务器不会保留以前的请求过程中所使用的变量值的任何信息。ASP.NET 会话状态将来自限定时间范围内的同一浏览器的请求标识为一个会话,并提供用于在该会话持续期间内保留变量值的方法。默认情况下,将为所有 ASP.NET 应用程序启用 ASP.NET 会话状态。
会话变量存储在通过 InProc 模式,此模式将会话状态存储在 Web 服务器上的内存中。这是默认设置。它是唯一支持 Session_OnEnd 事件的模式。 HttpContext..::.Session 属性公开的 SessionStateItemCollection 对象中。在 ASP.NET 页中,当前会话变量将通过 Page 对象的 Session 属性公开。
会话由一个唯一标识符标识,可使用 SessionID 属性读取此标识符。为 ASP.NET 应用程序启用会话状态时,将检查应用程序中每个页面请求是否有浏览器发送的 SessionID 值。如果未提供任何 SessionID 值,则 ASP.NET 将启动一个新会话,并将该会话的 SessionID 值随响应一起发送到浏览器。
默认情况下,SessionID 值存储在 Cookie 中。但也可以将应用程序配置为在"无 Cookie"会话的 URL 中存储 SessionID 值。
只要一直使用相同的 SessionID 值来发送请求,会话就被视为活动的。如果特定会话的请求间隔超过指定的超时值(以分钟为单位),则该会话被视为已过期。使用过期的 SessionID 值发送的请求将生成一个新的会话。
- 会话事件
ASP.NET 提供两个可帮助您管理用户会话的事件:Session_OnStart 事件和 Session_OnEnd 事件。前者在开始一个新会话时引发;而后者在一个会话被放弃或过期时引发。会话事件是在 ASP.NET 应用程序的 Global.asax 文件中指定的。
如果将会话 Mode 属性设置为 InProc(默认模式)以外的值,则不支持 Session_OnEnd 事件。
- 会话事件示例
public void Application_OnStart()
{
Application["UsersOnline"] = 0;
}
public void Session_OnStart()
{
Application.Lock();
Application["UsersOnline"] = (int)Application["UsersOnline"] + 1;
Application.UnLock();
}
public void Session_OnEnd()
{
Application.Lock();
Application["UsersOnline"] = (int)Application["UsersOnline"] - 1;
Application.UnLock();
}
- 会话模式
ASP.NET 会话状态支持若干用于会话数据的存储选项。每个选项都由 SessionStateMode 枚举中的一个值标识。下面的列表描述了可用的会话状态模式:
- StateServer 模式,此模式将会话状态存储在一个名为 ASP.NET 状态服务的单独进程中。这确保了在重新启动 Web 应用程序时会保留会话状态,并让会话状态可用于网络场中的多个 Web 服务器。
- SQLServer 模式将会话状态存储到一个 SQL Server 数据库中。这确保了在重新启动 Web 应用程序时会保留会话状态,并让会话状态可用于网络场中的多个 Web 服务器。
- Custom 模式,此模式允许您指定自定义存储提供程序。
- Off 模式,此模式禁用会话状态。
- 保护会话 ID
保护应用程序和数据时,确保会话标识符不会通过网络暴露给不必要的源以及不会用于针对您应用程序的重播攻击,这一点很重要。下面的建议可以提高会话标识符的安全性。应确保使用敏感数据的应用程序页的安全,方法是使用标准http://msdn.microsoft.com/zh-cn/library/ms178587(VS.90).aspx
- 使用安全套接字层 (SSL) 来保护应用程序。
-
为会话 Timeout 指定一个较小值。也可考虑使用客户端脚本对客户端强制执行一个与会话超时一样长的重定向,或使用下面的示例所示的 AddHeader 方法添加一个刷新标头。 Visual Basic
复制代码
Response.AddHeader("Refresh", Session.Timeout & ";URL=Logoff.htm"
Response.AddHeader("Refresh", Session.Timeout + ";URL=Logoff.htm";
- 避免使用无 cookie 的会话。如果指定无 cookie 的会话,需警告用户不要在电子邮件和书签中使用包含会话 ID 的链接,也不要保存这些链接。
- 避免指定 AutoDetect 和 UseDeviceProfile 的 cookie 模式。
- 允许用户注销,此时应调用 HttpSessionState..::.Abandon 方法。警告用户在注销后关闭浏览器。
- 使用无 cookie 的会话时,将 regenerateExpiredSessionID 配置为 true 以便在提供过期的会话标识符时始终启动一个新会话。
- 保护使用会话状态的网页
Web 安全机制,例如使用安全套接字层 (SSL) 并要求用户登录后才能执行敏感操作(如更新个人信息或删除帐户)。
此外,网页上不应以明文形式公开敏感数据,如密码(有时候还包括用户名)。请确保显示这种信息的页面使用了 SSL,并且仅可供已经过身份验证的用户使用。
- 会话读写
string firstName = "Jeff";
string lastName = "Smith";
string city = "Seattle";
Session["FirstName"] = firstName;
Session["LastName"] = lastName;
Session["City"] = city;
string firstName = (string)(Session["First"]);
string lastName = (string)(Session["Last"]);
string city = (string)(Session["City"]);
- 实现会话状态存储提供程序
使用 ASP.NET 会话状态可以将用户会话数据存储在不同的源中。默认情况下,会话状态值和信息都存储在 ASP.NET 进程的内存中。一个方法是将会话数据存储在状态服务器中,状态服务器将会话数据保存在单独的进程中,如果 ASP.NET 应用程序关闭再重新启动,则它会保留会话数据。另一个方法是将会话数据存储在 SQL Server 数据库中,这种情况下会话数据可由多个 Web 服务器共享。
可以使用 ASP.NET 附带的会话状态存储,也可以实现自己的会话状态存储提供程序。由于下列原因,您可以创建自定义会话状态存储提供程序:
- 需要将会话状态信息存储在 SQL Server 以外的数据源中,如 FoxPro 数据库或 Oracle 数据库。
- 需要使用不同于 .NET Framework 附带的提供程序所使用的数据库架构来管理会话状态信息。例如,使用预定义架构存储在现有 SQL Server 数据库中的购物车数据。
可以通过创建一个继承 SessionStateStoreProviderBase 类的类,来实现自定义会话状态存储提供程序。
参考:
-
应用程序状态
应用程序状态是可供 ASP.NET 应用程序中的所有类使用的数据储存库。它存储在服务器的内存中,因此与在数据库中存储和检索信息相比,它的执行速度更快。与特定于单个用户会话的会话状态不同,应用程序状态应用于所有的用户和会话。
- 资源 由于应用程序状态存储在内存中,因此比将数据保存到磁盘或数据库中速度更快。但是,在应用程序状态中存储较大的数据块可能会耗尽服务器内存,这会导致服务器将内存分页到磁盘。除了使用应用程序状态之外,还可以使用 ASP.NET 缓存机制来存储大量的应用程序数据。ASP.NET 缓存也是将数据存储在内存中,因此速度很快;但是,ASP.NET 会对缓存进行主动管理,如果内存不足时将移除项。有关更多信息,请参见 ASP.NET 缓存概述。
- 易失性 由于应用程序状态存储在服务器内存中,因此每当停止或重新启动应用程序时应用程序状态都将丢失。例如,如果更改了 Web.config 文件,则要重新启动应用程序,此时除非将应用程序状态值写入非易失性存储媒体(如数据库)中,否则所有应用程序状态都将丢失。
- 可伸缩性 应用程序状态不能在为同一应用程序服务的多个服务器间(如在网络场中)共享,也不能在同一服务器上为同一应用程序服务的多个辅助进程间(如在网络园中)共享。因此,应用程序不能依靠应用程序状态来实现在不同的服务器或进程间包含相同的应用程序状态数据。如果应用程序要在多处理器或多服务器环境中运行,可以考虑对必须在应用程序中准确保存的数据使用伸缩性更强的选项(如数据库)。
- 并发 应用程序状态采用自由线程模式,即应用程序状态数据可由多个线程同时访问。因此,必须确保通过包含内置同步支持,以线程安全的方式进行应用程序状态数据更新。可以使用 Lock 和 UnLock 方法来确保数据的完整性,方法是锁定数据,使其一次只能由一个源进行写操作。还可以初始化 Global.asax 文件中 Application_Start 方法中的应用程序状态值,降低出现并发问题的可能性。
- 读写
Application.Lock();
Application["PageRequestCount"] =
((int)Application["PageRequestCount"]) + 1;
Application.UnLock();
if (Application["AppStartTime"] != null)
{
DateTime myAppStartTime = (DateTime)Application["AppStartTime"];
}
转自:http://www.cnblogs.com/luminji/archive/2010/11/29/1890859.html