ViewState improvements in Whidbey

A bit about the new control state feature and view state serializer improvements in Whidbey, that should help go a long ways into minimizing view state on aspx pages.
Jeff posted about 9K worth of view state from an aspx page. Quite rightly described as "Uhhhhhhhhhhggggggggggggggggg!"

I am not going to extol the benefits of view state other than to summarize it as the price one pays to create the illusion of a stateful programming model in a stateless environment. Instead, I am going to talk of what's coming in Whidbey.

Couple of things to keep in mind: Turn off view state when its not needed and secondly ask yourself if its cheaper to requery the database or cache the queried data and data-bind on each request instead of using view state (data controls by their very nature generate significant view state).

Some controls however would be fundamentally broken when view state is turned off, and require careful programming by page developers. In Whidbey, we introduced a new concept, "Control State," that represents the minimal and essential state of a control. For example, SelectedIndex in a ListBox is an essential bit of information. You could re-databind the ListBox each request if fetching the data is cheap, but you would loose the selection state without state management. Control state allows a control to intelligently split their state into what is absolutely required and what is not. Control state is an opt-in model, so controls such as Literals don't contribute to view state simply by their existence. The idea is that control state should not get too large. Note that it cannot be turned off like view state. The intent is to allow the developer to turn off view state, but allow their pages to continue working.

The next thing I wanted to point out are the serialization improvements in Whidbey. For some time, we debated turning off view state by default; My own opinion was that we didn't need to make that drastic a change. View state (and control state) serialization now uses a new mechanism implemented in ObjectStateFormatter instead of using LosFormatter (the latter still available for compatibility reasons). Looking at my now rather ancient checkin mail, the new serializer serializes the same object graph into roughly half the size, and spends about half as much time in the serialization and deserialization process. What changed?

No more text: LosFormatter wrote to a TextWriter; ObjectStateFormatter writes to a BinaryWriter. This by itself doesn't do much, other than it enables a some other improvements.

Token-based approach: LosFormatter wrote out strings to represent data types and embedded the data within <, > brackets. None of that anymore. ObjectStateFormatter capitalizes on the underlying binary model, and writes out a byte representing the following data, and then the data.

No more strings: The old formatter converted everything to strings (numbers, booleans etc.) to write into the TextWriter. The new one writes out bytes. This saves the cost of converting to and from a string.

More compact storage: Integers are stored as 7-bit encoded numbers. So most of them (values 0 - 255) just take a single byte instead of 4. In the case of booleans, there are simply two boolean-type tokens: a true one and a false one, so there is no additional cost to storing boolean data. DateTime is also special cased. Just the TickCount is saved, which by the way isn't lossy as the string version is.

Indexing of strings: Lets say you had a DataGrid with a 100 cells. You'd have the word "Text" in view state a 100 times! This came from the Text property of TableCell. The StateBag type (that is used for ViewState) now saves property names using IndexedString. The ObjectStateFormatter special cases this type (like Pair and Triplet) to build a running table of strings. Each time a string is reused, it simply saves out a token referring to an IndexedString, and the index within this running table.


For control developers...
First look at control state, and use it judiciously. Think about your control's scenarios, and how it should work with view state disabled. Think about the state you absolutely need to carry around, and place that into control state in as compact a form as you can use.

Also, always package state information using the types special cased and optimized by the serializer (which primitive types, String, DateTime, Color, Pair, Triplet, IndexedString, arrays, ArrayLists, Hashtables, HybridDictionaries of these types). If the type isn't optimized, ObjectStateFormatter tries to find a TypeConverter that can convert to/from a string, but I would advise staying away from this. This is because it needs to store not only the converted string, but also the full (and long) assembly-qualified type name to be able to use the appropriate type converter during deserialization. The way to handle complex types is to break their state into simpler bits typically using Pair, Triplet or object arrays. The same requirement of storing type information also applies to enumeration values. If you know before hand that you are going to save an enumeration into view state in the mainline case for your control, save it as an integer and cast it to/from the enumeration type in your property accessors.

By the way, this same serializer is used for saving personalization information for Web Parts. So the same rules apply to it.
Posted on Sunday, 6/27/2004 @ 9:58 PM | #ASP.NET


Comments

13 comments have been posted.

Luis Angel

Posted on 6/28/2004 @ 7:35 AM
I can't believe that nobody have nothing to comment to this yet!, so I'll be the first 8:)
Very interesting (and clever) theese optimizations in viewstate. I think it's very easy to come with a huge viewstate right now, with only putting some controls in page (and not talking about DataGrid). This will be a very important improvement in ASP.NET v2
Do you (or anyone else in your group) plan to write an MSDN article about this in the near future? I'm really interested about the details.
How will Control State be affected by setting enableViewState = False at page level? and at web.config level?

Aaron

Posted on 6/28/2004 @ 9:17 AM
Will ControlState be serialized to the page in the same way? __CONTROLSTATE or some such? Just curious.

Nikhil Kothari

Posted on 6/28/2004 @ 9:56 AM
Control state is merged into view state (whether it exists or not) and persisted into the same __VIEWSTATE hidden variable. We decided not to invent a new variable because a) we depend on __VIEWSTATE anyway to detect post-back and b) its cheaper to combine them and serialize them together, so we don't incur the overhead of the serializer twice. For Luis' question - no planned article yet, though I am sure someone will pick this subject to write on. Disabling view state has no effect on control state. It is always enabled so controls can depend on it to save their essential state.

Kevin Dente

Posted on 6/28/2004 @ 10:30 AM
One of the trickier aspects of composite control authoring is ASP.NET is the dependency on the order than controls are added when restoring viewstate. Still an issue in v2, I assume?

Also, is there clear documentation about what the MS controls use for control state vs viewstate? Seems like that would be important for building composite controls that behave correctly.

Eric Newton

Posted on 6/30/2004 @ 4:57 PM
I'm glad the difference between VIEWSTATE and CONTROLSTATE has been formalized... it always annoyed me when I wanted to turn off DataGrid viewstate but then lost a lot more than I'd gain... ;-)

Derek White

Posted on 6/30/2004 @ 7:26 PM
I am glad to hear that improvements have been made to Viewstate in Whidbey, but I still don't understand why ViewState is turned on by default at least in most controls. I understand why it would be on by default in DataGrids or list controls, but it seems senseless for it to be on by default on things such as labels, image controls, and basically all HtmlControls. I work on a web site that loads a lot of user controls dynamically from configuration files and the entire site is translated into multiple languages. As a result, we have a lot of server-side Html TableCells, spans, divs. The viewstate on these pages really adds up. We use the form get method so that really compounds the problem as each additional bit of viewstate makes the url longer. On 1 simple page, I kept having problems with the url getting so long because of ViewState that none of the PostBacks on the page would work. I eventually created a function to cycle through all the controls on the page and turns off ViewState for all of them. I call that function then turn the ViewState on for the 1 or 2 controls that actually need it. If you could shed some insight into why all controls have the ViewState turned on by default, I would really appreciate it.

Nikhil Kothari

Posted on 6/30/2004 @ 9:40 PM
Why is view state on by default for all controls. Turning on view state doesn't automatically result in view state. Only changes made to controls after they have been initialized to their initial state are tracked in view state. Conversely turning on view state for specific controls is too cumbersome, especially given that to turn on view state for a particular control requires you to turn on view state for all its parents. If you're adding controls dynamically, (like Derek is from his comment), make sure you first initialize the controls to their initial state before adding them to the control collection. This will make sure that changes you make to controls to set them up in their initial state doesn't add to view state as well.

Derek White

Posted on 7/1/2004 @ 6:15 AM
Thanks for pointing that out. I can now sort of understand why they are true by default. For our application, it would still be a lot better for them to be false because we have so few controls that need ViewState. Most of these controls are not actually added dynamically. For instance on our translations, we add a Phrase attribute to the html tag then cycle through all the controls in the control array and add the text for any control that has that attribute. For me, it is very difficult to remember to turn off viewstate for a simple span or div tag, but I do understand that in some applications, it would be a pain to have to go through and turn ViewState on for all parents of a control that needs ViewState and you would probably get a lot of support calls wondering why ViewState wasn't working for a particular control.

Daniel Cazzulino

Posted on 7/12/2004 @ 12:40 PM
Victor explained almost the same almost 2 months ago: http://weblogs.asp.net/vga/archive/2004/05/26/WhidbeyWillBringsUsAShorterViewstateGuaranteed.aspx, hehe... what an active community! It's beating MS's employees on blogging cool stuff!

Daniel

Posted on 11/30/2005 @ 4:33 PM
Hi Nikhil,
Did "Control State" made it in the final release of ASP.NET 2.0? There is alarmingly litte information around...

Regards

Maestrocity

Posted on 12/2/2005 @ 10:20 PM
Question: setting attributes declaratively in the aspx page, does that constitute the "initial state?" Because if it doesn't, that would seem like a huge place for viewstate compaction right there.

Nikhil Kothari

Posted on 12/6/2005 @ 5:22 AM
Control state is in the final release.
Declaratively set properties are considered part of the initial state, and they are not in the stored view state. Intelligently written controls also make sure they setup controls created dynamically to minimize view state consumption.

Coen

Posted on 12/10/2005 @ 3:32 PM
Hi Nikhil,

I also run in the problem of very little info about the control state. I use a standard DropDownList control in ASP 2.0 with the viewstate turned off and populate the data on every request. However the SelectedIndex is always -1 after a postback.

With viewstate is on everything is working as expected.

Any clues why the SelectedIndex info is lost?
The discussion on this post has been closed. Please use my contact form to provide comments.