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 doesn’t 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 what’s 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 aclearcase/" target="_blank" >ccess 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, 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 user’s request. The new date selected or month being viewed must be persisted in the calendar’s 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.
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 control’s 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 control’s 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).
machine.config or web.config: <pages enableViewStateMac='false' /> page level directive: <%@Page enableViewStateMac='false' %> page level script code: Page.EnableViewStateMac = false;
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
protected override object LoadPageStateFromPersistenceMedium() { return Session["ViewState"]; } protected override void SavePageStateToPersistenceMedium(object viewState) { Session["ViewState"] = viewState; // Bug requires Hidden Form Field __VIEWSTATE RegisterHiddenField("__VIEWSTATE", ""); }
protected override object LoadPageStateFromPersistenceMedium() { LosFormatter format = new LosFormatter(); return format.Deserialize(YourDataStore["ViewState"]); } protected override void SavePageStateToPersistenceMedium(object viewState) { LosFormatter format = new LosFormatter(); StringWriter writer = new StringWriter(); format.Serialize(writer, viewState); YourDataStore["ViewState"] = writer.ToString(); }
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 >
protected override void SavePageStateToPersistenceMedium(object viewState) { // Call Base Method to Not Change Normal Process base.SavePageStateToPersistenceMedium(viewState); // Retrieve ViewState and Write Out to Page LosFormatter format = new LosFormatter(); StringWriter writer = new StringWriter(); format.Serialize(writer, viewState); string vsRaw = writer.ToString(); Response.Write("ViewState Raw: " + Server.HtmlEncode(vsRaw)); // Decode ViewState and Write Out to Page byte[] buffer = Convert.FromBase64String(vsRaw); string vsText = Encoding.ASCII.GetString(buffer); Response.Write("ViewState Text: " + Server.HtmlEncode(vsText)); // Parse ViewState -- Turn On Page Tracing ParseViewState(viewState, 0); } private void ParseViewState(object vs, int level) { if (vs == null) { Trace.Warn(level.ToString(), Spaces(level) + "null"); } else if (vs.GetType() == typeof(System.Web.UI.Triplet)) { Trace.Warn(level.ToString(), Spaces(level) + "Triplet"); ParseViewState((Triplet) vs, level); } else if (vs.GetType() == typeof(System.Web.UI.Pair)) { Trace.Warn(level.ToString(), Spaces(level) + "Pair"); ParseViewState((Pair) vs, level); } else if (vs.GetType() == typeof(System.Collections.ArrayList)) { Trace.Warn(level.ToString(), Spaces(level) + "ArrayList"); ParseViewState((IEnumerable) vs, level); } else if (vs.GetType().IsArray) { Trace.Warn(level.ToString(), Spaces(level) + "Array"); ParseViewState((IEnumerable) vs, level); } else if (vs.GetType() == typeof(System.String)) { Trace.Warn(level.ToString(), Spaces(level) + "'" + vs.ToString() + "'"); } else if (vs.GetType().IsPrimitive) { Trace.Warn(level.ToString(), Spaces(level) + vs.ToString()); } else { Trace.Warn(level.ToString(), Spaces(level) + vs.GetType().ToString()); } } private void ParseViewState(Triplet vs, int level) { ParseViewState(vs.First, level + 1); ParseViewState(vs.Second, level + 1); ParseViewState(vs.Third, level + 1); } private void ParseViewState(Pair vs, int level) { ParseViewState(vs.First, level + 1); ParseViewState(vs.Second, level + 1); } private void ParseViewState(IEnumerable vs, int level) { foreach (object item in vs) { ParseViewState(item, level + 1); } } private string Spaces(int count) { string spaces = ""; for (int index = 0; index < count; index++) { spaces += " "; } return spaces; }