Asp.net页面存储状态机制

Web 应用程序是无状态的。每次从服务器请求网页时,都会创建网页类的一个新实例。这通

常意味着在每次往返过程中将会丢失所有与该页面及其控件关联的信息.  因此页面要维持上次请求

的页面状态, 就需要用某种方式将页面状态保存起来, Asp.net 技术是用页面状态( 视图状态和控件状

态 ), 以下都简称"页面状态". 其中控件状态为Asp.net 2.0的新特性. 在有些场合, 视图状态和控件状

态是可以通用的, 但有此场合考虑到性能及其安全等因素, 要选择具体适合此场景的页面状态存储方

式.

      下面具体介绍一下页面状态的两种方式优缺点及其使用场景.

      
1.  视图状态.

        ♦ 概述:  视图状态是 ASP.NET 页框架用于保存往返过程之间的页和控件值的方法。当呈现页

的 HTML 形式时,需要在回发过程中保留的页的当前状态和值将被序列化为 Base64 编码的字符串,

并输出到视图状态的隐藏字段中, 即页面中Html源代码中的__VIEWSTATE隐藏字段.  可以存储: 字符

/整数/布尔值/Array 对象/ArrayList 对象/哈希表等数据类型.

       ♦ 视图状态优点: 

                
1. 节省服务端资源: 由于视图状态是存放到Hide字段(Html代码结构中)传送到客户端的, 因

                    为不占用服务端资源.

                
2. 使用方便: 默认已经开启视图状态(有些场合, 如控件没有注册服务端事件或者控件没有

                   动态属情况可以将视图状态关闭, 节省网络流量, 提高页面呈现速度).  

                
3. 安全方面: 视图状态通过散列码校检机制和使用3DES等加密机制来保证数据安全.

                4. 自定义存储位置:  在Load和Save方法中可以自定义其存储位置. 

       ♦ 视图状态缺点:

                
1. 性能: 由于其存储到页面Html代码结构中, 因此传输数据量大时, 会严重影响性能. 

                          可以用视图状态分块机制, 将数据分块存储, 设置MaxPageStateFieldLength 属性.

                
2. 禁用: 如果视图状态被禁用,  则无法保存页面状态. 

                
3. 安全: 虽然已经通过加密, 但由于其是呈现到客户端隐藏字段区域, 因此容易被篡改.


   
2. 控件状态

     ♦ 概述:  有时,为了让控件正常工作,您需要按顺序存储控件状态数据。例如,如果编写了一个

                 自定义控件,其中使用了不同的选项卡来显示不同的信息, 如(TabTrip/FormView等控件)

                 为了让自定义控件按预期的方式工作,该控件需要知道在往返行程之间选择了哪个选项

                 卡。可以使用 ViewState  属性来实现这一目的,然而,开发人员可以在页级别关闭视图

                 状态,从而使控件无法正常工作。为了解决此问题,ASP.NET 2.0 增加了一项新的存储

                 功能:  控件状态的功能。ControlState 属性允许您保持特定于某个控件的属性信息,且不

                 能像 ViewState 属性那样被关闭。等一下, 下面会有详细的示例演示进行测试这一点.  

                 简单地说, 当禁用视图状态时, ControlState能够完成ViewState不能够完成的任务.

      ♦ 控件状态优点:

                    
1.  节省服务端资源:  跟视图状态一样, 控件状态存储在隐藏字段中, 也不占用服务器

                         资源.

                    
2.  比视图状态更可靠: 控件状态功能推出的一重大原因就是, 当视图状态被禁用时, 

                        它依然可以有效.  (下面会有测试示例). 

                   
3.  自定义存储位置:  在Load和Save方法中可以自定义其存储位置. 

        ♦ 控件状态缺点:

                   
1. 性能: 由于其存储到页面Html代码结构中, 因此传输数据量大时, 会严重影响性能. 

                   
2. 自定义编程.  视图状态可以用System.Web.UI.StateBag类型的ViewState来存储使

                       用, 也可以自定义存储编程. 控件状态只能自定义编程.

        

(二) . 示例演示其用法

       1) .  视图状态

            代码示例使用四种不同的属性类型来演示视图状态的用法. 四种类型分别为:

                   a.  没有使用视图状态简单string类型属性

                   b.  使用视图状态的简单string类型属性

                   c.  自定义复杂类型FaceStyle的存储----存储复杂类FaceStyle内部属性

                   d.  自定义复杂类型FaceStyle的存储----存储复杂类FaceStyle继承的基类的属性

            代码中注释已经比较详细,  贴出代码:

           1.  自定义主控件测试类 ViewStateTest.cs 代码

  1  ///   <summary>
  2       ///  Author: [ ChengKing(ZhengJian) ] 
  3       ///  Blog:   Http://blog.csdn.net/ChengKing
  4       ///   </summary>
  5       ///   <summary>
  6       ///  本示例通过存储四种类型不同的属性来演示视图状态存储机制
  7       ///   </summary>
  8      [ToolboxData( " <{0}:ViewStateTest runat=server></{0}:ViewStateTest> " )]   
  9       public   class  ViewStateTest : WebControl
 10      {
 11           private   string  _text;
 12          [Bindable( true )]
 13          [DefaultValue( "" )]
 14          [Localizable( true )]
 15          [Category( " 测试视图状态 " )]
 16          [Description( " 没有使用视图状态存储 " )]
 17           public   string  Text_NoViewState
 18          {
 19               get
 20              {
 21                   return  _text;
 22              }
 23 
 24               set
 25              {               
 26                   this ._text  =  value;
 27              }
 28          }
 29        
 30          [Bindable( true )]        
 31          [DefaultValue( "" )]
 32          [Localizable( true )]
 33          [Category( " 测试视图状态 " )]
 34          [Description( " 使用ViewState属性来存储数据此属性 " )]
 35           public   string  Text_ViewState
 36          {
 37               get
 38              {
 39                  String s  =  (String)ViewState[ " Text_ViewState " ];
 40                   return  ((s  ==   null ?  String.Empty : s);
 41                  
 42              }
 43 
 44               set
 45              {
 46                  ViewState[ " Text_ViewState " =  value;
 47                 
 48              }
 49          }      
 50          
 51           private  FaceStyle _faceStyle;
 52          [PersistenceMode(PersistenceMode.InnerProperty)]
 53          [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 54          [NotifyParentProperty( true )]
 55          [Category( " 测试视图状态 " )]
 56          [Description( " 自定义视图状态(实现IStateManager接口)存储此属性 " )]
 57           public  FaceStyle 皮肤样式_CustomViewState
 58          {
 59               get
 60              {
 61                   if  (_faceStyle  ==   null )
 62                  {
 63                      _faceStyle  =   new  FaceStyle();                    
 64                  }
 65 
 66                   if  (IsTrackingViewState)
 67                  {
 68                      ((IStateManager)_faceStyle).TrackViewState();
 69                  }                     
 70                 
 71                   return  _faceStyle;
 72              }
 73          }
 74 
 75           protected   override   void  RenderContents(HtmlTextWriter output)
 76          {
 77               if  (DesignMode)
 78              {
 79                  output.Write( " [自定义视图状态存储示例控件] " );
 80              }
 81          }
 82 
 83           protected   override   void  CreateChildControls()
 84          {
 85               base .CreateChildControls();
 86          }
 87 
 88           protected   override   void  Render(HtmlTextWriter writer)
 89          {
 90               base .Render(writer);                
 91          }
 92          
 93           protected   override   object  SaveViewState()
 94          {
 95              Pair p  =   new  Pair(); 
 96              p.First  =   base .SaveViewState();
 97              p.Second  =  ((IStateManager)皮肤样式_CustomViewState).SaveViewState(); 
 98               for  ( int  i  =   0 ; i  <   2 ; i ++ )
 99              {
100                   if  (p.First  !=   null   ||  p.Second  !=   null )
101                  {
102                       return  p;
103                  }
104              }
105               return   null ;
106          }
107 
108           protected   override   void  LoadViewState( object  savedState)
109          {
110               if  (savedState  ==   null )
111              {
112                   base .LoadViewState( null );
113                   return ;
114              }
115               else
116              {
117                  Pair p  =  (Pair)savedState;
118                   if  ( p  ==   null  )
119                  {
120                       throw   new  ArgumentException( " 无效的 View State 数据! " );
121                  }
122                   base .LoadViewState(p.First);
123                   if  (p.Second  !=   null )
124                  {
125                      ((IStateManager)皮肤样式_CustomViewState).LoadViewState(p.Second);
126                  }
127              }           
128          }
129      }

           2. 自定义复杂类 FaceStyle.cs 代码

 1  ///   <summary>
 2       ///  Author: [ ChengKing(ZhengJian) ] 
 3       ///  Blog:   Http://blog.csdn.net/ChengKing
 4       ///   </summary>
 5       ///   <summary>
 6       ///  一个复杂的数据类型类定义
 7       /// </summary>
 8      public   class  FaceStyle : TableItemStyle, IStateManager
 9      {
10           #region  类变量
11 
12           private   bool  _blnOK;
13 
14           #endregion
15 
16           #region  构造函数
17 
18           public  FaceStyle()
19          {
20              _blnOK  =   false ;
21          }
22 
23           #endregion
24 
25           #region  属性
26         
27          [Browsable( true )]
28          [Description( " 自定义类测试变量 " )]
29           public   bool  OK
30          {
31               get
32              {
33                   return  _blnOK;
34              }
35               set
36              {
37                  _blnOK  =  value;
38              }
39          }
40 
41          
42           bool  IStateManager.IsTrackingViewState
43          {
44               get
45              {
46                   return   base .IsTrackingViewState;
47              }
48          }
49 
50           #endregion
51 
52           #region  方法
53 
54 
55           // 从当前点开始, 此控件具有保存视图状态功能       
56           void  IStateManager.TrackViewState()
57          {
58               base .TrackViewState();
59          }
60 
61         
62           object  IStateManager.SaveViewState()
63          {
64               object [] state  =   new   object [ 2 ];
65              state[ 0 =   base .SaveViewState();            
66              
67              state[ 1 =  ( object )OK;
68 
69               // 状态管理会存储此返回的值; 另外此方法返回值还有个用途: 创建复合控件时取得各个子控件的视图状态时使用
70               return  state;
71          }
72 
73         
74           void  IStateManager.LoadViewState( object  state)
75          {
76               if  (state  ==   null )
77              {
78                   return ;
79              }
80               object [] myState  =  ( object [])state;
81               base .LoadViewState(myState[ 0 ]);
82 
83              OK  =  ( bool )myState[ 1 ];                
84          }
85 
86           #endregion
87      }

           3. 测试页面 Default.aspx.cs 代码

 1  ///   <summary>
 2  ///  Author: [ ChengKing(ZhengJian) ] 
 3  ///  Blog:   Http://blog.csdn.net/ChengKing
 4  ///   </summary>
 5  public  partial  class  _Default : System.Web.UI.Page 
 6  {
 7       protected   void  Page_Load( object  sender, EventArgs e)
 8      {
 9           // 禁用页面视图状态测试
10           // Page.EnableViewState = false;
11 
12           // 禁用控件视图状态测试
13           // this.ViewStateTest1.EnableViewState = false;
14          
15      }
16       protected   void  btnSetProperty_Click( object  sender, EventArgs e)
17      {
18           /// 设置没有用视图状态存储的属性值
19           this .ViewStateTest1.Text_NoViewState  =   " 我没有用任何视图状态存储! " ;
20 
21           /// 设置用ViewState存储的属性值
22           this .ViewStateTest1.Text_ViewState  =   " 我是用ViewState容器存储的! " ;
23 
24           // 设置用自定义视图状态存储的属性值
25           this .ViewStateTest1.皮肤样式_CustomViewState.OK  =   true ;
26           this .ViewStateTest1.皮肤样式_CustomViewState.BackColor  =  System.Drawing.Color.LightPink;
27      }
28       protected   void  btnRefresh_Click( object  sender, EventArgs e)
29      {
30           ///   <summary>
31           ///  ViewState容器存储测试--测试存储ViewStateTest1.Text_NoViewState属性
32           ///   </summary>
33           if  ( this .ViewStateTest1.Text_NoViewState  ==   " 我没有用任何视图状态存储! " )
34          {
35               this .lbDisplay.Text  =   " this.ViewStateTest1.Text_NoViewState属性 已经保存了视图状态, :)<br><br> " ;
36          }
37           else
38          {
39               this .lbDisplay.Text  =   " this.ViewStateTest1.Text_NoViewState属性 没有保存视图状态, :(<br><br> " ;
40          }
41 
42 
43           ///   <summary>
44           ///  ViewState容器存储测试--测试存储ViewStateTest1.Text_ViewState属性
45           ///   </summary>
46           if  ( this .ViewStateTest1.Text_ViewState  ==   " 我是用ViewState容器存储的! " )
47          {
48               this .lbDisplay.Text  +=    " this.ViewStateTest1.Text_ViewState属性 已经保存了视图状态, :)<br><br> " ;
49          }
50           else
51          {
52               this .lbDisplay.Text  +=   " this.ViewStateTest1.Text_ViewState属性 没有保存视图状态, :(<br><br> " ;
53          }
54          
55 
56           ///   <summary>
57           ///  自定义视图状态测试--测试存储类ViewStateTest1.FaceStyle的内部属性OK
58           ///   </summary>
59           if  ( this .ViewStateTest1.皮肤样式_CustomViewState.OK  ==   true )
60          {
61               this .lbDisplay.Text  +=   " this.ViewStateTest1.皮肤样式_CustomViewState属性.OK 已经保存了视图状态, :)<br><br> " ;
62          }
63           else
64          {
65               this .lbDisplay.Text  +=   " this.ViewStateTest1.皮肤样式_CustomViewState属性.OK 没有保存视图状态, :(<br><br> " ;
66          }
67 
68 
69           ///   <summary>
70           ///  自定义视图状态测试--测试存储类ViewStateTest1.FaceStyle的基类TableItemStyle中的属性BackColor
71           ///   </summary>
72           if  ( this .ViewStateTest1.皮肤样式_CustomViewState.BackColor  ==  System.Drawing.Color.LightPink)
73          {
74               this .lbDisplay.Text  +=   " this.ViewStateTest1.皮肤样式_CustomViewState.BackColor 已经保存了视图状态, 瞧,我自己的颜色就是保存的颜色, :) " ;
75               this .lbDisplay.BackColor  =  System.Drawing.Color.LightPink;
76          }
77           else
78          {
79               this .lbDisplay.Text  +=   " this.ViewStateTest1.皮肤样式_CustomViewState.BackColor 没有保存视图状态, 瞧,我的颜色还是白色, :( " ;
80          }
81      }
82  }

           4. 测试方案  

               a.  下载示例代码后, 直接Ctrl + F5运行. 点"刷新"按钮button,  这时由于没有设置给控件值,

                    会显示如下页面:

                   

                b. 点击另一个按钮 "设置控件属性",  然后点击刷新按钮, 刷新页面, 这里视图状态已经保存了.

                    会出现如下图:

                   

                   可以看到,  四种不同的类型只有第一种没有被存储到视图中.  因为第一种属性类型没有启用视图.

                  c.  将 Default.aspx.cs中Page_Load事件中的两行代码

                        //禁用页面视图状态测试
                        //Page.EnableViewState = false;

                       //禁用控件视图状态测试
                       //this.ViewStateTest1.EnableViewState = false;

                      任意移除一个注释语句, 再Ctrl+F5运行,  并按步骤 b 操作,  会出现以下运行结果:

                      

                     表示四种类型的属性没有被视图存储, 很显然是因为Default.aspx.cs 中Page_Load中的代码禁

                     用了视图功能.  所以四种属性类型没有存储. 如果当页面禁用了视图状态, 但要求其属性类型

                     一定要存储怎么办? 这就要用到控件状态了,  下面就演示一下控件状态的用法.

      2) .  控件状态

           代码中注释也比较详细,  贴出代码:

           1.  自定义主控件测试类 ControlStateTest.cs 代码

 1  ///   <summary>
 2       ///  Author: [ ChengKing(ZhengJian) ] 
 3       ///  Blog:   Http://blog.csdn.net/ChengKing
 4       ///   </summary>
 5      [DefaultProperty( " Text " )]
 6      [ToolboxData( " <{0}:ControlStateTest runat=server></{0}:ControlStateTest> " )]
 7       public   class  ControlStateTest : WebControl
 8      {
 9           private   string  _Text;
10 
11          [Bindable( true )]
12          [Category( " Appearance " )]
13          [DefaultValue( "   " )]
14          [Localizable( true )]
15          [Description( " 测试用控件状态存储此属性值 " )]
16           public   string  Text_ControlState
17          {
18               get
19              {
20                   if  (_Text  !=   null )
21                  {
22                       return  _Text.Trim();
23                  }
24                   return  _Text;
25              }
26 
27               set
28              {
29                  _Text  =  value;
30              }
31          }
32 
33           protected   override   void  RenderContents(HtmlTextWriter output)
34          {
35               if  (DesignMode)
36              {
37                  output.Write( " [自定义控件状态存储示例控件] " );
38              }
39          }
40 
41           ///   <summary>
42           ///  由于在回发事件的过程中,控件状态的注册无法在请求之间进行传递,因此使用
43           ///  控件状态的自定义服务器控件必须对每个请求调用RegisterRequiresControlState
44           ///  方法
45           ///   </summary>
46           ///   <param name="e"></param>
47           protected   override   void  OnInit(EventArgs e)
48          {
49               base .OnInit(e);
50              Page.RegisterRequiresControlState( this );
51          }
52 
53           protected   override   object  SaveControlState()
54          {
55               object  obj  =   base .SaveControlState();
56 
57               if  (Text_ControlState  !=   null )
58              {
59                   if  (obj  !=   null )
60                  {
61                       return   new  Pair(obj, Text_ControlState);
62                  }
63                   else
64                  {
65                       return  Text_ControlState;
66                  }
67              }
68               else
69              {
70                   return  obj;
71              }
72 
73          }
74 
75           protected   override   void  LoadControlState( object  savedState)
76          {
77               if  (savedState  !=   null )
78              {
79                  Pair p  =  savedState  as  Pair;
80                   if  (p  !=   null )
81                  {
82                       base .LoadControlState(p.First);
83                      Text_ControlState  =  ( string )p.Second;
84                  }
85                   else
86                  {
87                       if  (savedState  is   string )
88                      {
89                          Text_ControlState  =  ( string )savedState;
90                      }
91                       else
92                      {
93                           base .LoadControlState(savedState);
94                      }
95                  }
96              }
97 
98          }
99      }

           2.  页面测试类Default.aspx.cs代码

 1  ///   <summary>
 2  ///  Author: [ ChengKing(ZhengJian) ] 
 3  ///  Blog:   Http://blog.csdn.net/ChengKing
 4  ///   </summary>
 5  public  partial  class  _Default : System.Web.UI.Page 
 6  {
 7       protected   void  Page_Load( object  sender, EventArgs e)
 8      {
 9           // 禁用页面的视图状态
10           // Page.EnableViewState = false;
11 
12           // 禁用控件的视图状态
13           // this.ControlStateTest1.EnableViewState = false;
14      }
15       protected   void  btnSetProperty_Click( object  sender, EventArgs e)
16      {
17           // 设置控件的属性
18           this .ControlStateTest1.Text_ControlState  =   " 我被设置了值 " ;
19      }
20       protected   void  btnRefresh_Click( object  sender, EventArgs e)
21      {
22           if  ( this .ControlStateTest1.Text_ControlState  ==   " 我被设置了值 " )
23          {
24               this .lblDisplay.Text  =   " this.ControlStateTest1.Text_ControlState属性 已经保存了控件状态, :)<br><br> " ;
25               this .lblDisplay.BackColor  =  System.Drawing.Color.LightPink;
26          }
27           else
28          {
29               this .lblDisplay.Text  =   " this.ControlStateTest1.Text_ControlState属性 没有保存控件状态, :(<br><br> " ;
30          }
31      }

            3. 测试方案

                     a.  下载示例代码, 按Ctrl+F5运行, 点击 "设置控件属性", 再点击"刷新"按钮, 刷新页面, 会出现

                          如下页面:

                         

                          表示控件状态成功存储.

                    b.  同样把Default.aspx.cs中Page_Load事件中的注释代码, 去掉注释

                          //禁用页面的视图状态
                          //Page.EnableViewState = false;

                         //禁用控件的视图状态
                         //this.ControlStateTest1.EnableViewState = false;

                        再按步骤 a 运行, 会发现如下运行结果:

                       

                        控件状态仍然被存储, 到现在为止已经测试成功,  即使视图状态被禁用的情况下, 控件

                        状态也能够起效. 

                 c.  把 主控件代码中的 这句: Page.RegisterRequiresControlState(this); 这句代码注释掉, 如下:

                      47         protected override void OnInit(EventArgs e)
                      48         {
                      49             base.OnInit(e);
                      50             //Page.RegisterRequiresControlState(this);//注释掉这句
                      51         }

                      再运行, 会发现控件状态会失效, 这是因为:

                          由于在回发事件的过程中,控件状态的注册无法在请求之间进行传递,因此使用
                          控件状态的自定义服务器控件必须对每个请求调用RegisterRequiresControlState
                          方法.


         好了, 页面状态就讲这么多.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值