<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://scottonwriting.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Scott On Writing.NET : ASP.NET View State</title><link>http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx</link><description>Tags: ASP.NET View State</description><dc:language>en</dc:language><generator>CommunityServer 2007 (Build: 20423.869)</generator><item><title>Determining an ASP.NET Page's View State Footprint</title><link>http://scottonwriting.net/sowblog/archive/2010/07/06/programmatically-determining-an-asp-net-page-s-view-state-footprint.aspx</link><pubDate>Tue, 06 Jul 2010 19:35:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:166486</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=166486</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2010/07/06/programmatically-determining-an-asp-net-page-s-view-state-footprint.aspx#comments</comments><description>
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms972976.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms972976.aspx"&gt;ASP.NET view state&lt;/a&gt; is the technique used by an ASP.NET Web page to persist changes to the state of a Web Form across postbacks. The view state of a page is, by default, placed in a hidden form field named __VIEWSTATE, and can easily get very large. Not only does the __VIEWSTATE form field cause slower downloads, but, whenever the user posts back the Web page, the contents of this hidden form field must be posted back in the HTTP request, thereby lengthening the request time, as well. Because view state is buried in a hidden form field and because as developer we typically test locally, the affect of view state bloat on the user experience requires preemptive action. Steps must be taken to measure view state's size and to take steps in trimming down view state if it begins to negatively affect the user experience.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;There are a variety of techniques for measuring the view state size on a given page. Perhaps the simplest is to turn on &lt;a href="http://www.4guysfromrolla.com/webtech/081501-1.shtml" mce_href="http://www.4guysfromrolla.com/webtech/081501-1.shtml"&gt;page tracing&lt;/a&gt;. With page tracing enabled you can see the estimated view state of each control in the control hierarchy. For instance, the screen show below shows that two Labels on my page consume (roughly) 120 bytes of view state each.&lt;/p&gt;

&lt;p style="text-align: center;"&gt;&lt;a href="http://www.datawebcontrols.com/images/ViewStateTrace.gif"&gt;&lt;img src="http://www.datawebcontrols.com/images/ViewStateTraceSmall.gif" mce_src="http://www.datawebcontrols.com/images/ViewStateTraceSmall.gif" border="0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's also a free add-on for Firefox that reports view state size directly in your browser window: &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/5956/" mce_href="https://addons.mozilla.org/en-US/firefox/addon/5956/"&gt;Viewstate Size&lt;/a&gt;. When installed, this add-on will show a little icon in your browser's lower right corner reporting the view state size for a given page.&lt;/p&gt;

&lt;p style="text-align: center;"&gt;&lt;img src="https://addons.mozilla.org/img/uploads/previews/thumbs/17/17145.png?modified=1194381618" mce_src="https://addons.mozilla.org/img/uploads/previews/thumbs/17/17145.png?modified=1194381618" height="48" width="110"&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;It's also possible to determine the view state size programmatically. Today I was working on a demo for an article and wanted to have the view state size displayed on every page. After reading an article I wrote back in 2004 - &lt;a href="http://msdn.microsoft.com/en-us/library/ms972976.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms972976.aspx"&gt;Understanding ASP.NET View State&lt;/a&gt; - I came up with the following code snippet to compute and display the view state size for a given page. This technique uses the "old school" way of doing it, relying on objects that have been around since ASP.NET's inception. Consequently, the below code will work in any ASP.NET application.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Visual Basic Version:&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: vb"&gt;Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
    MyBase.SavePageStateToPersistenceMedium(state)

    Dim formatter As New LosFormatter()
    Dim viewStateLength = -1

    Using writer As New StringWriter()
        formatter.Serialize(writer, state)
        viewStateLength = writer.ToString().Length
    End Using

    Response.Write(String.Format("&amp;lt;h1 class="" viewstate-summary=""&amp;gt;Total ViewState Size For This Page: {0:N0} bytes&amp;lt;/h1&amp;gt;", viewStateLength))
End Sub&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;C# Version:&lt;/b&gt; &lt;br&gt;&lt;/p&gt;
&lt;pre class="brush: c#"&gt;protected override void SavePageStateToPersistenceMedium(object state)
{
    base.SavePageStateToPersistenceMedium(state);

    var formatter = new LosFormatter();
    var viewStateLength = -1;

    using (var writer = new StringWriter())
    {
        formatter.Serialize(writer, state);
        viewStateLength = writer.ToString().Length;
    }

    Response.Write(String.Format(@"&amp;lt;h1 class="" viewstate-summary=""&amp;gt;Total ViewState Size For This Page: {0:N0} bytes&amp;lt;/h1&amp;gt;", viewStateLength));
}&lt;/pre&gt;
&lt;p&gt;The approach overrides the &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.page.savepagestatetopersistencemedium.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ui.page.savepagestatetopersistencemedium.aspx"&gt;&lt;b&gt;SavePageStateToPersistenceMedium&lt;/b&gt; method&lt;/a&gt;, which is what is invoked when the page is ready to persist its view state. In ASP.NET 1.x you would override this method to store view state to an alternative store, such as to a file on the web server, rather than in a hidden input field on the form. Starting with ASP.NET 2.0 you could use the &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.pagestatepersister.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ui.pagestatepersister.aspx"&gt;&lt;b&gt;PageStatePersister&lt;/b&gt; class&lt;/a&gt;. However, here I just want to compute the size of the serialized view state string. Consequently, I start by calling the base class's &lt;b&gt;SavePageStateToPersistenceMedium &lt;/b&gt;method. Next, I replicate the default logic that the ASP.NET Page class uses to serialize view state - namely, I create a &lt;b&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.losformatter.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ui.losformatter.aspx"&gt;LosFormatter&lt;/a&gt;&lt;/b&gt; object and serialize the content to a &lt;b&gt;StringWriter&lt;/b&gt;. Once I've done this I can determine the size of the persisted view state by getting the &lt;b&gt;StringWriter&lt;/b&gt;'s contents and determining how many characters are included. The above code can be placed directly in a code-behind class or, better yet, in a &lt;a href="http://www.4guysfromrolla.com/articles/041305-1.aspx" mce_href="http://www.4guysfromrolla.com/articles/041305-1.aspx"&gt;custom base &lt;b&gt;Page&lt;/b&gt; class&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The above programmatic approach is relatively easy to implement and works in all versions of ASP.NET. However, it won't produce the precise view state size for ASP.NET 2.0 applications and beyond. This is because the &lt;b&gt;LosFormatter&lt;/b&gt; class was replaced with a new formatting type, &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.objectstateformatter.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ui.objectstateformatter.aspx"&gt;ObjectStateFormatter&lt;/a&gt;, starting in ASP.NET 2.0. (You can certainly use the &lt;b&gt;LosFormatter &lt;/b&gt;code above in ASP.NET 2.0 and beyond applications, as the class remains in the framework for backwards compatibility. Granted, the reported view state size and actual size will differ slightly, but in analyzing whether a page contains too much view state or not, precise numbers aren't required - a close estimate will usually suffice.)&lt;/p&gt;

&lt;p&gt;To get precise measurements we can use the ASP.NET 2.0+ by doing the following:&lt;br&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a class that extends the &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.hiddenfieldpagestatepersister.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ui.hiddenfieldpagestatepersister.aspx"&gt;&lt;b&gt;HiddenFieldPageStatePersister&lt;/b&gt; class&lt;/a&gt;. This is the class that is used by ASP.NET (by default) to persist view state and other information to hidden form fields. We want to extend this class to include a property that reports the size of the persisted state, and&lt;br&gt;&lt;/li&gt;

&lt;li&gt;Override the &lt;b&gt;Page&lt;/b&gt; class's &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ui.page.pagestatepersister.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ui.page.pagestatepersister.aspx"&gt;&lt;b&gt;PageStatePersister&lt;/b&gt; property&lt;/a&gt; and return the custom persister class created in step 1.&lt;/li&gt;
&lt;li&gt;Override the &lt;b&gt;Page&lt;/b&gt; class's &lt;b&gt;SavePageStateToPersistenceMedium &lt;/b&gt;method and read the value of the view state size from the class created in step 1.&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the code for the class that extends &lt;b&gt;HiddenFieldPageStatePersister&lt;/b&gt;, which I've named &lt;b&gt;MyHiddenFieldPageStatePersister&lt;/b&gt; (please don't mock me for my lack of naming creativity). This class is pretty simple: it defines a property named &lt;b&gt;StateSize&lt;/b&gt;, overrides the &lt;b&gt;Save&lt;/b&gt; method, and then sets the &lt;b&gt;StateSize &lt;/b&gt;property from this method using the same code/logic as used internally by the &lt;b&gt;HiddenFieldPageStatePersister &lt;/b&gt;class. The code snippet below takes advantage of some language features that you might not have at your disposal if you're using an older version of C# or VB (for example, the use of automatic properties). But the concept is sound and should work (with a little tweaking) in earlier versions of VB/C#. (I tested this using ASP.NET 4. You can download the complete source code &lt;a href="http://aspnet.4guysfromrolla.com/code/ViewStateModeDemo.zip" mce_href="http://aspnet.4guysfromrolla.com/code/ViewStateModeDemo.zip"&gt;here&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Visual Basic Version:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="brush: vb"&gt;Public Class MyHiddenFieldPageStatePersister
    Inherits HiddenFieldPageStatePersister

    Public Sub New(ByVal page As Page)
        MyBase.New(page)
    End Sub

    Public Overrides Sub Save()
        If MyBase.ViewState IsNot Nothing OrElse MyBase.ControlState IsNot Nothing Then
            Me.StateSize = MyBase.StateFormatter.Serialize(New Pair(MyBase.ViewState, MyBase.ControlState)).Length
        End If
        
        MyBase.Save()
    End Sub

    Public Property StateSize As Integer
End Class&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;C# Version:&lt;/b&gt; &lt;br&gt;&lt;/p&gt;
&lt;pre class="brush: c#"&gt;public class MyHiddenFieldPageStatePersisterCS : HiddenFieldPageStatePersister
{
    public MyHiddenFieldPageStatePersisterCS(Page page) : base(page) { }

    public override void Save()
    {
        if (base.ViewState != null || base.ControlState != null)
            this.StateSize = base.StateFormatter.Serialize(new Pair(base.ViewState, base.ControlState)).Length;

        base.Save();
    }

    public int StateSize
    {
        get;
        private set;
    }
}&lt;/pre&gt;
&lt;p&gt;The last step, then, is to override the &lt;b&gt;Page &lt;/b&gt;class's &lt;b&gt;PageStatePersister &lt;/b&gt;property and return an instance of our persister class, &lt;b&gt;MyHiddenFieldPageStatePersister&lt;/b&gt;. Again, this can be done in the code-behind class of an ASP.NET page, but I recommend putting it in a custom base &lt;b&gt;Page &lt;/b&gt;class.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Visual Basic Version:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="brush: vb"&gt;Private _PageStatePersister As PageStatePersister = Nothing

Protected Overrides ReadOnly Property PageStatePersister As System.Web.UI.PageStatePersister
    Get
        If _PageStatePersister Is Nothing Then
            _PageStatePersister = New MyHiddenFieldPageStatePersister(Me)
        End If

        Return _PageStatePersister
    End Get
End Property&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;C# Version:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="brush: c#"&gt;private PageStatePersister _PageStatePersister = null;

protected override PageStatePersister PageStatePersister
{
    get
    {
        if (_PageStatePersister == null)
            _PageStatePersister = new MyHiddenFieldPageStatePersisterCS(this);

        return _PageStatePersister;
    }
}&lt;/pre&gt;
&lt;p&gt;EDIT [2010-07-07]: I forget an important final piece of the puzzle for using the &lt;b&gt;MyHiddenFieldPageStatePersister&lt;/b&gt; class! In addition to overriding the &lt;b&gt;PageStatePersister&lt;/b&gt; property you also need to override the &lt;b&gt;SavePageStateToPersistenceMedium &lt;/b&gt;method like in the &lt;b&gt;LosFormatter &lt;/b&gt;example, but instead of using &lt;b&gt;LosFormatter &lt;/b&gt;you need to read the value of the &lt;b&gt;StateSize &lt;/b&gt;property from the &lt;b&gt;MyHiddenFieldPageStatePersister&lt;/b&gt; class. The code for this overridden method follows:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Visual Basic Version:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="brush: vb"&gt;Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
    MyBase.SavePageStateToPersistenceMedium(state)

    Dim myPersister As MyHiddenFieldPageStatePersister = CType(Me.PageStatePersister, MyHiddenFieldPageStatePersister)

    Response.Write(String.Format("&lt;h1 class="" viewstate-summary=""&gt;Total ViewState Size For This Page: {0:N0} bytes&lt;/h1&gt;", myPersister.StateSize))
End Sub&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;C# Version:&lt;/b&gt; &lt;br&gt;&lt;/p&gt;
&lt;pre class="brush: c#"&gt;protected override void SavePageStateToPersistenceMedium(object state)
{
    base.SavePageStateToPersistenceMedium(state);

    var myPersister = this.PageStatePersister as MyHiddenFieldPageStatePersisterCS;

    if (myPersister != null)
        Response.Write(String.Format(@"&lt;h1 class="" viewstate-summary=""&gt;Total ViewState Size For This Page: {0:N0} bytes&lt;/h1&gt;", myPersister.StateSize));
}&lt;/pre&gt;
&lt;p&gt;Happy Programming! &lt;br&gt;&lt;/p&gt;
&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=166486" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>How Big is Too Big a ViewState?</title><link>http://scottonwriting.net/sowblog/archive/2005/09/07/163107.aspx</link><pubDate>Wed, 07 Sep 2005 13:14:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163107</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163107</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2005/09/07/163107.aspx#comments</comments><description>&lt;p&gt;When creating ASP.NET pages one thing that usually doesn't get looked at too intensely by developers is the page's ViewState weight (&lt;a href="http://scottonwriting.net/sowblog/posts/1579.aspx"&gt;I've been guilty of this myself&lt;/a&gt;).  While there are various mechanisms to reduce the ViewState bloat in a page, the ultimate (uneloquently worded) question is, “How big is too big a ViewState?”  &lt;a href="http://weblogs.asp.net/despos/"&gt;Dino Esposito&lt;/a&gt; chimes in with some metrics in his blog entry &lt;a href="http://weblogs.asp.net/despos/archive/2005/07/21/420082.aspx"&gt;ViewState Numbers&lt;/a&gt; [emphasis Dino's]:&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;You should endeavour to keep a page size around &lt;strong&gt;30 KB&lt;/strong&gt;, to the extent that is possible of course. For example, the &lt;strong&gt;Google’s&lt;/strong&gt; home page is less than &lt;strong&gt;4 KB&lt;/strong&gt;. The home page of &lt;strong&gt;ASP.NET&lt;/strong&gt; counts about&lt;strong&gt; 50 KB&lt;/strong&gt;. The Google’s site is not written with ASP.NET so nothing can be said about the viewstate; but what about the viewstate size of the home of the &lt;strong&gt;ASP.NET&lt;/strong&gt; site? Interestingly enough, that page has only &lt;strong&gt;1 KB&lt;/strong&gt; of viewstate. On the other hand, this &lt;strong&gt;page&lt;/strong&gt; on the same site (ASP.NET) is longer than &lt;strong&gt;500 KB&lt;/strong&gt; of which &lt;strong&gt;120 KB&lt;/strong&gt; is viewstate.&lt;/p&gt;
&lt;p&gt;The ideal size for a viewstate is around &lt;strong&gt;7 KB&lt;/strong&gt;; it is optimal if you can keep it down to &lt;strong&gt;3 KB&lt;/strong&gt; or so. In any case, the viewstate, no matter its absolute size, should never exceed 30% of the page size.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p dir="ltr"&gt;I think these are good metrics to live by when building apps targetted for the Internet.  ViewState enacts a “double hit” regarding page load time.  First, the user must download the ViewState bytes.  Then, when posting back, that same ViewState must be reuploaded to the web server (sent back in the POST headers).  And then, when receiving back the resulting markup from the postback, the ViewState (possibly modified) is sent back down again.  So during a postback there's a seemingly double hit.  That is, if it takes &lt;em&gt;x&lt;/em&gt; seconds to download the ViewState of the page, when the user posts back it will take at least 2&lt;em&gt;x&lt;/em&gt; - &lt;em&gt;x&lt;/em&gt; to upload the ViewState and another &lt;em&gt;x&lt;/em&gt; to download it back again.  Cripes!  (This is part of the reason &lt;a href="http://en.wikipedia.org/wiki/AJAX"&gt;AJAX&lt;/a&gt; is so appealing in Internet situations, although AJAX carries with it it's own slew of issues.)&lt;/p&gt;
&lt;p dir="ltr"&gt;When you're building intranet apps, where you know your user's will be connecting over a LAN, the page sizes and ViewState sizes are not as important as they impact the user experience much less.  Most of my “real-world” projects have been created for the intranet setting, so I've not had to fret over ViewState size as much as others may have.  &lt;/p&gt;
&lt;p dir="ltr"&gt;For those projects where a trim ViewState size is paramount, one common question is how to quickly determine the ViewState size (and, perhaps, what junk is actually being stored in there).  For the ViewState size, I usually just do a View/Source and then highlight the ViewState content.  (In &lt;a href="http://www.ultraedit.com/"&gt;UltraEdit&lt;/a&gt; - my text editor of choice - the number of bytes selected is shown in the toolbar.)  To determine the contents of ViewState there are tools like &lt;a href="http://pluralsight.com/blogs/fritz/default.aspx"&gt;Fritz Onion&lt;/a&gt;'s &lt;a href="http://www.pluralsight.com/tools.aspx"&gt;ViewState decoder&lt;/a&gt; (for ASP.NET 1.x and 2.0) and &lt;a href="http://www.nikhilk.net/"&gt;Nikhil Kothari&lt;/a&gt;'s &lt;a href="http://www.nikhilk.net/Project.WebDevHelper.aspx"&gt;Web Development Helper&lt;/a&gt; (for 2.0).  I also provide code for a web-based ViewState decoder (for ASP.NET 1.x) in my article, &lt;em&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/viewstate.asp"&gt;Understanding ASP.NET ViewState&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163107" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Don't Trust ViewState</title><link>http://scottonwriting.net/sowblog/archive/2005/05/03/163073.aspx</link><pubDate>Tue, 03 May 2005 21:03:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163073</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163073</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2005/05/03/163073.aspx#comments</comments><description>&lt;p&gt;Today I was pointed to a recent email to the BUGTRAQ mailing list (a mailing frequented by security experts) concerning replay attacks and ASP.NET view state.  The email was posted by Michal Zalewski, titled: &lt;a href="http://www.securityfocus.com/archive/1/397375/2005-04-30/2005-05-06/2"&gt;ASP.NET __VIEWSTATE crypto validation prone to replay attacks&lt;/a&gt;.  As I describe in my article &lt;em&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/viewstate.asp"&gt;Understanding ASP.NET ViewState&lt;/a&gt;&lt;/em&gt;, The contents stashed in the hidden __VIEWSTATE form field are base-64 encoded and (by default) cryptographically signed to prevent view state tampering by a malicious client and ensure validity of the view state's contents across postback.&lt;/p&gt;
&lt;p&gt;The signature occurs by salting the view state with both the HashCode for the virtual directory in which the page exists along the page's HashCode.  This signature prevents a nefarious user from modifying the view state and posting it back.  If such a situation unfolds, the ASP.NET runtime will not that the reposted view state's signature does not match up and throw an exception.  Similarly, this mechanism prevents against replay attacks where the view state is taken, without modification, and posted back to a different page.  Since the view state is signed by the page's HashCode, the signature wouldn't match up.&lt;/p&gt;
&lt;p&gt;What Michal reasoned out, though, was that the view state was vulnerable to replay attacks to the same page.  His example is a common one: you have an eCommerce site where the data loaded on the page is dependent upon querystring parameters, such as &lt;font face="Courier New"&gt;GetProduct.aspx?ID=&lt;em&gt;productID&lt;/em&gt;&lt;/font&gt;.  If things like price are stored in the view state (such as in a shopping cart DataGrid or put there programmatically), a frugal visitor could visit &lt;font face="Courier New"&gt;GetProducts.aspx?ID=&lt;em&gt;cheapProduct&lt;/em&gt;&lt;/font&gt;, save the view state in the hidden form field, then repost that to &lt;font face="Courier New"&gt;GetProducts.aspx?ID=&lt;em&gt;expensiveProduct&lt;/em&gt;&lt;/font&gt;.  The end effect might be that the user could order the expensive product for the price of the cheap one.  (Of course this would only be possible if the eCommerce site relied solely on the view state for pricing information when computing the final bill.)&lt;/p&gt;
&lt;p&gt;The point is, &lt;strong&gt;don't trust view state&lt;/strong&gt; (or the data that is put there by Web controls, such as the DataGrid).  That is, if you have important information, such as pricing data, it's OK if it is placed in view state (such as in a row in a DataGrid), but don't grab the pricing data to charge by just poking around the view state (as in programmatically accessing the contents of a DataGrid).  Instead, if you need to get pricing information (or any other important bit of information) for the final order processing, it is imperative that you &lt;em&gt;requery the database&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Another point Michal made in his email was that view state can be used in a one-click attacks.  That is, a nefarious hacker could pass along one view state through a third-party, the end effect being that the third-party sees a page with a view state they did not “create” themselves.  Michal points out that to avoid this there needs to be someway to associate the view state with information particular to a user.  This is possible in ASP.NET 1.1 via the &lt;font face="Courier New"&gt;ViewStateUserKey&lt;/font&gt; property, which is an additional, optional parameter that is used as a salt in the signature.  You can assign this property to some unique user value to prevent the attack; see &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCh10.asp"&gt;&lt;em&gt;Improving Web Application Security: Threats and Countermeasures&lt;/em&gt;&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;The last point of Michal's email to BUGTRAQ was concerned unsigned view states.  If you opt not to sign the view state (that is, if you set &lt;font face="Courier New"&gt;EnableViewStateMac&lt;/font&gt; to false), ASP.NET naively attempts to decode the view state passed in.  This can be used as a denial of service vector by dumping in a very large hidden view state field, which can severely hamper the performance of the web server.  (Of course, the web server is likely configured to reject any incoming request that's larger than 4 MB in size, but this is still an easy point of attack since crafting and posting a large view state is a trivial task from the attacker's point of view.)  To protect yourself from this don't set &lt;font face="Courier New"&gt;EnableViewStateMac&lt;/font&gt; to false, if possible.  There have &lt;a href="http://www.dotnetbips.com/displayarticle.aspx?id=183"&gt;been some claims&lt;/a&gt; that &lt;a href="http://www.devx.com/vb2themax/Tip/18744"&gt;you need to&lt;/a&gt; set &lt;font face="Courier New"&gt;EnableViewStateMac&lt;/font&gt; to false in order to have &lt;font face="Courier New"&gt;Server.Transfer&lt;/font&gt; work properly.  There is a workaround, as discussed in &lt;a href="http://support.microsoft.com/default.aspx?scid=kb;EN-US;316920"&gt;this KB article&lt;/a&gt;.  It is my understanding, however, that you'll need to set &lt;font face="Courier New"&gt;EnableViewStateMac&lt;/font&gt; to false if you are using a web farm without server affinity.&lt;/p&gt;
&lt;p&gt;I followed up Michal's email to BUGTRAQ with an offlist discussion.  His main point, as I understand it, is that he in concerned because developers might think that view state is a safe place to put sensitive data or data that need not be revalidated due to the signing/encrypting options view state provides.  However, as Michal's email shows, view state - even signed and/or encrypted view state - is not safe from replay attacks on sites where a single page's differs merely by the querystring.  The short of it - don't trust that your view state information has not been modified and &lt;em&gt;always&lt;/em&gt; requery the database before using information whose correctness is important.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163073" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Using Email as a Knowledge Base</title><link>http://scottonwriting.net/sowblog/archive/2005/04/25/163070.aspx</link><pubDate>Tue, 26 Apr 2005 01:42:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:163070</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=163070</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2005/04/25/163070.aspx#comments</comments><description>&lt;p&gt;A recent BBC article, &lt;a href="http://news.bbc.co.uk/2/hi/business/4167633.stm"&gt;E-mail is the New Database&lt;/a&gt;, examines how as the storage capacity and search capabilities of email services have grown and improved over the past year, many folks are using their online email accounts as personal databases.  Need to remember and be able to find that colleague's phone number from anywhere in the world?  Email his contact information to your GMail account.  Want to be able to puruse your TODO list at work?  Email it to your GMail account before you leave home in the morning.&lt;/p&gt;
&lt;p&gt;Anywho, this article got me to thinking - why not use GMail as an online knowledge base?  I've already blogged before about &lt;a href="http://scottonwriting.net/sowblog/posts/3006.aspx"&gt;the usefulness of GMail for managing high-volume listservs&lt;/a&gt; - with its threaded email views, virtually unlimited storage space, and killer search features it's makes email listservs enjoyable to use again.  So why not create a GMail account that does nothing else but serve as a repository for a gaggle of focused email listservs?  Over time this GMail account would automatically be populated with user's questions and (more importantly) answers to these questions.  When facing a particularly tough problem, the first stop - before searching the web, would be to logon and search this GMail account.  It would be like searching a small corner of the web that was known to be highly focused on,.say, server-side development using Microsoft technologies.&lt;/p&gt;
&lt;p&gt;On Sunday I created a new GMail account and started signing up to ASP.NET-related listservs.  There are a number over at &lt;a href="http://www.aspadvice.com"&gt;ASPAdvice.com&lt;/a&gt; along with a number over at &lt;a href="http://groups.yahoo.com"&gt;Yahoo! Groups&lt;/a&gt;.  What's also neat is that the &lt;a href="http://forums.asp.net"&gt;ASP.NET Forums&lt;/a&gt; allow you to receive an email whenever a new post is made to a specified forum.  Similarly, you can configure &lt;a href="http://groups.google.com"&gt;Google Groups&lt;/a&gt; to send you a daily digest from a particular USENET newsgroup (such as &lt;a href="http://groups-beta.google.com/group/microsoft.public.dotnet.framework.aspnet"&gt;microsoft.public.dotnet.framework.aspnet&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;With these data sources alone, I've already amassed 417 “conversations” from around the web, highly focused on ASP.NET development. (These numbers boil down to an estimated 12 new conversations per hour; meaning in a month, there'd be roughly 8,000 conversations, or 86,000 in a year.  The nice thing is that this archive can be quickly searched just as well as the web is searched through Google and space will (likely) never be an issue.).  I've yet to need to search this GMail account for technical help, but I am expecting/hoping to find it to be: (a) easy to search, and (b) more relevant than a general web search via Google, especially since many of these resources (especially listservs) are not archived on a website, and therefore not indexed by Google's spiders.  (I'll keep you posted as to how useful such a GMail account turns out to be...)&lt;/p&gt;
&lt;p&gt;Another neat use for GMail!  BTW, if you need a GMail account, feel free to &lt;a href="http://scottonwriting.net/sowblog/contact.aspx"&gt;drop me a line&lt;/a&gt;, I'd be happy to hook you up.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=163070" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Control Building and ViewState Redux</title><link>http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx</link><pubDate>Fri, 08 Oct 2004 12:35:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162998</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162998</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx#comments</comments><description>&lt;p&gt;Earlier this week I posted an entry titled &lt;a href="http://scottonwriting.net/sowblog/posts/2129.aspx"&gt;Control Building and ViewState Lesson for the Day&lt;/a&gt;, in which I discussed when working with dynamic controls the importance of the order with which a control is added and its properties are set.  My end recommendation was to use the following pattern:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create an instance of the control (i.e., &lt;font face="Courier New"&gt;TextBox tb = &lt;font color="#0000ff"&gt;new&lt;/font&gt; TextBox();&lt;/font&gt;)&lt;/li&gt;
&lt;li&gt;Add the control to the appropriate &lt;font face="Courier New"&gt;Controls&lt;/font&gt; collection (i.e., &lt;font face="Courier New"&gt;&lt;em&gt;PlaceHolderID&lt;/em&gt;.Controls.Add(tb);&lt;/font&gt;)&lt;/li&gt;
&lt;li&gt;Set the dynamic control's properties (i.e., &lt;font face="Courier New"&gt;tb.ForeColor = Color.Red;&lt;/font&gt;)&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;The key lesson was to make sure you do step 2 before step 3, or you may be plauged with view state issues.  In that previous blog entry I mentioned that the reason this happens is because if the control is added after the TrackViewState stage in the page lifecycle (such as in the Load stage), then any changes to the control's properties are not recorded by view state, so nothing gets saved to view state and so nothing on postback gets populated back into the control's view state.  However, I said that adding a control via the &lt;font face="Courier New"&gt;Controls.Add()&lt;/font&gt; method causes the controls &lt;font face="Courier New"&gt;TrackViewState()&lt;/font&gt; method to be called.  This is correct, but it's not a complete answer.&lt;/p&gt;
&lt;p&gt;Not only is the &lt;font face="Courier New"&gt;TrackViewState()&lt;/font&gt; method being called for the added control, but it goes through the entire control lifecycle, if needed.  Using &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector&lt;/a&gt; you can see that the control's &lt;font face="Courier New"&gt;InitRecursive()&lt;/font&gt; method is called, which fires the &lt;font face="Courier New"&gt;Init&lt;/font&gt; event for the added control and all of its children controls (this also is where the control's &lt;font face="Courier New"&gt;TrackViewState()&lt;/font&gt; method is invoked).  If the control that is having the dynamic control added to it has a non-null ViewState, the control being added has it's &lt;font face="Courier New"&gt;LoadViewStateRecursive()&lt;/font&gt; method called, which loads the view state into the added control and its child controls.  But things don't end there necessarily.  If the control that had the dynamic control added to it has already fired its Load event, the added control's &lt;font face="Courier New"&gt;Load&lt;/font&gt; event is fired (recursively, again), and even the &lt;font face="Courier New"&gt;PreRender&lt;/font&gt; event is fired if needed.&lt;/p&gt;
&lt;p&gt;One final point to clear up: in my &lt;a href="http://scottonwriting.net/sowblog/posts/2129.aspx"&gt;previous blog entry&lt;/a&gt; I credited &lt;a href="http://blogs.msdn.com/alowe/"&gt;Alex Lowe&lt;/a&gt; with being the one whose words from 2001 had reminded me that I needed to add the control first and &lt;em&gt;then&lt;/em&gt; set its properties.  Memory's a funny thing, really, since I remembered Alex's words, but I had totally blanked on an email Wessam Zeidan had sent me in late September 2004 where he talked about the same thing, saying: “... some how when we add a dynamic control to the Controls collection, the TrackViewState method gets called, and that explains why the backcolor property of the textbox gets saved to the viewstate if we add the textbox to the controls collection before setting it.”  And if that wasn't enough, I realized that I said the same thing &lt;em&gt;myself&lt;/em&gt; in my MSDN article &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/viewstate.asp"&gt;Understanding ASP.NET View State&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;You may be able to get away with loading your controls in the &lt;font face="Courier New"&gt;Page_Load&lt;/font&gt; event handler and maintaining the view state properly. It all depends on whether or not you are setting any properties of the dynamically loaded controls programmatically and, if so, when you're doing it relative to the &lt;font face="Courier New"&gt;Controls.Add(&lt;em&gt;dynamicControl&lt;/em&gt;)&lt;/font&gt; line. A thorough discussion of this is a bit beyond the scope of this article, but the reason it may work is because the &lt;font face="Courier New"&gt;Controls&lt;/font&gt; property's &lt;font face="Courier New"&gt;Add()&lt;/font&gt; method recursively loads the parent's view state into its children, even though the load view state stage has passed.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p dir="ltr"&gt;It's funny how our minds work, and how fluid memory can truly be.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162998" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Control Building and ViewState Lesson for the Day</title><link>http://scottonwriting.net/sowblog/archive/2004/10/06/162995.aspx</link><pubDate>Wed, 06 Oct 2004 19:17:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162995</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162995</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/10/06/162995.aspx#comments</comments><description>&lt;p&gt;Whenever I am working on a problem and hit a perplexing roadblock that impedes my process, my initial emotional state is calm.  “I'll figure out this problem soon,” I tell myself, as I explore workarounds or examine the code base to try to understand why I can't do what I know I should be able to do.  If this search goes on for five or more minutes, I start to get a little flustered.  Off to Google!” I declare, hoping there has been some other unfortunate soul who has experienced the same problem and has shared his solution.  I usually hit the Google Web search first and, if I have no luck there, I delve into the USENET postings on Google Groups.  If 15 minutes have passed with no hits from Google, I start to get angry at myself.  “I SHOULD KNOW HOW TO FIX THIS,” I say, as I pour back over the material I examined in the first five minutes, knowing there must be somethinig I overlooked.  What's interesting is that if this search continues into, say, the half hour mark, my emotions start to sway from frustration and despair to glee.  “Wait until I figure out what went wrong,” I reason, “and I can share it on my blog, and it will help others down the road.”  And that's what keeps me going.&lt;/p&gt;
&lt;p&gt;Today's lesson - which will hopefully save you the 40 minutes it cost me - centers around &lt;strong&gt;composite controls&lt;/strong&gt;, the &lt;strong&gt;DropDownList&lt;/strong&gt; Web control, and &lt;strong&gt;ViewState&lt;/strong&gt;.  Let's say you want to create a composite control that contains a DropDownList that already is bound to database data (namely, it does &lt;em&gt;not&lt;/em&gt; allow the control developer to specify the DropDownList's &lt;font face="Courier New"&gt;DataSource&lt;/font&gt; as would normally be the case: for a discussion on the pros and cons of this approach check out &lt;a href="http://weblogs.asp.net/asmith/archive/2004/08/29/222442.aspx"&gt;Composite Controls That Do Their Own DataBinding&lt;/a&gt; by &lt;a href="http://weblogs.asp.net/asmith/"&gt;Andy Smith&lt;/a&gt;).  If you are at all like me, you're composite control's code would look like this (WARNING: this is wrong):&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;public class&lt;/font&gt; MyControl : WebControl, INamingContainer&lt;br /&gt;{&lt;br /&gt;  ...&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;  &lt;font color="#0000ff"&gt;protected override void&lt;/font&gt; CreateChildControls()&lt;br /&gt;  {&lt;br /&gt;    DropDownList ddl = new DropDownList();&lt;br /&gt;    &lt;font color="#0000ff"&gt;if&lt;/font&gt; (!Page.IsPostBack)&lt;br /&gt;      &lt;font color="#008000"&gt;// &lt;/font&gt;&lt;em&gt;&lt;font color="#008000"&gt;do data binding to some database...&lt;br /&gt;&lt;/font&gt;&lt;/em&gt;&lt;br /&gt;    Controls.Add(ddl);&lt;br /&gt;  }&lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;This, as aforementioned is the WRONG WAY to do it.  Why?  Well, give the control a whirl by creating an ASP.NET Web page with this control and a Button Web control.  When you visit the page the first time, the DropDownList is displayed, populated with the database data.  However, if you click the Button and the page posts back, the items in the DropDownList disappear - the DropDownList is not saving its view state.&lt;/p&gt;
&lt;p&gt;If you're like me, the first thing you do is crack open &lt;em&gt;&lt;a href="http://www.4guysfromrolla.com/ASPScripts/Goto.asp?ID=170"&gt;Developing Microsoft ASP.NET Server Controls and Components&lt;/a&gt;&lt;/em&gt;, thumb through to Chapter 12: Composite Controls, and read the section titled “State and Child Controls.”  The gist of the section says that composite controls don't need to employ extra effort to save the view state of their children since it's saved automatically when the page recursively walks the control tree to generate the entire view state.  Opening &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector&lt;/a&gt;, I poured through the &lt;font face="Courier New"&gt;Page&lt;/font&gt; and &lt;font face="Courier New"&gt;Control&lt;/font&gt; classes, and saw that, yes, the control hierarchy should be walked and the view state saved, so when my composite control's &lt;font face="Courier New"&gt;SaveViewState()&lt;/font&gt; method was called, it should save not only its own view state, but the view state of its child(ren): namely, the DropDownList.  But, evidently it was not.&lt;/p&gt;
&lt;p&gt;This got me to scratching my head.  Why isn't the DropDownList's view state being saved?  &lt;font face="Courier New"&gt;EnableViewState&lt;/font&gt; for both the Web page, composite control, and DropDownList were all set to True (the default).  I looked at the &lt;font face="Courier New"&gt;SaveViewState()&lt;/font&gt; method for the DropDownList and confirmed that it should be saving its view state.  So why wouldn't the DropDownList be saving its view state?&lt;/p&gt;
&lt;p&gt;And then it occurred to me - check to make sure that the DropDownList's &lt;font face="Courier New"&gt;IsTrackingViewState&lt;/font&gt; property is True - if it isn't, then the DropDownList won't be recording changes to its state, and therefore won't produce a ViewState.  A control begins tracking its view state when its &lt;font face="Courier New"&gt;TrackViewState()&lt;/font&gt; method is called, and this is handled after the Initialization stage of the page lifecycle.  So, if the DropDownList is being added after that stage, then it wouldn't be tracking its view state, and therefore its state would be lost on postbacks.&lt;/p&gt;
&lt;p&gt;But wait a minute, if you add a child control via the &lt;font face="Courier New"&gt;Controls.Add()&lt;/font&gt; method, the added child control's &lt;font face="Courier New"&gt;TrackViewState()&lt;/font&gt; method is automatically called.  But wait!  Only those items added to the view state &lt;em&gt;after&lt;/em&gt; the view state has started being tracked will be recorded.  So binding the items to the DropDownList prior to adding the DropDownList to the &lt;font face="Courier New"&gt;Controls&lt;/font&gt; collection causes those additions to not be saved in the view state for the DropDownList.  Rather, we need to &lt;em&gt;first&lt;/em&gt; add the DropDownList to the &lt;font face="Courier New"&gt;Controls&lt;/font&gt; collection and &lt;em&gt;then&lt;/em&gt; bind the database data to the list.  The order matters because we don't want to bind the data to the DropDownList until after we've started tracking view state.&lt;/p&gt;
&lt;p&gt;To summarize, the correct code should look like:&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;public class&lt;/font&gt; MyControl : WebControl, INamingContainer&lt;br /&gt;{&lt;br /&gt;  ...&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;  &lt;font color="#0000ff"&gt;protected override void&lt;/font&gt; CreateChildControls()&lt;br /&gt;  {&lt;br /&gt;    DropDownList ddl = new DropDownList();&lt;br /&gt;    Controls.Add(ddl);   &lt;font color="#008000"&gt;// Add the control FIRST&lt;br /&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;    &lt;font color="#0000ff"&gt;if&lt;/font&gt; (!Page.IsPostBack)  &lt;font color="#008000"&gt;// Bind data AFTER&lt;/font&gt;&lt;br /&gt;      &lt;font color="#008000"&gt;// &lt;/font&gt;&lt;em&gt;&lt;font color="#008000"&gt;do data binding to some database...&lt;br /&gt;&lt;/font&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Courier New"&gt;  }&lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Partial credit goes to (IIRC) &lt;a href="http://blogs.msdn.com/alowe/"&gt;Alex Lowe&lt;/a&gt;.  If I'm remembering correctly, way back in (yikes!) 2001 he tech reviewed &lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/0672321432/"&gt;&lt;em&gt;ASP.NET: Tips, Tutorials, and Code&lt;/em&gt;&lt;/a&gt; for which I authored some chapters, and on one of the chapters I had an example of adding dynamic controls to a page and - again, if my memory doesn't fail me - he noted that you wanted to first add the control to the page prior to setting properties that needed to be maintained in the view state.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162995" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Question: I set my page's EnableViewState property False; why is there still a __VIEWSTATE hidden form field?</title><link>http://scottonwriting.net/sowblog/archive/2004/07/23/162971.aspx</link><pubDate>Fri, 23 Jul 2004 18:54:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162971</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162971</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/07/23/162971.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;ANSWER:&lt;/strong&gt; A while back I wrote an article for MSDN online titled &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/viewstate.asp"&gt;Understanding ASP.NET View State&lt;/a&gt;, and blogged about the article in &lt;a href="http://scottonwriting.net/sowblog/posts/1368.aspx"&gt;this past entry&lt;/a&gt;. I recently noticed a comment in that blog entry from &lt;a href="http://mc.freezope.org/"&gt;Matthias Cavigelli&lt;/a&gt;, asking:&lt;/p&gt;
&lt;blockquote&gt;When I disable the ViewState property of the page, I still have the hidden field &lt;code&gt;__VIEWSTATE&lt;/code&gt; in the html code. Could you explain why it's still there although it's not enabled?&lt;/blockquote&gt;
&lt;p&gt;What Matthias is referring to is the &lt;code&gt;EnableViewState&lt;/code&gt; property, which is defined in the &lt;code&gt;System.Web.UI.Control&lt;/code&gt; class (which means that &lt;b&gt;all&lt;/b&gt; ASP.NET server controls have this property, including the &lt;code&gt;Page&lt;/code&gt; class from which all ASP.NET Web pages are derived.) This property defaults to True, which means that, by default, a control should track its view state and save its view state during the &lt;code&gt;SaveViewState&lt;/code&gt; stage of the page's lifecycle. By setting &lt;code&gt;EnableViewState&lt;/code&gt; to false, a control is saying, "Don't bother recording my view state."&lt;/p&gt;
&lt;p&gt;Setting &lt;code&gt;EnableViewState&lt;/code&gt; to False on certain state-heavy controls is a good way to trim the size of a page's view state. Of course, you must take care when tweaking this property, since the state-heavy controls typically rely on the view state to maintain their functionality. Here's a good example of when you can set &lt;code&gt;EnableViewState&lt;/code&gt; to False: when you have a DataGrid Web control on a page that simply displays data, and where the DataGrid's properties are not programmatically changed on postback. (Note: if this page does have postbacks you'll have to make sure to rebind the database data to your DataGrid on &lt;i&gt;every&lt;/i&gt; postback.) 
&lt;/p&gt;&lt;p&gt;If your page does not perform any postbacks at all, having view state is a big waste. So, you might as well set the &lt;code&gt;Page&lt;/code&gt; class's &lt;code&gt;EnableViewState&lt;/code&gt; to False, so that no view state is saved for the entire page. Or so you'd think. If you set &lt;code&gt;EnableViewState&lt;/code&gt; to False for the page, you'll still get a hidden &lt;code&gt;__VIEWSTATE&lt;/code&gt; form field, although it will be pretty small. Why does this hidden form field exist at all?&lt;/p&gt;
&lt;p&gt;To answer this question it is important to realize that view state really is paramount to Web Forms, not the &lt;code&gt;Page&lt;/code&gt; class. (A Web Form is a server-side &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tag, which is represented in the .NET Framework via the &lt;code&gt;System.Web.UI.HtmlControls.HtmlForm&lt;/code&gt; class.) If a Web Form exists, there typically needs to be a hidden &lt;code&gt;__VIEWSTATE&lt;/code&gt; form field. But the Web Form does not know the complete view state of the page. The &lt;code&gt;Page&lt;/code&gt; class, for instance, has a &lt;code&gt;ViewState&lt;/code&gt; property, into which a page developer can store items into the view state. The Web Form, obviously, is ignorant about this. So there's this chicken-and-egg thing going on here - the &lt;code&gt;Page&lt;/code&gt; knows how to completely represent the view state, but it's the Web Form that cares about it, not the &lt;code&gt;Page&lt;/code&gt;. The end result is that the &lt;code&gt;Page&lt;/code&gt; class is responsible for generating the hidden &lt;code&gt;__VIEWSTATE&lt;/code&gt; form field, but it's the Web Form that knows whether or not this is needed.&lt;/p&gt;
&lt;p&gt;To overcome this hurdle, the &lt;code&gt;Page&lt;/code&gt; class needs some way to know whether or not the &lt;code&gt;__VIEWSTATE&lt;/code&gt; form field needs to be emitted or not. To allow for this, the &lt;code&gt;Page&lt;/code&gt; class provides a public &lt;code&gt;RegisterViewStateHandler()&lt;/code&gt; method; if this method is called during the page lifecycle, a &lt;code&gt;__VIEWSTATE&lt;/code&gt; hidden form field will be emitted, &lt;b&gt;even if the &lt;code&gt;Page&lt;/code&gt; class's &lt;code&gt;EnableViewState&lt;/code&gt; property is set to False&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;From a Web Form's perspective, it always needs to save view state. Well, this is the way the Web Form class was programmed by Microsoft. You can see this by examining the &lt;code&gt;HtmlForm&lt;/code&gt; class's &lt;code&gt;OnInit()&lt;/code&gt; method:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;protected override void OnInit(EventArgs e)
{
      base.OnInit(e);
      this.Page.SetForm(this);
      &lt;b&gt;this.Page.RegisterViewStateHandler();&lt;/b&gt;
}
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;Personally, it would seem to make more sense to me to have &lt;code&gt;Page.RegisterViewStateHandler()&lt;/code&gt; called only if &lt;code&gt;Page.EnableViewState&lt;/code&gt; is true, but there may be a reason behind this that I haven't seen. Anywho, when the Web Form is rendered, it calls an additional two of the &lt;code&gt;Page&lt;/code&gt; class's methods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;OnFormRender()&lt;/code&gt; - this adds the &lt;code&gt;__VIEWSTATE&lt;/code&gt; hidden form field along with any registered hidden form fields or script blocks registered via &lt;code&gt;Page.RegisterClientScriptBlock()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnFormPostRender()&lt;/code&gt; - this adds any script blocks registered via &lt;code&gt;Page.RegisterStartupScript()&lt;/code&gt; and any client-side arrays registered via &lt;code&gt;Page.RegisterArrayDeclaration()&lt;/code&gt;.&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;You may still be wondering why when the &lt;code&gt;Page&lt;/code&gt;'s &lt;code&gt;EnableViewState&lt;/code&gt; is False that the &lt;code&gt;__VIEWSTATE&lt;/code&gt; hidden form field has anything in it. Well, if you take a look at the &lt;code&gt;Page&lt;/code&gt; class's &lt;code&gt;SavePageViewState()&lt;/code&gt; method, you'll see:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;internal void SavePageViewState()
{
      if (!this._needToPersistViewState)
      {
            return;
      }
      Triplet triplet1 = new Triplet();
      int num1 = this.GetTypeHashCode();
      triplet1.First = num1.ToString(NumberFormatInfo.InvariantInfo);
      triplet1.Third = this._registeredControlsThatRequirePostBack;
      ...
      triplet1.Second = base.SaveViewStateRecursive();
      
      this.SavePageStateToPersistenceMedium(triplet1);
}
&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;So what you see her is the following: if &lt;code&gt;_needToPersistViewState&lt;/code&gt; is False, then nothing is saved. Well, this flag is set to True when the Web Form calls &lt;code&gt;Page.RegisterViewStateHandler()&lt;/code&gt;. So a &lt;code&gt;Triplet&lt;/code&gt; is built up, with the first item containing the page's hash, the third item containing an ArrayList of Web controls that require a postback. Now, the second item is where the meat of the view state comes from - this is the sum of the view state of the controls in the page. But if &lt;code&gt;EnableViewState&lt;/code&gt; is False for the page, &lt;code&gt;SaveViewStateRecursive()&lt;/code&gt; returns null.&lt;/p&gt;
&lt;p&gt;So even if you set the &lt;code&gt;Page&lt;/code&gt;'s &lt;code&gt;EnableViewState&lt;/code&gt; to False, you'll still get a &lt;code&gt;__VIEWSTATE&lt;/code&gt; hidden form field with the &lt;code&gt;Page&lt;/code&gt;'s hash and ArrayList of controls that require postback. I still don't see why this is needed, but there is likely a good reason.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;In an upcoming article of mine for MSDN online, I talk more about the &lt;code&gt;Page&lt;/code&gt; class's methods for registering client-side elements - scripts, arrays, hidden form fields, etc. Keep your eyes peeled on the &lt;a href="http://msdn.microsoft.com/asp.net/"&gt;ASP.NET Dev Center&lt;/a&gt;!&lt;/i&gt;&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162971" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Largest. ViewState. Ever.</title><link>http://scottonwriting.net/sowblog/archive/2004/07/22/162968.aspx</link><pubDate>Thu, 22 Jul 2004 12:37:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162968</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162968</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/07/22/162968.aspx#comments</comments><description>&lt;p&gt;The ASP.NET DataGrid Web control is notorious for its hefty view state size, but the DropDownList control can hold its own weight as well, especially when it contains a lot of items.  For example, a page containing nothing but a DropDownList populated with ~100 items from a database will yield around 10 KB in view state.  While 10 KB might not seem like much, remember that view state is a two-way penalty - it is sent down with the page's HTML and sent back during postback, thereby increasing both the download and postback time for the end user.&lt;/p&gt;
&lt;p&gt;I just finished a page that, I think, will hold record as having &lt;em&gt;the&lt;/em&gt; largest view state.  Ever.  Working on a site for a client and he needs a page that has over a dozen DropDownList controls, and each DropDownList has, believe it or not, upwards of 1,000 items.  End view state?  &lt;strong&gt;Over 800,000&lt;/strong&gt; &lt;strong&gt;bytes&lt;/strong&gt;.  In total, the page was over 2.5 MB in size.  What does this mean for an average dialup user?  Well, they'll have to wait nearly six minutes to download the page, and eight minutes to postback (two minutes to upload the 800 KB of view state, six minutes to download the 2.5 MB again).&lt;/p&gt;
&lt;p&gt;Of course, I cut the view state down to a few KB by turning off view state for the page.  It wasn't needed since I wasn't programmatically changing the state of the controls on the page, nor was I using the &lt;font face="Courier New"&gt;SelectedIndexChanged&lt;/font&gt; event of the DropDownList.  But still, the page weighs in at 1.7 MB, which is still prohibitively large (even though all users are really on an intranet).&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162968" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Understanding ASP.NET View State</title><link>http://scottonwriting.net/sowblog/archive/2004/06/03/162941.aspx</link><pubDate>Thu, 03 Jun 2004 13:28:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162941</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162941</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/06/03/162941.aspx#comments</comments><description>&lt;p&gt;My latest MSDN article is now online, and covers a topic that many developers do not have as tight a grasp on as they may think.  &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/viewstate.asp"&gt;Understanding ASP.NET View State&lt;/a&gt; looks at how an ASP.NET page maintains its state changes across postbacks, examining:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ASP.NET Page Life Cycle&lt;/li&gt;
&lt;li&gt;The Role of View State&lt;/li&gt;
&lt;li&gt;The Cost of View State&lt;/li&gt;
&lt;li&gt;How View State is Serialized/Deserialized&lt;/li&gt;
&lt;li&gt;Specifying &lt;em&gt;Where&lt;/em&gt; to Store the View State Information (see how to store it in a file on the Web server rather than as a bloated hidden form field)&lt;/li&gt;
&lt;li&gt;Programmatically Parsing the View State&lt;/li&gt;
&lt;li&gt;View State and Security Implications&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;A special thanks to &lt;a href="http://scottonwriting.net/sowblog/posts/1066.aspx"&gt;those who helped review this article&lt;/a&gt;, especially those whose feedback was used to improve the article.  If you'd be interested in reviewing articles, read &lt;a href="http://scottonwriting.net/sowblog/posts/1066.aspx"&gt;this blog entry&lt;/a&gt; for more information...&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162941" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Google AdSense and ASP.NET View State</title><link>http://scottonwriting.net/sowblog/archive/2004/05/29/162939.aspx</link><pubDate>Sat, 29 May 2004 15:43:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162939</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162939</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/05/29/162939.aspx#comments</comments><description>&lt;p&gt;I recently decided to try out &lt;a href="https://www.google.com/adsense/"&gt;Google AdSense&lt;/a&gt; on a few personal sites I run - ScottOnWriting.NET, &lt;a href="http://nbaweblog.com/nba/"&gt;NBAWebLog.com&lt;/a&gt;, &lt;a href="http://www.mp3players101.com/"&gt;MP3Players101.com&lt;/a&gt;, &lt;a href="http://skmmenu.com/menu/"&gt;skmMenu.com&lt;/a&gt;, and &lt;a href="http://datawebcontrols.com"&gt;DataWebControls.com&lt;/a&gt; - mainly as an experiment to see the effectiveness of text advertising and what sort of revenue streams small, focused sites like these are capable of generating.  (I'll be sure to post an analysis after having collected sufficient data.)&lt;/p&gt;
&lt;p&gt;The nice thing about Google AdSense is that it's a breeze to setup.  Once you have an AdSense account, you just choose a few options - colors for the text ads, if you want to serve text ads only or both text and image ads, and if you want to assign the ad to a “channel” (useful for tracking performance of ads on certain sites or pages) - and, based on these selections, you're given a snippet of client-side JavaScript code to add to the page(s) where you want to display the ads.  AdSense automatically scans the content of your site to send targetted text ads, and you get some money whenever anyone clicks on one of your ads.  The precise amount of money you receive depends on the ads served.  Essentially, advertisers can bid on showing their ads for certain keywords, so your revenue depends on how much advertisers are willing to pay for your targetted customer's clicks.&lt;/p&gt;
&lt;p&gt;In any event, I got Google AdSense up and running on all of the sites and all of them, save one (NBAWebLog.com), displayed targetted ads.  NBAWebLog.com was displaying nothing but public service ads - Save the Rainforest, Become a Big Brother, and things like that.  Reading up at AdSense, I learned that these public service ads are displayed until AdSense can successfully search and categorize the site's content.  After these public service ads persisted for three days, I emailed the AdSense support staff, and asked them what was up.  They came back and said that their spider could not classify my site due to a large amount of non-standard content near the beginning of the page.&lt;/p&gt;
&lt;p&gt;I visited NBAWebLog.com, did a quick view source and found... a large amount of non-standard content - several KB of base64 encoded content in the &lt;font face="Courier New"&gt;__VIEWSTATE&lt;/font&gt; hidden form field.  This view state information didn't need to be persisted - I wasn't handling postbacks at all from the front page - so I turned off view state from the &lt;font face="Courier New"&gt;@Page&lt;/font&gt; directive and everything worked out.  I emailed back the Google AdSense staff, got my site respidered, and now it's showing the applicable ads.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;On a slight tangent, I have an article on ASP.NET view state coming up on the MSDN &lt;a href="http://msdn.microsoft.com/asp.net/"&gt;ASP.NET Dev Center&lt;/a&gt;...&lt;/em&gt;&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162939" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/Miscellaneous/default.aspx">Miscellaneous</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>A Stumper of an ASP.NET Question: SOLVED!</title><link>http://scottonwriting.net/sowblog/archive/2004/05/20/162929.aspx</link><pubDate>Thu, 20 May 2004 19:05:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162929</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162929</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/05/20/162929.aspx#comments</comments><description>&lt;p&gt;In my &lt;a href="http://scottonwriting.net/sowblog/posts/1263.aspx"&gt;last blog entry&lt;/a&gt; I posed an ASP.NET / Repeater question that had me and a student of mine utterly stumped.  I have been communicating with this student today, bouncing ideas back and forth, and he noted that if the Repeater's &lt;font face="Courier New"&gt;EnableViewState&lt;/font&gt; property was set to False, then the Button column raised the &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event, as expected.  Now, all that the Repeater stores in its &lt;font face="Courier New"&gt;ViewState StateBag&lt;/font&gt; is the number of items in the Repeater (stored in a view state variable named &lt;font face="Courier New"&gt;_!ItemCount&lt;/font&gt;).&lt;/p&gt;
&lt;p&gt;Basically, when the Repeater's &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt; method is called, the following steps happen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Repeater's &lt;font face="Courier New"&gt;base&lt;/font&gt;'s &lt;font face="Courier New"&gt;Controls&lt;/font&gt; collection has its &lt;font face="Courier New"&gt;Clear()&lt;/font&gt; method called, cleaning out any controls in the Repeater's hierarchy. 
&lt;/li&gt;&lt;li&gt;The child view state is cleared out. 
&lt;/li&gt;&lt;li&gt;The &lt;font face="Courier New"&gt;CreateControlHierarchy()&lt;/font&gt; method is called, passing in True (indicating that the data should be bound from the &lt;font face="Courier New"&gt;DataSource&lt;/font&gt;). 
&lt;/li&gt;&lt;li&gt;The &lt;font face="Courier New"&gt;ChildControlsCreated&lt;/font&gt; property is set to True.  This property is a flag to indicate that the Repeater's control hierarchy has been built.  Whenever the Repeater's &lt;font face="Courier New"&gt;Controls&lt;/font&gt; property is accessed, it first checks to make sure that the control hierarchy has been built by calling &lt;font face="Courier New"&gt;EnsureChildControls()&lt;/font&gt;.  &lt;font face="Courier New"&gt;EnsureChildControls()&lt;/font&gt; checks to see if &lt;font face="Courier New"&gt;ChildControlsCreated&lt;/font&gt; is false; if it is, it calls &lt;font face="Courier New"&gt;CreateChildControls()&lt;/font&gt;.&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;When a Button submits a Form, the Button's &lt;font face="Courier New"&gt;name&lt;/font&gt; and &lt;font face="Courier New"&gt;value&lt;/font&gt; attributes are sent along in the POST data to the Web server.  After the LoadViewState stage in the page's life-cycle (which comes before the Load stage), the ProcessPostData stage transpires.  This stage loads post data back into the appropriate Web controls, such as reloading the text from a textbox back into the &lt;font face="Courier New"&gt;Text&lt;/font&gt; property of a TextBox Web control.  Specifically, the &lt;font face="Courier New"&gt;Page&lt;/font&gt; class's &lt;font face="Courier New"&gt;ProcessPostData()&lt;/font&gt; method enumerates all the POST names passed in and searches the control hierarchy for these controls to determine if they participate in this stage of the life-cycle.  In accessing the control via &lt;font face="Courier New"&gt;FindControl()&lt;/font&gt;, the &lt;font face="Courier New"&gt;EnsureChildControls()&lt;/font&gt; method is called and the Repeater's &lt;font face="Courier New"&gt;CreateChildControls()&lt;/font&gt; method is invoked.&lt;/p&gt;
&lt;p&gt;Now, what does the Repeater's &lt;font face="Courier New"&gt;CreateChildControls()&lt;/font&gt; method do?  Well, it checks to see if the view state variable &lt;font face="Courier New"&gt;_!ItemCount&lt;/font&gt; is &lt;font face="Courier New"&gt;null&lt;/font&gt; or not.  If it is &lt;em&gt;not&lt;/em&gt; &lt;font face="Courier New"&gt;null&lt;/font&gt;, then it calls &lt;font face="Courier New"&gt;CreateControlHierarchy()&lt;/font&gt;, passing in False.  This builds up the control hierarchy, creating the Button.  This created Button is then the Button the &lt;font face="Courier New"&gt;Page&lt;/font&gt; class's &lt;font face="Courier New"&gt;ProcessPostData()&lt;/font&gt; method marks to have its &lt;font face="Courier New"&gt;Command&lt;/font&gt; event raised during the RaisePostBackEvent stage later on.&lt;/p&gt;
&lt;p&gt;Hopefully the problem is becoming clearer now.  After this ProcessPostData stage, the Load stage transpires, and the Repeater's &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt; method is called.  This clears out the control hierarchy and rebuilds it.  Hence, the reference to the Button we had earlier has had it's &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; “detached” from the Repeater, replaced by a new &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; isntance from the call to &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt;.  Since it's this orphaned Button's &lt;font face="Courier New"&gt;Command&lt;/font&gt; event that is raised, the event cannot percolate up to the Repeater, and hence the Repeater's &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event does not fire.&lt;/p&gt;
&lt;p&gt;The LinkButton works because clicking a LinkButton does not send the LinkButton's &lt;font face="Courier New"&gt;ID&lt;/font&gt; through the POST data.  Rather, it passes this information along in the &lt;font face="Courier New"&gt;__EVENTARG&lt;/font&gt; hidden form field.  This information, then, is not queried by the &lt;font face="Courier New"&gt;Page&lt;/font&gt; class until the RaisePostBackEvents stage, which happens after the Load event, after the Repeater's control hierarchy has been constructed.&lt;/p&gt;
&lt;p&gt;So, one workaround is as follows: don't call a data Web control's &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt; method each and every page load if you are using view state.  If you are not using view state, then you'll need to call &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt; on each and every page load.  &lt;/p&gt;
&lt;p&gt;My student, Matt, wrote in to share the following workaround as well (I've not tested it; might not work in all browsers):&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;My colleague Borys has proposed a fix.  I don't think I can explain it&lt;br /&gt;very well, but we think it has to do with a conflict between post data&lt;br /&gt;and viewstate.  I'll let the code speak for itself.&lt;/p&gt;&lt;code&gt;
&lt;p&gt;Private Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As&lt;br /&gt;System.Web.UI.WebControls.DataListItemEventArgs) Handles&lt;br /&gt;DataList1.ItemDataBound&lt;/p&gt;
&lt;p&gt;            Dim b As Button = DirectCast(e.Item.Controls(1), Button)&lt;/p&gt;
&lt;p&gt;            Dim evTarget As String = b.UniqueID.Replace(":", "$")&lt;/p&gt;
&lt;p&gt;            Dim script As String = "__doPostBack('" + evTarget +&lt;br /&gt;"','');return(false)"&lt;/p&gt;
&lt;p&gt;            b.Attributes.Add("onclick", script)&lt;/p&gt;
&lt;p&gt;End Sub&lt;/p&gt;&lt;/code&gt;&lt;/blockquote&gt;
&lt;p&gt;Hope this helps someone, it was rather fun to examine and unearth the solution.&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162929" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>A Stumper of an ASP.NET Question</title><link>http://scottonwriting.net/sowblog/archive/2004/05/20/162928.aspx</link><pubDate>Thu, 20 May 2004 15:25:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162928</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162928</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/05/20/162928.aspx#comments</comments><description>&lt;p&gt;Last night a student of mine asked why the Button Web control in a Repeater's &lt;font face="Courier New"&gt;ItemTemplate&lt;/font&gt; does not raise the Repeater's &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event when clicked, but a LinkButton does.  I was perplexed because from my understanding anytime a &lt;font face="Courier New"&gt;Command&lt;/font&gt; event is raised, a &lt;font face="Courier New"&gt;CommandEventArgs&lt;/font&gt; is bubbled up the control hierarchy.  When the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; class detects a bubbled &lt;font face="Courier New"&gt;CommandEventArgs&lt;/font&gt;, it stops the bubbling of the &lt;font face="Courier New"&gt;CommandEventArgs&lt;/font&gt; and starts bubbling up a &lt;font face="Courier New"&gt;RepeaterCommandEventArgs&lt;/font&gt; instance.  Likewise, the Repeater listens for bubbled events, and in detecting a bubbled &lt;font face="Courier New"&gt;RepeaterCommandEventArgs&lt;/font&gt;, it raises its &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event.  (This is the same sequence of steps that happens in the DataList and DataGrid.)&lt;/p&gt;
&lt;p&gt;I asked this student to show me a code sample where this was the case at a break.  He did and, sure enough, the problem existed as he described.  Specifically, he had a Repeater like so:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;asp:Repeater runat=“server“&amp;gt;&lt;br /&gt;  &amp;lt;ItemTemplate&amp;gt;&lt;br /&gt;    &amp;lt;asp:Button runat=”server” CommandName=”foo” Text=”Button” /&amp;gt;&lt;br /&gt;    &amp;lt;asp:LinkButton runat=”server” CommandName=”bar” Text=”LinkButton” /&amp;gt;&lt;br /&gt;  &amp;lt;/ItemTemplate&amp;gt;&lt;br /&gt;&amp;lt;/asp:Repeater&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Next, he created an event handler for the Repeater's &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event, and did a simple &lt;font face="Courier New"&gt;Response.Write()&lt;/font&gt; in the event handler.  Finally, in the &lt;font face="Courier New"&gt;Page_Load&lt;/font&gt; event handler he added the code to bind the data to the Repeater on each postback.  (That is, &lt;em&gt;not&lt;/em&gt; just on the first page load...)  Upon visiting the page, if the LinkButton was clicked, the &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event fired (as evidenced by the &lt;font face="Courier New"&gt;Response.Write()&lt;/font&gt; output, and by the debugger); clicking the Button, however, did &lt;strong&gt;not&lt;/strong&gt; fire the &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event.&lt;/p&gt;
&lt;p&gt;Clearly, this perplexed me, so I decided to spend some time researching this after class.  The results I have found are very odd and run counter to my understanding of how the Repeater and ASP.NET works.  I am posting this here in hopes that someone will know why this behavior exists.  Let me describe my research.&lt;/p&gt;
&lt;p&gt;I started by creating a simple ASP.NET Web page with the following HTML markup:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;asp:Repeater id="Repeater1" runat="server"&amp;gt;&lt;br /&gt;  &amp;lt;ItemTemplate&amp;gt;&lt;br /&gt;    &amp;lt;asp:LinkButton ID="linkButtonTest" Runat="server" OnCommand="lCommand" CommandName="bar" Text="LinkButton"&amp;gt;&amp;lt;/asp:LinkButton&amp;gt;&lt;br /&gt;    &amp;lt;asp:Button OnCommand="bCommand" ID="buttonTest" Runat="server" CommandName="foo" Text="Button"&amp;gt;&amp;lt;/asp:Button&amp;gt;&lt;br /&gt;    &amp;lt;br /&amp;gt;&lt;br /&gt;  &amp;lt;/ItemTemplate&amp;gt;&lt;br /&gt;&amp;lt;/asp:Repeater&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Next I created a &lt;font face="Courier New"&gt;Page_Load&lt;/font&gt; event handler and &lt;font face="Courier New"&gt;BindData()&lt;/font&gt; method that looked like the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load&lt;br /&gt;        BindData()&lt;br /&gt;    End Sub&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;    Private Sub BindData()&lt;br /&gt;        Dim a As New ArrayList&lt;br /&gt;        a.Add(1) : a.Add(2) : a.Add(3)&lt;br /&gt;        Repeater1.DataSource = a&lt;br /&gt;        Repeater1.DataBind()&lt;br /&gt;    End Sub&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Notice that the data is bound to the Repeater on each and every &lt;font face="Courier New"&gt;Page_Load&lt;/font&gt;.  If I placed the call to &lt;font face="Courier New"&gt;BindData()&lt;/font&gt; in &lt;font face="Courier New"&gt;Page_Load&lt;/font&gt; within an &lt;font face="Courier New"&gt;If&lt;/font&gt; statement so that it only ran when &lt;font face="Courier New"&gt;Not Page.IsPostBack&lt;/font&gt;, then the problems described above did not occur.&lt;/p&gt;
&lt;p&gt;Following these two methods, I created event handlers for the Button and LinkButton's &lt;font face="Courier New"&gt;Command&lt;/font&gt; event, as well as an event handler for the Repeater's &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;    Private Sub Repeater1_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles Repeater1.ItemCommand&lt;br /&gt;        Response.Write(String.Concat("&amp;lt;b&amp;gt;ItemCommand&amp;lt;/b&amp;gt;: The CommandName = ", e.CommandName, "&amp;lt;br /&amp;gt;"))&lt;br /&gt;    End Sub&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;    Protected Sub bCommand(ByVal sender As Object, ByVal e As CommandEventArgs)&lt;br /&gt;        Response.Write("Button Command event fired!&amp;lt;br /&amp;gt;")&lt;br /&gt;    End Sub&lt;/p&gt;
&lt;p&gt;    Protected Sub lCommand(ByVal sender As Object, ByVal e As CommandEventArgs)&lt;br /&gt;        Response.Write("LinkButton Command event fired!&amp;lt;br /&amp;gt;")&lt;br /&gt;    End Sub&lt;/p&gt;
&lt;p&gt;Again, when running this demo the LinkButton, when clicked, would display “LinkButton &lt;font face="Courier New"&gt;Command&lt;/font&gt; event fired” &lt;strong&gt;and&lt;/strong&gt; “&lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event fired.”  The Button Web control, however, would &lt;strong&gt;only&lt;/strong&gt; display “Button &lt;font face="Courier New"&gt;Command&lt;/font&gt; event fired.”  It was apparent that the Button's &lt;font face="Courier New"&gt;Command&lt;/font&gt; event was indeed firing, but the Repeater's &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; was not.  In an attempt to shed more light onto this I added code in the &lt;font face="Courier New"&gt;Command&lt;/font&gt; event handlers to print out the control that raised the event (the Button or LinkButton), along with its ancestors in the control hierarchy.  The results stupefied me.  For the LinkButton, the results were as expected:&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;Control Ascestors: Repeater1:_ctl1:linkButtonTest (System.Web.UI.WebControls.LinkButton) --&amp;gt; Repeater1:_ctl1 (System.Web.UI.WebControls.RepeaterItem) --&amp;gt; Repeater1 (System.Web.UI.WebControls.Repeater) --&amp;gt; _ctl0 (System.Web.UI.HtmlControls.HtmlForm) --&amp;gt; (ASP.test_aspx)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the LinkButton was first printed, it's Parent was the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt;, it's Parent was the Repeater, it's parent was the Web Form, and it's Parent was the ASP.NET Page object.  The Button results, however, were a shock:&lt;/p&gt;
&lt;p&gt;&lt;font face="Courier New"&gt;Control Ascestors: _ctl0:buttonTest (System.Web.UI.WebControls.Button) --&amp;gt; _ctl0 (System.Web.UI.WebControls.RepeaterItem)&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;The Button's Parent, as expected, was the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt;, but &lt;strong&gt;the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; has no Parent&lt;/strong&gt;!  This explained why the Repeater's &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event was not firing - the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; could not bubble up the &lt;font face="Courier New"&gt;RepeaterCommandEventArgs&lt;/font&gt; up to the Repeater to raise the &lt;font face="Courier New"&gt;ItemCommand&lt;/font&gt; event.  But &lt;em&gt;why&lt;/em&gt; isn't there a parent for the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt;?  The Button's &lt;font face="Courier New"&gt;Command&lt;/font&gt; event fires &lt;em&gt;after&lt;/em&gt; &lt;font face="Courier New"&gt;Page_Load&lt;/font&gt;, where the control hierarchy is created (via the call to &lt;font face="Courier New"&gt;BindData()&lt;/font&gt;, which calls the Repeater's &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt; method).  So the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; should indeed have a parent, namely the Repeater!&lt;/p&gt;
&lt;p&gt;I decided to create a method to print out the entire control hierarchy.  I then called this method both right after the Repeater was databound and in the Button &lt;font face="Courier New"&gt;Command&lt;/font&gt; event handler.  The results were as expected: the entire control tree was displayed, showing that the &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; did indeed have the Repeater as its parent.&lt;/p&gt;
&lt;p&gt;&lt;code&gt; Repeater1 (Parent = _ctl0)&lt;br /&gt;    Repeater1:_ctl0 (Parent = Repeater1)&lt;br /&gt;       Repeater1:_ctl0:_ctl0 (Parent = Repeater1:_ctl0)&lt;br /&gt;       Repeater1:_ctl0:linkButtonTest (Parent = Repeater1:_ctl0)&lt;br /&gt;       Repeater1:_ctl0:_ctl1 (Parent = Repeater1:_ctl0)&lt;br /&gt;       Repeater1:_ctl0:buttonTest (Parent = Repeater1:_ctl0)&lt;br /&gt;       Repeater1:_ctl0:_ctl2 (Parent = Repeater1:_ctl0)&lt;br /&gt;    Repeater1:_ctl1 (Parent = Repeater1)&lt;br /&gt;       Repeater1:_ctl1:_ctl0 (Parent = Repeater1:_ctl1)&lt;br /&gt;       Repeater1:_ctl1:linkButtonTest (Parent = Repeater1:_ctl1)&lt;br /&gt;       Repeater1:_ctl1:_ctl1 (Parent = Repeater1:_ctl1)&lt;br /&gt;       Repeater1:_ctl1:buttonTest (Parent = Repeater1:_ctl1)&lt;br /&gt;       Repeater1:_ctl1:_ctl2 (Parent = Repeater1:_ctl1)&lt;br /&gt;    Repeater1:_ctl2 (Parent = Repeater1)&lt;br /&gt;       Repeater1:_ctl2:_ctl0 (Parent = Repeater1:_ctl2)&lt;br /&gt;       Repeater1:_ctl2:linkButtonTest (Parent = Repeater1:_ctl2)&lt;br /&gt;       Repeater1:_ctl2:_ctl1 (Parent = Repeater1:_ctl2)&lt;br /&gt;       Repeater1:_ctl2:buttonTest (Parent = Repeater1:_ctl2)&lt;br /&gt;       Repeater1:_ctl2:_ctl2 (Parent = Repeater1:_ctl2)&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;So each of the three &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt;s has a Parent in the Button &lt;font face="Courier New"&gt;Command&lt;/font&gt; event... but it seems like the Button does not have a &lt;font face="Courier New"&gt;RepeaterItem&lt;/font&gt; with a Parent.  What in the world is happening here?  And why does it work with the LinkButton but not the Button Web control?  Why does it work if the Repeater's &lt;font face="Courier New"&gt;DataBind()&lt;/font&gt; method was not called on that page visit?  Using &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector&lt;/a&gt;, I've poured over the source code for the Repeater, Button, LinkButton, and Page class, but am at a loss.  Does anyone have any ideas?  Am I missing something simple?&lt;/p&gt;
&lt;p&gt;My test case can be viewed online &lt;a href="http://scottonwriting.net/demos/RepeaterWeirdness.aspx"&gt;here&lt;/a&gt; (includes complete source code).&lt;/p&gt;
&lt;p&gt;Thanks for any possible insight...&lt;/p&gt;
&lt;p&gt;P.S.: If you can explain why this is happening, and if you're at Tech-Ed this year, I'll buy you a beer!!  :-)&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162928" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item><item><title>Panel Weirdness</title><link>http://scottonwriting.net/sowblog/archive/2004/04/28/162943.aspx</link><pubDate>Wed, 28 Apr 2004 16:14:00 GMT</pubDate><guid isPermaLink="false">2814ed8b-42a8-4dfe-b0b1-a7acb3e6d762:162943</guid><dc:creator>Scott Mitchell</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://scottonwriting.net/sowblog/rsscomments.aspx?PostID=162943</wfw:commentRss><comments>http://scottonwriting.net/sowblog/archive/2004/04/28/162943.aspx#comments</comments><description>&lt;p&gt;I recently responded to a &lt;a href="http://groups.google.com/groups?dq=&amp;amp;hl=en&amp;amp;lr=&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8&amp;amp;group=microsoft.public.dotnet.framework.aspnet.webcontrols&amp;amp;safe=off&amp;amp;selm=O3zc4lRLEHA.2400%40tk2msftngp13.phx.gbl"&gt;newsgroup post&lt;/a&gt; on &lt;a href="http://groups.google.com/groups?hl=en&amp;amp;lr=&amp;amp;ie=UTF-8&amp;amp;oe=UTF-8&amp;amp;safe=off&amp;amp;group=microsoft.public.dotnet.framework.aspnet.webcontrols"&gt;microsoft.public.dotnet.framework.aspnet.webcontrols&lt;/a&gt; that I thought warranted a follow-up comment here.  The posters question was:&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;I have a Panel control containing a few TextBox controls.  The Panel is originally enabled, I enter data into the TextBox controls.  When I submit, the Panel is disabled during the PostBack and the TextBox controls render greyed-out, and I can see the values in the TextBox controls....this is what I expected.&lt;/p&gt;
&lt;p&gt;I submit again, the Panel is enabled during the PostBack.  All of the TextBox controls within the Panel are now enabled, however, the values are gone.  This doesn't happen with a TextBox control outside of the Panel that is also enabled/disabled.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p dir="ltr"&gt;The post then contained a sample ASP.NET Web page that illustrated the problem.  Namely, it had a Panel Web control with a TextBox Web control inside of it, along with a CheckBox and a Button outside of the Panel.  When the page was posted back, if the CheckBox was checked the Panel's &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property was set to False; if the CheckBox was unchcekd, the &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property was set to True.&lt;/p&gt;
&lt;p dir="ltr"&gt;I started by testing the poster's source code in &lt;a href="http://www.mozilla.org/products/firefox/"&gt;Mozilla Firefox&lt;/a&gt;, my default browser.  When the Panel's &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property was set to False, the TextBox was still editable and not grayed out, nor did I lose the TextBox value when posting back after it was disabled.  Doing a view source illustrated why: the Panel renders as a &lt;font face="Courier New"&gt;&amp;lt;table&amp;gt;&lt;/font&gt; for downlevel browsers.  Setting the &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property to False created a table with the attribute &lt;font face="Courier New"&gt;disabled=”disabled”&lt;/font&gt;.&lt;/p&gt;
&lt;p dir="ltr"&gt;Switching to IE6, I reran the test and was able to replicate the poster's problem.  IE6 renders a Panel as a &lt;font face="Courier New"&gt;&amp;lt;div&amp;gt;&lt;/font&gt;.  When the Panel's &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property was set to False, the following HTML markup was generated:&lt;/p&gt;
&lt;p dir="ltr"&gt;&lt;code&gt;&amp;lt;div id="panelID" disabled="disabled"&amp;gt;&lt;br /&gt;  &amp;lt;input type="text" name="textboxID" id="textboxID" value="valueEnteredOnLastPostback" /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p dir="ltr"&gt;Note that the disabled attribute only applies to the &lt;font face="Courier New"&gt;&amp;lt;div&amp;gt;&lt;/font&gt;, and not the &lt;font face="Courier New"&gt;&amp;lt;input&amp;gt;&lt;/font&gt;.  (This was the case in Firefox, too, except instead of a &lt;font face="Courier New"&gt;&amp;lt;div&amp;gt;&lt;/font&gt; it was a &lt;font face="Courier New"&gt;&amp;lt;table&amp;gt;&lt;/font&gt;.)  Interestingly, with this HTML markup, IE displays the TextBoxes as grayed out - however, I could edit them!  What's &lt;em&gt;really&lt;/em&gt; interesting, though, is that when the form is submitted, IE doesn't send back the values of the TextBoxes in the HTTP POST header.  I guess it hits the &lt;font face="Courier New"&gt;&amp;lt;div&amp;gt;&lt;/font&gt;, sees that it is disabled, and then doesn't bother processing the &lt;font face="Courier New"&gt;&amp;lt;div&amp;gt;&lt;/font&gt;'s inner children. (Firefox always posts back the TextBox value, regardless of the value of the enclosing &lt;font face="Courier New"&gt;&amp;lt;table&amp;gt;&lt;/font&gt;'s &lt;font face="Courier New"&gt;disabled&lt;/font&gt; attribute.)  Since the TextBox value is not posted back when the Panel is disabled, the TextBox loses its Text property value, resulting in an empty TextBox on postback.  The solution to this problem is to explicitly set the TextBox's &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property to False - not just the Panel's.&lt;/p&gt;
&lt;p dir="ltr"&gt;The reason the problem exists is because when a visitor enters a value into a TextBox, and posts back the form, that value is not persisted into the TextBox's view state.  Yes, the value is saved to the TextBox's &lt;font face="Courier New"&gt;ViewState&lt;/font&gt; property, but the view state for the TextBox is only saved if the TextBox's &lt;font face="Courier New"&gt;TrackViewState&lt;/font&gt; property is set to True.  I'm going to gloss over the sticky internal details, but realize that the TextBox does not record its Text property value in its view state if the TextBox is a Password TextBox or if there is not an event handler wired up to the TextBox's TextChanged event.  If the Text property is the only property set after the Initialization stage, then the TextBox won't record any view state information.  The means by which TextBox's persist their &lt;font face="Courier New"&gt;Text&lt;/font&gt; values across postback is by having the TextBox value continually posted back in the HTTP POST headers... but when using a disabled &lt;font face="Courier New"&gt;&amp;lt;div&amp;gt;&lt;/font&gt;, the TextBox value is not posted back.&lt;/p&gt;
&lt;p dir="ltr"&gt;An astute reader might then counter, “Well, if what you say is true, then why does explicitly setting the TextBox's &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property to False make everything work?  After all, when the Panel is disabled, the TextBox's value is not being posted back, right?”  Right you are, but when you set the &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; property to False explicitly, that has the side-effect of setting the TextBox's &lt;font face="Courier New"&gt;TrackViewState&lt;/font&gt; property to True, so &lt;em&gt;both&lt;/em&gt; the TextBox's &lt;font face="Courier New"&gt;Enabled&lt;/font&gt; and &lt;font face="Courier New"&gt;Text&lt;/font&gt; properties will be persisted to view state, and hence be used to repopulate the TextBox.&lt;/p&gt;
&lt;p dir="ltr"&gt;A final question readers might have is, “How in the world did you find out all this stuff?”  Through the book &lt;a href="http://www.4guysfromrolla.com/ASPScripts/Goto.asp?ID=170"&gt;&lt;em&gt;Developing Microsoft ASP.NET Server Controls&lt;/em&gt;&lt;/a&gt;; using &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Reflector&lt;/a&gt; to look at the decompiled source code of the &lt;font face="Courier New"&gt;System.Web.UI.Control&lt;/font&gt;, &lt;font face="Courier New"&gt;System.Web.UI.Page&lt;/font&gt;, &lt;font face="Courier New"&gt;System.Web.UI.WebControls.TextBox&lt;/font&gt;, and &lt;font face="Courier New"&gt;System.Web.UI.WebControls.WebControl&lt;/font&gt;; and using a view state parser (specifically, I used one I will be presenting in an upcoming article on ASP.NET View State on MSDN, but you could use &lt;a href="http://weblogs.asp.net/pwilson/"&gt;Paul Wilson&lt;/a&gt;'s &lt;a href="http://www.wilsondotnet.com/Demos/ViewState.aspx"&gt;View State Parser&lt;/a&gt;, or Fritz Onion's &lt;a href="http://staff.develop.com/onion/resources.htm"&gt;ViewState Decoder&lt;/a&gt;).&lt;/p&gt;&lt;img src="http://scottonwriting.net/aggbug.aspx?PostID=162943" width="1" height="1"&gt;</description><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+Talk/default.aspx">ASP.NET Talk</category><category domain="http://scottonwriting.net/sowblog/archive/tags/ASP.NET+View+State/default.aspx">ASP.NET View State</category></item></channel></rss>