控制视图状态

更新:2007 年 11 月

Microsoft ASP.NET 网页能够跨往返过程维护它们自己的状态。当为控件设置了一个属性之后,ASP.NET 将该属性值保存为控件状态的一部分。对于应用程序,这使页的生存期看起来像跨多个客户端请求。这种页级别的状态称为页的视图状态。

在普通的 ASP.NET 网页上,服务器将页的视图状态以窗体中隐藏字段的形式作为响应的一部分发送到客户端,客户端将视图状态作为回发的一部分返回服务器。但是,为了降低使用移动控件时的带宽要求,ASP.NET 不会将页的视图状态发送到客户端,而是将视图状态作为用户会话的一部分保存在服务器上。无论何处存在视图状态,ASP.NET 都会将标识该页视图状态的隐藏字段作为每个响应的一部分发送到客户端,客户端将隐藏字段作为下一个回发的一部分返回服务器。

管理视图状态历史记录

因为给定页的视图状态必须保存在服务器上,所以如果用户单击浏览器的“后退”按钮,则服务器上的当前状态和浏览器的当前页有可能失去同步。例如,假设用户转到第 1 页,然后单击某个按钮转到第 2 页,然后按“后退”返回第 1 页。现在浏览器上的当前页是第 1 页,但服务器上的当前状态是第 2 页的状态。

为了解决此问题,ASP.NET 移动网页在用户会话中维护一个视图状态信息的历史记录。发送到客户端的每个标识符都对应于此历史记录中的一个位置。在上一个示例中,如果用户再次从第 1 页发送,则移动网页将使用与第 1 页保存在一起的标识符来同步视图状态历史记录。

可以配置此历史记录的大小,以便为应用程序对其进行微调。默认大小是 6,可以通过将数字属性添加到 Web.config 文件中的标记来更改此大小,如下面的示例所示:

<configuration>
  <system.web>
    <mobileControls sessionStateHistorySize="10" />
  </system.web>
</configuration>

管理过期会话

因为视图状态保存在用户会话中,所以如果未在会话到期时间内回发页,则视图状态有可能到期。此到期时间是移动网页特有的。如果用户发送的页没有可用的视图状态,则将调用该页的 OnViewStateExpire 方法。此方法的默认实现引发一个异常,指示视图状态已到期。但是,如果您的应用程序能够在到期后手动还原视图状态,则您可以在页级别重写此方法并选择不调用基实现。

启用和禁用视图状态

使用会话来管理视图状态的优点在于它使得响应大小更小。缺点是会话状态使用效率低下可导致性能较差。如果使用包含大量数据的控件,则您可以使用一些技术(例如自定义分页或禁用视图状态)来提高效率。例如,假定有一个显示新闻的站点。该站点可以使用智能化更高的数据访问功能(而不是保存每个用户会话的报导内容),使服务器上只缓存每篇报导的一个副本,从而最大程度地减少使用会话状态。

若要禁用控件及其子级的视图状态,请将该控件的 EnableViewState 属性设置为 false。若要禁用整页的视图状态,请将 @ Page 指令的 EnableViewState 属性设置为 false。

即使当禁用了视图状态之后,某些移动控件还会跨客户端往返过程保存关键的状态信息。这种信息的示例包括页上当前活动的窗体。当关闭了视图状态之后,页将此关键信息作为往返过程上发送到客户端的隐藏窗体变量保存。

默认情况下,ASP.NET 的会话管理功能要求服务器将会话 Cookie 写到客户端。然后,客户端在会话过程中每次收到请求时提交该 Cookie,服务器使用 Cookie 信息查找会话状态信息。但是,许多移动设备不支持 Cookie。为使会话管理(包括视图状态)在这些设备上正确工作,您必须配置应用程序使用无 Cookie 的会话管理。如果启用了此功能,则 ASP.NET 将自动在应用程序 URL 中插入会话键。

某些设备不支持 Cookie。若要保持长期客户端状态,应用程序可以使用客户端特定的信息,例如用户输入的客户号。因为不能指望客户端总有 Cookie,所以您的应用程序必须将您定向到可做成书签的替代页。下面的示例演示一个例子。浏览到此 URL 的用户会看到一个用来输入他们的客户 ID 的窗体。然后应用程序显示一个替换 URL,用户可将该 URL 做成书签。

<%@ Page Inherits="System.Web.UI.MobileControls.MobilePage"
    Language="C#"
    EnableViewState="false" %>

<script runat="server" language="c#">
protected void Page_Load(Object sender, EventArgs e)
{
    String customerID = Request.QueryString["cid"];

    if (customerID != null)
    {
        // A customer ID was found. Simulate a lookup by 
        // converting the client ID back to a user.
        int underscore = customerID.IndexOf('_');
        if (underscore != -1)
        {
            // If visiting the first time, prompt the user to bookmark.
            if (Session["FirstTime"] != null)
            {
                Session["FirstTime"] = null;
                WelcomeLabel.Text = String.Format("Welcome, {0}", 
                customerID.Substring(0, underscore));
                ActiveForm = WelcomeForm;
            }
            else
            {
                ReturnLabel.Text = String.Format("Welcome back, {0}", 
                    customerID.Substring(0, underscore));
                ActiveForm = ReturnForm;
            }
        }
    }
}

protected void LoginForm_OnSubmit(Object sender, EventArgs e)
{
    // Generate a customer ID. Normally, you would create
    // a new customer profile.
    String customerID = CustomerName.Text + "_" + 
        System.Guid.NewGuid().ToString();
    String path = AbsoluteFilePath + "?cid=" + 
        Server.UrlEncode(customerID);
    Session["FirstTime"] = true;
    RedirectToMobilePage(path);
}
</script>

<mobile:Form runat="server">
  <mobile:Label runat="server" StyleReference="title">
    Welcome to the site. Please register to continue.
  </mobile:Label>
  <mobile:TextBox runat="server" id="CustomerName" />
  <mobile:Command runat="server" OnClick="LoginForm_OnSubmit" 
    Text="Register" />
</mobile:Form>

<mobile:Form id="WelcomeForm" runat="server">
  <mobile:Label runat="server" id="WelcomeLabel" />
    Please bookmark this page for future access.
</mobile:Form>

<mobile:Form id="ReturnForm" runat="server">
  <mobile:Label runat="server" id="ReturnLabel" />
</mobile:Form>

为移动应用程序优化视图状态

对于移动网页,以下注意事项非常重要:

  • 将视图状态保存到会话状态这一功能已经过高度优化。如果没有要保存的视图状态,则不会在会话中存储任何内容,也不会向客户端发送任何标识符。但是,想要避免使用会话管理或希望页具有高吞吐量的应用程序开发人员,可以考虑减少使用或不使用视图状态。在许多应用中(例如呈现格式化文本的页),视图状态是不必要的,最好将其关闭。

  • 除了应用程序视图状态之外,移动网页必须存储有关页的其他类型的状态信息。这些信息可能涉及活动窗体或窗体的分页情况。通常将此类信息发送到客户端而不是保存在服务器上,并且通常以优化的方式生成这些信息。例如,如果第一个窗体是活动的或者正在显示窗体的第一页,则不保存此信息,因为这些是默认状态。这样的状态信息称为私有视图状态。所有控件都可以重写 LoadPrivateViewStateSavePrivateViewState 方法以读取和写入私有视图状态。

    说明:

    安全的做法是,如果您在会话状态中包括敏感信息,则应该使用带有 HTTPS 和 SSL/TLS 身份验证的连接。

请参见

概念

ASP.NET 状态管理概述

控制会话状态

参考

LoadPrivateViewState

SavePrivateViewState

其他资源

支持视图状态

创建 ASP.NET 移动网页

应用程序开发人员指南

开发 ASP.NET 移动网页