Why we get the exception “Failed to load viewstate”

Background

When we try to add controls dynamically during the post-back request for an ASPX page, we may get below error:

Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

  
 [HttpException (0x80004005): Failed to load viewstate.  The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request.  For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.]
    System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +310
    System.Web.UI.Control.AddedControl(Control control, Int32 index) +302
    System.Web.UI.ControlCollection.Add(Control child) +146
    WebUserControl.Page_Load(Object sender, EventArgs e) +110
    System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +15
    System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +33
    System.Web.UI.Control.OnLoad(EventArgs e) +99
    System.Web.UI.Control.LoadRecursive() +47
    System.Web.UI.Control.LoadRecursive() +131
    System.Web.UI.Control.LoadRecursive() +131
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1436

 Actually, we can reproduce this kind of exception easily with below code snippet:

 

protected void Page_Load(object sender, EventArgs e)

 

    {

 

        Button btn4PostBack = new Button();
        btn4PostBack.Text = "Click me to POST back to web server ";
        form1.Controls.Add(btn4PostBack);
        if (!IsPostBack)

 

        {
            GridView gv = new GridView();
            form1.Controls.Add(gv);
        }

 

        else

 

        {
            Button btnClickMe = new Button();
            btnClickMe.Text = "Click me";
            form1.Controls.Add(btnClickMe);
        }

 

}

 

So the question is: why we get above exception while we try to add controls dynamically?

Cause

As we know, we use VIEWSTATE which is stored at a hidden filed called _VIEWSTATE to restore controls status for the post-back Request, just like below:

“…

<div>

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTcwMzIxOTA3Ng9kabcAw9kFgICAw9kFgJmabcwrAA0AZBgBBRVXZWJVc2VyQ29udHJvbDEkY3RsMDAPZ2S95O9gAO7zi4zDomJbUayuj3/4Fw==" />

</div>


At the same time, the controls’ status is stored with a kind of ArrayList which consist of PAIR or Triplet. Let’s saying:

Position: Index 0, Type: Button
Position: Index 1, Type: literal
Position: Index 2, Type: RadioButton

So for the current POST-BACK request, when you try to add controls dynamically, the newly added control will be validated and see if it matches the control stored in the previous VIEWSTAT. If not, you will get above exception.

Resolution

Option 1:

You can disable the VIEWSTATE of this ASPX page :
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind=" #####.aspx.cs" Inherits="#####" EnableViewState="false"%>

Option 2:

You can also change your source code to make sure the controls added during a post-back must match the type and position of the controls added during the initial request.

 

References

1)      Understanding ASP.NET View State

https://msdn.microsoft.com/en-us/library/ms972976.aspx

2)      Triplet Class

https://msdn.microsoft.com/en-us/library/system.web.ui.triplet(v=VS.80).aspx

 

 Winston from APGC team