ViewState: All You Wanted to Know

原创 2004年06月15日 15:36:00

ViewState: All You Wanted to Know

Paul Wilson
www.WilsonDotNet.com
www.ASPAlliance.com/PaulWilson

Previous Article            Page Events and PostBack            Next Article

What ViewState is Not

First, lets consider what ViewState is NOT, since there are several common misconceptions. ViewState does not help restore posted values to form controls, although this is said at times. The easiest way to see this is to disable a controls ViewState and watch its value be restored. This is done automatically for us by matching the posted form variable name with the control, although this only works for controls that are created by the time the Load event is completed. So while ASP.NET does automate the restoring of form values, this is not part of ViewState.

ViewState also does not auto-recreate any controls that were dynamically created in the code. This is actually something that many of us have discovered the hard way, since it doesnt work. Any controls that you dynamically create in your code must therefore be recreated in the code. This can be a little difficult at times to work around, especially for controls created in events, but it is doable if you keep track of whats been previously done and recreate it on each Load. ViewState can, however, be used to track this information, but we must manually code for it.

Finally, ViewState is not intended for user or session data, nor for transferring across pages. ViewState is only designed for state data related to the current page and its various controls. It does not get sent to a new page in any case, not through links, redirects, or server transfers. There may be things that you want to access on multiple pages, due to redirects or transfers, but the solutions involve using either cookies, session, or the request context, not ViewState. We will also see that ViewState is neither secure, nor always the best use of server resources.

So What is ViewState

ViewState is used to track and restore the state values of controls that would otherwise be lost, either because those values do not post with the form or because they are not in the page html. This means that a control totally defined in your page html, with no changes made in the code, will have no ViewState at all, as is often the case when using drag-n-drop with static content. Instead, ViewState only holds the values of properties that are dynamically changed somehow, usually in code, data-binding, or user interactions, so that they can be restored on each request.

So, ViewState holds properties you change in code, any data that you bind to a control in code, and any changes that occur as a result of user interactions that were triggered with a PostBack. An example of a user interaction is a user selecting a date or moving a month in the calendar, which triggers a PostBack that changes properties of the calendar to match the users request. The new date selected or month being viewed must be persisted in the calendars ViewState since these are properties that will need to be restored but which will not be posted next time.

ViewState also provides a StateBag, which is a special collection or dictionary, for each page that you can use to store any object or value, associated with a key, to retain across PostBacks. This is useful for your own custom items that are relevant to only that specific page instance, since these values will automatically post with that page, but not transfer to any other pages. One very good use of custom ViewState is to keep track of any dynamically created controls, which you can then manually recreate on each post based on your tracking data in ViewState.

And What is the Format

ViewState is by default serialized and passed across page PostBacks as a hidden form field, __VIEWSTATE, that is Base64 encoded so that it is not easily readable, but not encrypted. ViewState is by default tamper-proof, however, since a hash is applied based on machine key, although this is disabled by setting the enableViewStateMac property to false (see Listing 1). ViewState can be optionally encrypted, by setting up machineKey validation (see Listing 2), but this must be done at the machine level and it uses more resources so its not recommended.

ViewState is saved before rendering in the Page.SavePageStateToPersistenceMedium method and it is restored on PostBacks in the Page.LoadPageStateFromPersistenceMedium method. Both of these methods can be easily overridden to save ViewState to Session (see Listing 3), which is useful for low-bandwidth cases, like Mobile devices which use Session by default. Storing the ViewState in other data stores, like a database or even advanced Session modes, requires serialization and deserialization using the special LosFormatter class (see Listing 4).

Finally, lets take a look at the internal format of the ViewState object for completeness sake. Each controls ViewState is stored in a Triplet (System.Web.UI.Triplet) with the First object being a Pair (System.Web.UI.Pair), or Array or Pairs, of ArrayLists of related name-values. The Second object of the Triplet is an ArrayList of that controls child indices in control tree, and the Third object is an ArrayList of the similar associated Triplets of those child controls. Its all rather hard to describe, so look at the example and try it for yourself (see Listings 5/6).

Listing 1: ViewState Machine Hash Disabled
machine.config or web.config: <pages enableViewStateMac='false' />
page level directive:         <%@Page enableViewStateMac='false' %>
page level script code:       Page.EnableViewStateMac = false;
Listing 2: ViewState Encryption is Enabled
machine.config: <machineKey validation='3DES' validationKey='*' />
where the validationKey must be the same across a web-farm setup
also requires the enableViewStateMac property setting to be true
Listing 3: ViewState Saved in Session State
 LoadPageStateFromPersistenceMedium() {
	 Session["ViewState"];
}

 SavePageStateToPersistenceMedium( viewState) {
	Session["ViewState"] = viewState; 
	
	RegisterHiddenField("__VIEWSTATE", "");
}
Listing 4: ViewState Saved in Custom Store
 LoadPageStateFromPersistenceMedium() {
	LosFormatter format =  LosFormatter();
	 format.Deserialize(YourDataStore["ViewState"]);
}

 SavePageStateToPersistenceMedium( viewState) {
	LosFormatter format =  LosFormatter();
	StringWriter writer =  StringWriter();
	format.Serialize(writer, viewState);
	YourDataStore["ViewState"] = writer.ToString();
}
Listing 5: ViewState Decode/Parse Example
Encoded ViewState:
dDwxMjM0NTY3ODkwO3Q8cDxsPHBycEE7cHJwQjtwcnBDOz47bDx2YWxBO3ZhbEI7dmFsQzs+PjtsPGk8
MD47aTwyPjtpPDM+O2k8NT47PjtsPHQ8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+O3Q8
cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+O3Q8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2
YWxCOz4+Ozs+O3Q8cDxsPHBycEE7cHJwQjs+O2w8dmFsQTt2YWxCOz4+Ozs+Oz4+Oz4=

Decoded ViewState:
t<1234567890;t<p<l<prpA;prpB;prpC;>;l<valA;valB;valC;>>;
l<i<0>;i<2>;i<3>;i<5>;>;l<
t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;
t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;
t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;
t<p<l<prpA;prpB;>;l<valA;valB;>>;;>;>>;>

Parsed ViewState:
t<1234567890;             Page-Level Triplet is Special Case
  t<p<l<prpA;prpB;prpC;>; Triplet-First:Pair-First:ArrayList
      l<valA;valB;valC;>                Pair-Second:ArrayList
     >;
    l<i<0>;               Triplet-Second:ArrayList:Indices
      i<2>;                                        of the
      i<3>;                                        Children
      i<5>;                                        Controls
     >;
    l<t<p<l<prpA;prpB;>;  Triplet-Third:ArrayList:Triplets
          l<valA;valB;>                           of the
         >;                                       Children
       ;                                          Controls
       >;
      t<p<l<prpA;prpB;>;  Each Sub-Triplet follows same Pattern
          l<valA;valB;>   
         >;
       ;                  More Levels Possible if sub-Children
       >;
      t<p<l<prpA;prpB;>;  Each Sub-Triplet follows same Pattern
          l<valA;valB;>
         >;
       ;                  More Levels Possible if sub-Children
       >;
      t<p<l<prpA;prpB;>;  Each Sub-Triplet follows same Pattern
          l<valA;valB;>
         >;
       ;                  More Levels Possible if sub-Children
       >;
     >
   >;                     Closing of Special Page-Level Triplet
 >
Listing 6: ViewState Decode/Parse Code
 SavePageStateToPersistenceMedium( viewState) {
	
	.SavePageStateToPersistenceMedium(viewState);

	
	LosFormatter format =  LosFormatter();
	StringWriter writer =  StringWriter();
	format.Serialize(writer, viewState);
	 vsRaw = writer.ToString();
	Response.Write("ViewState Raw: " + Server.HtmlEncode(vsRaw));

	
	[] buffer = Convert.FromBase64String(vsRaw);
	 vsText = Encoding.ASCII.GetString(buffer);
	Response.Write("ViewState Text: " + Server.HtmlEncode(vsText));

	
	ParseViewState(viewState, 0);
}

 ParseViewState( vs,  level) {
	 (vs == ) {
		Trace.Warn(level.ToString(), Spaces(level) + "null");
	}
	 (vs.GetType() == (System.Web.UI.Triplet)) {
		Trace.Warn(level.ToString(), Spaces(level) + "Triplet");
		ParseViewState((Triplet) vs, level);
	}
	 (vs.GetType() == (System.Web.UI.Pair)) {
		Trace.Warn(level.ToString(), Spaces(level) + "Pair");
		ParseViewState((Pair) vs, level);
	}
	 (vs.GetType() == (System.Collections.ArrayList)) {
		Trace.Warn(level.ToString(), Spaces(level) + "ArrayList");
		ParseViewState((IEnumerable) vs, level);
	}
	 (vs.GetType().IsArray) {
		Trace.Warn(level.ToString(), Spaces(level) + "Array");
		ParseViewState((IEnumerable) vs, level);
	}
	 (vs.GetType() == (System.String)) {
		Trace.Warn(level.ToString(), Spaces(level) + "'" + vs.ToString() + "'");
	}
	 (vs.GetType().IsPrimitive) {
		Trace.Warn(level.ToString(), Spaces(level) + vs.ToString());
	}
	 {
		Trace.Warn(level.ToString(), Spaces(level) + vs.GetType().ToString());
	}
}

 ParseViewState(Triplet vs,  level) {
	ParseViewState(vs.First, level + 1);
	ParseViewState(vs.Second, level + 1);
	ParseViewState(vs.Third, level + 1);
}

 ParseViewState(Pair vs,  level) {
	ParseViewState(vs.First, level + 1);
	ParseViewState(vs.Second, level + 1);
}

 ParseViewState(IEnumerable vs,  level) {
	 ( item  vs) {
		ParseViewState(item, level + 1);
	}
}

 Spaces( count) {
	 spaces = "";
	 ( index = 0; index < count; index++) {
		spaces += "   ";
	}
	 spaces;
}

Author Bio

Paul Wilson is a software architect in Atlanta, currently with a medical device company. He specializes in Microsoft technologies, including .NET, C#, ASP, SQL, COM+, and VB. His WilsonWebForm Control allows Multiple Forms and Non-PostBack Forms in ASP.NET. He is a Microsoft MVP in ASP.NET and is also recognized as an ASPFriend's ASPAce/ASPElite. He is a moderator on Microsoft's ASP.NET Forums, as well as one of the top posters. He is certified in .NET (MCAD), as well as also holding the MCSD, MCDBA, and MCSE. Please visit his website, www.WilsonDotNet.com, or email him at Paul@WilsonDotNet.com.

解题报告 之 POJ3463 ACM Computer Factory

解题报告 之 POJ 3463 ACM Computer Factory 有陷阱 拆点
  • maxichu
  • maxichu
  • 2015年04月22日 15:20
  • 558

codeforces 508B Anton and currency you all know

B. Anton and currency you all know time limit per test 0.5 seconds memory limit per test 256 megab...
  • Tc_To_Top
  • Tc_To_Top
  • 2015年02月05日 12:26
  • 986

poj 3436 ACM Computer Factory (最大流 拆点建图 找路径)@

As you know, all the computers used for ACM contests must be identical, so the participants compete ...
  • yjf3151731373
  • yjf3151731373
  • 2017年03月13日 12:09
  • 114

拆点最大流-POJ-3436-ACM Computer Factory

ACM Computer Factory Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6674 Acce...
  • Roy_Yuan
  • Roy_Yuan
  • 2016年04月25日 19:43
  • 254

zoj 2954 Hanoi Tower(汉诺塔)

汉诺塔
  • u012860063
  • u012860063
  • 2014年03月30日 22:24
  • 1027

poj 1731 Orders(STL)

Orders Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9670   Accepte...
  • xky1306102chenhong
  • xky1306102chenhong
  • 2015年04月22日 00:02
  • 304

TCP_CORK: More than you ever wanted to know

原文地址: http://baus.net/on-tcp_cork/ TCP_CORK: More than you ever wanted to know April 6, 2005...
  • ty3219
  • ty3219
  • 2015年12月18日 10:25
  • 404

Everything You Wanted to Know About Machine Learning

Everything You Wanted to Know About Machine Learning 翻译了理解机器学习的10个重要的观点,加入了自己的理解,这些原则在大部分情况下也许是这样,...
  • yihucha166
  • yihucha166
  • 2014年06月25日 15:37
  • 1100

杭电 HDU ACM 1213 How Many Tables

How Many Tables Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)...
  • lsgqjh
  • lsgqjh
  • 2015年05月17日 20:19
  • 497

appium解决We wanted {"required":["value"]} and you sent ["text","sessionId","id","valu

如题,在mac上重新配置了appium 结果输入的时候提示 We wanted {"required":["value"]} and you sent ["text","sessionId","i...
  • dayuzhuangzhi
  • dayuzhuangzhi
  • 2017年08月01日 17:08
  • 471
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ViewState: All You Wanted to Know
举报原因:
原因补充:

(最多只允许输入30个字)