ASP.NET ViewState

ASP.NET ViewState 初探

1. ViewState的工作原理

    ViewState是由ASP.NET页面框架管理的一个隐藏的窗体字段。当ASP.NET执行某个页面时,该页面上的ViewState值和所有控件将被收集并给和格式化成一个编码字符串,然后分配给隐藏窗体字段的值属性(即<input type=”hidden”>)。由于隐藏窗体字段是发送到客户端的页面的一部分,所以ViewState值被临时存储在客户端的浏览器中。如果客户端选择该页面回传给服务器,则ViewState字符串也将被回传。回传后,ASP.NET页面框架将解析ViewState字符串,并为该页面和各个控件填充ViewState属性。然后,控件再使用ViewState数据将自己重新恢复为以前的状态。

2.  关于ViewState要注意的问题

1、如果要使用ViewState,则在ASPX页面中必须有一个服务器端窗体标记(<form     runat="server">)。窗体字段是必需的,这样包含ViewState信息的隐藏字段才能回传给服务 器。而且,该窗体还必须是服务器端的窗体,这样在服务器上执行该页面时,ASP.NET页面  框架才能添加隐藏的字段。

2、页面本身将20字节左右的信息保存在ViewState中,用于在回传时将PostBack数据和ViewState值分发给正确的控件。因此,即使该页面或应用程序禁用了ViewState,仍可以在ViewState中看到少量的剩余字节。

3、在页面不会传得情况下,可以通过省略服务器端的<form>标记来去掉页面中的ViewState

3.  充分利用ViewState

ViewState为跨回传跟踪控件的状态提供了一条神奇的路径,因为它不使用服务器资源、不会超时,并且适用任何浏览器。

ViewState的创建和使用:

     //保存在ViewState

     ViewState["SortOrder"] = "DESC";

     //ViewState中读取

 string sortOrder = (string)ViewState["SortOrder"];

代码如下:

Default3.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default3.aspx.cs" Inherits="Default3" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>无标题页</title>

</head>

<body>

    <form id="form1" runat="server">

        <h3>

            ViewState 中存储非控件状态

        </h3>

        <p>

            此示例将一列静态数据的当前排序顺序存储在 ViewState 中。<br />

            单击列标题中的链接,可按该字段排序数据。<br />

            再次单击该链接,将按相反顺序排序。</p>

        <p>

            <asp:GridView ID="GridView1" runat="server" BackColor="White" BorderColor="#3366CC"

                BorderStyle="None" BorderWidth="1px" CellPadding="4" AllowSorting="True" OnSorting="GridView1_Sorting">

                <FooterStyle BackColor="#99CCCC" ForeColor="#003399" />

                <RowStyle BackColor="White" ForeColor="#003399" />

                <SelectedRowStyle BackColor="#009999" Font-Bold="True" ForeColor="#CCFF99" />

                <PagerStyle BackColor="#99CCCC" ForeColor="#003399" HorizontalAlign="Left" />

                <HeaderStyle BackColor="#003399" Font-Bold="True" ForeColor="#CCCCFF" />

            </asp:GridView>

            &nbsp;</p>

    </form>

</body>

</html>

 

Default3.aspx.cs

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

 

public partial class Default3 : System.Web.UI.Page

{

      protected void Page_Load(object sender, EventArgs e)

      {

           if (!this.IsPostBack)

           {

            BindGrid();

           }

       }

 

      string SortField

      {

 

          get

          {

                object o = ViewState["SortField"];

               if (o == null)

               {

                return String.Empty;

               }

                return (string)o;

           }

 

           set

          {

              if (value == SortField)

               {

                    // 与当前排序文件相同,切换排序方向

                    SortAscending = !SortAscending;

              }

               ViewState["SortField"] = value;

          }

    }

 

    // ViewState 中跟踪 SortAscending 属性

    bool SortAscending

    {

 

        get

        {

            object o = ViewState["SortAscending"];

            if (o == null)

            {

                return true;

            }

            return (bool)o;

        }

 

        set

        {

            ViewState["SortAscending"] = value;

        }

    }

 

    void BindGrid()

    {

 

        // 获取数据

        DataSet ds = new DataSet();

        ds.ReadXml(Server.MapPath("TestData.xml"));

 

        DataView dv = new DataView(ds.Tables[0]);

 

        // 应用排序过滤器和方向

        dv.Sort = SortField;

        if (!SortAscending)

        {

            dv.Sort += " DESC";

        }

 

        // 绑定网格

        this.GridView1.DataSource = dv;

        this.GridView1.DataBind();

    }

    protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)

    {

        this.GridView1.PageIndex = 0;

        SortField = e.SortExpression;

        BindGrid();

    }

}

Testdata.xml

<?xml version="1.0" encoding="utf-8" ?>

<NewDataSet>

  <Table>

    <pub_id>0736</pub_id>

    <pub_name>New Moon Books</pub_name>

    <city>Boston</city>

    <state>MA</state>

    <country>USA</country>

  </Table>

  <Table>

    <pub_id>0877</pub_id>

    <pub_name>Binnet &amp; Hardley</pub_name>

    <city>Washington</city>

    <state>DC</state>

    <country>USA</country>

  </Table>

  <Table>

    <pub_id>1389</pub_id>

    <pub_name>Algodata Infosystems</pub_name>

    <city>Berkeley</city>

    <state>CA</state>

    <country>USA</country>

  </Table>

  <Table>

    <pub_id>1622</pub_id>

    <pub_name>Five Lakes Publishing</pub_name>

    <city>Chicago</city>

    <state>IL</state>

    <country>USA</country>

  </Table>

  <Table>

    <pub_id>1756</pub_id>

    <pub_name>Ramona Publishers</pub_name>

    <city>Dallas</city>

    <state>TX</state>

    <country>USA</country>

  </Table>

  <Table>

    <pub_id>9901</pub_id>

    <pub_name>GGG&amp;G</pub_name>

    <city>Muenchen</city>

    <country>Germany</country>

  </Table>

  <Table>

    <pub_id>9952</pub_id>

    <pub_name>Scootney Books</pub_name>

    <city>New York</city>

    <state>NY</state>

    <country>USA</country>

  </Table>

  <Table>

    <pub_id>9999</pub_id>

    <pub_name>Lucerne Publishing</pub_name>

    <city>Paris</city>

    <country>France</country>

  </Table>

</NewDataSet>

4.  选择会话状态还是ViewState

在某些情况下,状态值保存在ViewState中部是最佳选择,最常用的替代方法就是会话状态,它通常更适用于:

1、大量的数据:由于 ViewState 增加了发送到浏览器的页面的大小(HTML 有效负载),   同时也增加了回传的窗体的大小,因此不适合存储大量数据。

2、未在UI中显示的安全数据:尽管ViewState数据已被编码,并且可以选择对其进行加密,但始终不将数据发送到客户端才是最安全的,因此,会话是更安全的选择。(由于数据库学要额外的凭据进行验证,因此将数据存储在数据库中会更安全。可以添加SSL以获得更安全的链接。)但是,如果在UI中已经显示了该专用数据,那么您应该已经确认了链接的安全性。在这种情况下,将同样的值放入ViewState不会降低安全性。

3、尚未序列化到ViewState中的对象,如DataSetViewState序列化程序只为一小部分常用的对象类型进行了优化,其他可序列化的类型或许可以保留在ViewState中,但速度会变慢,并会生成一个非常大的ViewState

比较项

会话状态

ViewState

是否适用服务器资源

是否超时

是,20分钟后(默认)

是否存储所有.NET类型

否,仅支持:stingintboolArrayArrayListHashtable和自定义TypeConverter

是否增加“HTML有效负担”

 

5.  使用ViewState获得最佳性能

使用ViewState时,每个对象都必须先序列化到ViewState中,然后再通过回传进行反序列化,因此使用ViewState并非是没有代价的。但是,如果遵循某些简单的原则对ViewState的成本加以控制,并通常不会产生明显的性能影响。

1、  在不需要时禁用ViewState

2、  使用优化过的ViewState序列化程序,上面列出的类型具有专门的序列化程序,这些程序运行速度很快,并已经过优化,可以生成很小的ViewState。如果要序列化一个未在上面列出的类型,可以创建一个自定义TypeConverter来显著提高它的性能。

3、  尽量减少使用对象,如果可能,尽量减少放入ViewState中的对象的数目。例如,不要使用尔维数组(名称/值,其对象的数目与数组的长度一样多),而应适用二个字符串数组(只有两个对象)。但是,在将二个已知类型存储在ViewState中之前,在这两者之间转换不会获得不会获得任何性能提高,因为这样做实际上相当于付出了两次转换的代价。

6.  减少使用ViewState

默认情况下,ViewState将被启用,并且是由每个控件(而非页面开发人员)来决定存储在viewState中的内容。有时,这一信息对应程序并没有什么用处。尽管也没什么害处,但却会明显增加发送到浏览器的页面的大小。因此如果不需要使用viewState,最好还是将它关闭,特别是当ViewState很大的时候。

可以基于每个控件、每个页面或每个应用程序来关闭ViewState。在以下情况下不再需要ViewState

页面

控件

页面不回传给自身

处理的不是控件地事件

控件没有动态的或数据邦定的属性值(或对于每一个请求他们都设置在代码中)

关闭ViewState例子:

Default4.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default4.aspx.cs" Inherits="Default4" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>减少页面的HTML 有效负载</title>

</head>

<body>

    <form id="form1" runat="server">

        <h3>

            通过禁用 ViewState 来减少页面的HTML 有效负载

        </h3>

        <p>

            <asp:GridView ID="GridView" runat="server" BackColor="White" BorderColor="#3366CC" BorderStyle="None" BorderWidth="1px" CellPadding="4" EnableViewState="False">

                <FooterStyle BackColor="#99CCCC" ForeColor="#003399" />

                <RowStyle BackColor="White" ForeColor="#003399" />

                <SelectedRowStyle BackColor="#009999" Font-Bold="True" ForeColor="#CCFF99" />

                <PagerStyle BackColor="#99CCCC" ForeColor="#003399" HorizontalAlign="Left" />

                <HeaderStyle BackColor="#003399" Font-Bold="True" ForeColor="#CCCCFF" />

           

            </asp:GridView>

        </p>

    </form>

</body>

</html>

Default4.aspx.cs

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

 

public partial class Default4 : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        DataSet ds = new DataSet();

        ds.ReadXml(Server.MapPath("testdata.xml"));

        this.GridView.DataSource = ds;

        this.GridView.DataBind();

    }

}

7.  禁用ViewState

在上述事例中,我通过将网络的EnableViewState属性设置为false禁用了ViewState。可以针对单个控件、整个页面或整个应用程序禁用ViewState,如下所示:

每个控件(在标记上)

<asp:GridView EnableViewState=”false”/>

在页面(在指令中)

<%@Page EnableViewState=”false”%>

每个应用程序(在web.config中)

<Pages EnableViewState=”false”/>

 

8.  使用ViewState更安全

由于ViewState没有被格式化为清晰的文本,某些人有时会认为它被加密了,其实并没有。相反,ViewState只是进行了Base64编码,以确保值在返回过程中不会发生变化,而且不考虑应用程序使用的相应/请求编码。可以向应用程序中添加2ViewState安全级别:1、防篡改;2、加密。

1、  防篡改

尽管散列代码不能确保ViewState字段中实际数据的安全,但它能够显著降低有人通过ViewState骗过应用程序的可能性,即防止回传应用程序通常禁用输入的值。

可以通过设置EnableViewStateMac属性来显示ASP.NETViewState字段中追加一个散列代码:

<%@ Page EnableViewStateMac="true" %>

可以在页面级上设置EnableViewStateMac,也可以在应用程序级别上设置。在回传时,ASP.NET将为ViewState数据生成一个散列代码,并将其与存储在回传值中的散列代码进行比较。如果两处的散列代码不匹配,该ViewState数据将被丢弃,同时控件将恢复为原来的设置。

默认情况下,ASP.NET使用SHA1算法来生成ViewState散列代码,此外,也可以通过在machine.config文件中设置<machineKey>来选择MD5算法,如下所示:<machineKey validation="MD5" />

2、  加密

    可以使用加密来保护ViewState字段中的实际数据值。首先,必须设置:EnableViewState=”true”,然后,将machineKey validation类型设置为3DES。这个指示ASP.NET使用Triple DES对称加密算法来加密ViewState值。<machineKey validation=”3DES”/>

9.  Web领域中的ViewState安全性

默认情况下,ASP.NET将创建一个随机的验证钥匙,并存储在每个服务器的本地安全授权(LSA)中。要验证在另一台服务器上创建的ViewState字段,两台服务器的validationKey必须设置为相同的值。如果通过上述方式之一,对运行Web领域配置中的应用程序进行ViewState安全设置,则需要为所有服务器提供一个唯一的、共享的验证密钥。

Default5.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default5.aspx.cs" Inherits="Default5" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>无标题页</title>

</head>

<body>

    <form id="form1" runat="server">

        <h3>生成随机加密密钥</h3>

        <p>

            <asp:RadioButtonList ID="RadioButtonList" runat="server" RepeatDirection="horizontal">

                <asp:ListItem Value="40">40-byte</asp:ListItem>

                <asp:ListItem Value="128" Selected="True">128-byte</asp:ListItem>

            </asp:RadioButtonList>

            <asp:Button ID="Button" runat="server" Text="生成密钥" OnClick="Button_Click" />

        </p>

        <p>

            <asp:TextBox ID="TextBox" runat="server" TextMode="multiLine" Rows="10" Columns="70" BackColor="#EEEEEE" EnableViewState="false">

                复制并粘贴生成的结果

            </asp:TextBox>

        </p>

    </form>

</body>

</html>

Default5.aspx.cs

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using System.Security.Cryptography;

using System.Text;

 

public partial class Default5 : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

 

    }

    protected void Button_Click(object sender, EventArgs e)

    {

        int keylength = Int32.Parse(this.RadioButtonList.SelectedItem.Value);

        //在此处放入用于初始化页面的用户代码

        byte[] buff = new byte[keylength / 2];

        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        //该数组已使用密码增强的随机字节进行填充

        rng.GetBytes(buff);

        StringBuilder sb = new StringBuilder(keylength);

        for (int i = 0; i < buff.Length; i++)

        {

            sb.Append(string.Format("{0:X2}", buff[i]));

        }

        this.TextBox.Text = sb.ToString();

    }

}

 

10.   总结:

ASP.NET ViewState是一种新的状态服务,可供开发人员基于每个用户来跟踪UI状态。ViewState是在一个隐藏的窗体字段中来回传递状态,并将它直接应用于页面处理框架中。但效果却非常好,在基于Web的窗体中只需要编写并维护很少的代码。

 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值