Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Viewstate is null on postback

Right, I've got something very peculiar going on here...

ASP.NET 4 page with the following property:

protected QuickShopBag QuickShopBagInstance
{
    get { return (QuickShopBag)ViewState["QuickShopBag"]; }
    set { ViewState["QuickShopBag"] = value; }
}

During the initial Page_Load() in (!Page.IsPostBack) the QuickShopBagInstance is populated and ViewState saved.

However when you perform a postback on the page the ViewState is empty when accessed from the postback Button_OnClick() event!!!

I've checked the Request.Form and sure enough the _Viewstate value is there and is populated. I've also ran this value through a parser and it does contain the expected data, the page has ViewStateEnabled="true" and the new .NET 4 ViewStateMode="Enabled".

I've moved on to override the LoadViewState method to check to see if it is firing, it doesn't appear to be.

protected override void LoadViewState(object savedState)
{
    base.LoadViewState(savedState);
}

I am really lost as to what could possibly be the problem. Any ideas?

like image 627
James Law Avatar asked Dec 02 '11 11:12

James Law


2 Answers

First of all I was mistaken, the code in question was not in Page_Load but in Page_Init, although I haven't read anything that says you can't assign to ViewState at Init.

So I put together a very basic test that duplicates the problems I'm having...

<form id="form1" runat="server">
<div>
    <asp:ListView id="QuickshopListView" runat="server">
        <LayoutTemplate>
            <asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
        </LayoutTemplate>
        <ItemTemplate>
            <asp:TextBox ID="txtItem" runat="server" Text='<%# Container.DataItem %>' />
            <asp:Button ID="btnDelete" runat="server" Text="Delete" OnClick="btnDelete_Click" />
            <br />
        </ItemTemplate>
    </asp:ListView>
    <asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
</div>
</form>

public partial class Quickshop : System.Web.UI.Page
{
    protected QuickShopBag QuickShopBagInstance
    {
        get { return (QuickShopBag)ViewState["QuickShopBag"]; }
        set { ViewState["QuickShopBag"] = value; }
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            if (QuickShopBagInstance == null)
                QuickShopBagInstance = new QuickShopBag();

            if (!String.IsNullOrEmpty(Request.QueryString.ToString()))
            {
                string[] items = Server.UrlDecode(Request.QueryString.ToString()).Split(',');
                if (items.Length > 0)
                {
                    foreach (string item in items)
                    {
                        QuickShopBagInstance.QuickShopItems.Add(item);
                    }
                }
            }
        }
    }

    protected void Page_LoadComplete(object sender, EventArgs e)
    {
        QuickshopListView.DataSource = QuickShopBagInstance.QuickShopItems;
        QuickshopListView.DataBind();
    }

    protected void btnAdd_Click(object sender, EventArgs e)
    {
        if (QuickShopBagInstance == null)
            QuickShopBagInstance = new QuickShopBag();

        QuickShopBagInstance.QuickShopItems.Add("add1");
        QuickShopBagInstance.QuickShopItems.Add("add2");
        QuickShopBagInstance.QuickShopItems.Add("add3");
    }

    protected void btnDelete_Click(object sender, EventArgs e)
    {
        Button DeleteButton = (Button)sender;
        ListViewDataItem item = (ListViewDataItem)DeleteButton.NamingContainer;
        QuickShopBagInstance.QuickShopItems.RemoveAt(item.DisplayIndex);
    }
}

[Serializable]
public class QuickShopBag
{
    public List<string> QuickShopItems { get; set; }

    public QuickShopBag()
    {
        this.QuickShopItems = new List<string>();
    }
}

If you request say "/quickshop.aspx?add1,add2,add3", the ListView is populated correctly with the data from the qs, however when it comes to clicking the delete button a NullReferenceException is thrown because the ViewState hasn't persisted the QuickShopBag object.

But if you click the "Add" button, which as you can see adds to the same values to the QuickShopBagInstance (and ViewState), the ListView is populated correctly and when you click the Delete button it works perfectly as the ViewState has been persisted.

Now if you change the reading the querystring bit to Page_InitComplete as opposed to Page_Init it works perfectly. So the conclusion is...

YOU CAN'T ADD TO THE VIEWSTATE BEFORE Init_Complete!!!!!!!!

How silly of me, well whoever wrote it at least!

like image 177
James Law Avatar answered Nov 17 '22 20:11

James Law


You seem to have ruled out most of the suggestions so far so I've created a basic page with only the information you've provided above:

class

namespace SO_Questions
{
    [Serializable()]
    public class QuickShopBag
    {
        public string MyProperty { get; set; }
    }
}

code behind

namespace SO_Questions
{
    public partial class TestPage : System.Web.UI.Page
    {
        protected QuickShopBag QuickShopBagInstance
        {
            get { return (QuickShopBag)ViewState["QuickShopBag"]; }
            set { ViewState["QuickShopBag"] = value; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                this.QuickShopBagInstance = new QuickShopBag() { MyProperty = "Test String" };
            }
            Message.Text = "Value is: " + this.QuickShopBagInstance.MyProperty.ToString();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            btnSubmit.Text += QuickShopBagInstance.MyProperty;
        }
    }
}

markup:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestPage.aspx.cs" Inherits="SO_Questions.TestPage" ViewStateMode="Enabled" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"><title></title></head>
<body>
    <form id="form1" runat="server"><div>
        <asp:Label ID="Message" runat="server"></asp:Label>
        <asp:Button runat="server" ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click" />
    </div></form>
</body></html>

As expected, this runs correctly; the overridden LoadViewState method is hit (and viewstate correctly contains 2 items) and the button's text is updated.

The logical explanation would be that there's something else going on somewhere else, or you've failed to provide an additional salient piece of information.

like image 1
Dave Avatar answered Nov 17 '22 20:11

Dave