ViewState

Hi,
I have a site with a couple of pages. On one of them there is a bunch of data the visitor shall supply. If he leaves this page and then comes back all his work is gone. Which is the easiest way to persist the data as a whole. I have been looking at using VIEWSTATE but I can't figure out how to do. I would not like to save the individual controls but everything on the page.
Best regards
RTSol
RTSolAsked:
Who is Participating?
 
vbwizardryCommented:
Here is the full code.
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
 
        protected override PageStatePersister PageStatePersister
        {
            get
            {
                return new CacheStatePersister(this);
            }
        }
 
        protected override System.Collections.Specialized.NameValueCollection DeterminePostBackMode()
        {
            var id = CatchID;
            var value = base.DeterminePostBackMode();
            if (value == null)
            {
                var mode = Session[id] as System.Collections.Specialized.NameValueCollection;
                if (mode != null)
                {
                    Debug.Print("Load saved PostBack");
                    return mode;
                }
            }
            Debug.Print("Use existing PostBack");
            Session[id] = value;
            return value;
        }
 
        [System.Web.AspNetHostingPermission(System.Security.Permissions.SecurityAction.Demand, Level = System.Web.AspNetHostingPermissionLevel.Minimal)]
        private class CacheStatePersister : System.Web.UI.PageStatePersister
        {
 
            private string CatchID
            {
                get
                {
                    return (Page.Session.SessionID + "_" + Page.GetType().FullName + "_" + DateTime.Now.Date.Ticks).ToUpper();
                }
            }
 
            public CacheStatePersister(Page page)
                : base(page)
            { }
            
            public override void Load()
            {
                var id = CatchID;
                Debug.WriteLine("Persister load: " + id);
                var state = Page.Cache[id] as Pair;
                if (state == null)
                {
                    base.ViewState = null;
                    return;
                }
                base.ViewState = state.First;
                base.ControlState = state.Second;
            }
 
            public override void Save()
            {
                var id = CatchID;
                if (ViewState != null || ControlState != null)
                {
                    Debug.WriteLine("Persister save: " + id);
                    if (Page.Cache == null)
                    { throw new InvalidOperationException("Caching is not enabled!"); }
                    Page.Cache.Remove(id);
 
                    Page.Cache.Add(
                        id,
                        new Pair(ViewState, ControlState),
                        null,
                        DateTime.Now.AddMinutes(Page.Session.Timeout),
                        TimeSpan.Zero,
                        System.Web.Caching.CacheItemPriority.Default,
                        null);
                }
            }
        }
 
        private string CatchID
        {
            get
            {
                return (Page.Session.SessionID + "_" + Page.GetType().FullName + "_" + DateTime.Now.Date.Ticks).ToUpper();
            }
        }
 
    }

Open in new window

0
 
DanielWillmottCommented:
I found this nice set of code to do what you are looking for. It saves the ViewState in cache and then will call it back up if the user goes back to the page and the current ViewState is empty. It overrides the 'SavePageStateToPersistenceMedium' and
'LoadPageStateFromPersistenceMedium' methods of the page. (C#)
protected override void SavePageStateToPersistenceMedium(Object viewState)
{
string _vskey;
_vskey = "VIEWSTATE_" + base.Session.SessionID + "_" + Request.RawUrl + 
"_" + System.DateTime.Now.Ticks.ToString();
 
Cache.Add(_vskey, viewState, null, 
System.DateTime.Now.AddMinutes(Session.Timeout), Cache.NoSlidingExpiration, 
CacheItemPriority.Default, null);
 
RegisterHiddenField("_VIEWSTATE_KEY", _vskey);
}
 
protected override object LoadPageStateFromPersistenceMedium()
{
string _vskey = Request.Form["_VIEWSTATE_KEY"];
 
if (_vskey == null)
{
return null; 
}
else
{
return Cache[_vskey];
}
}

Open in new window

0
 
RTSolAuthor Commented:
Hi,
I tried the code but I am not sure how to use it. I made a small site with two pages containing a textbox and a drop down. I have attached the code in one of the pages. When I first call the page SavePageStateToPersistenceMedium is fired. When I change the drop down (Which has postpack enabled) first LoadPageStateFromPersistenceMedium() is fired and then  SavePageStateToPersistenceMedium is fired. When I leave the page neither of the mehtods are fired. Cab you help me out?
-RTSol
Page 1
 
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test1.aspx.cs" Inherits="Test1" %>
 
<!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:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Test1.aspx">Test1</asp:HyperLink>&nbsp;
        <asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl="~/Test2.aspx">Test2</asp:HyperLink>
    </div>
    </form>
</body>
</html>
 
Page 2
 
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test2.aspx.cs" Inherits="Test2" %>
 
<!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:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Test1.aspx">Test1</asp:HyperLink>&nbsp;
        <asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl="~/Test2.aspx">Test2</asp:HyperLink>
        <br /><br /><asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <br /><br />
        <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True">
            <asp:ListItem>first value</asp:ListItem>
            <asp:ListItem>second value</asp:ListItem>
        </asp:DropDownList>
    </div>
    </form>
</body>
</html>
 
Code in page 2
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Caching;
 
public partial class Test2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
 
    }
    protected override void SavePageStateToPersistenceMedium(Object viewState)
    {
        string _vskey;
        _vskey = "VIEWSTATE_" + base.Session.SessionID + "_" + Request.RawUrl +
        "_" + System.DateTime.Now.Ticks.ToString();
 
        Cache.Add(_vskey, viewState, null,
        System.DateTime.Now.AddMinutes(Session.Timeout), Cache.NoSlidingExpiration,
        CacheItemPriority.Default, null);
 
        RegisterHiddenField("_VIEWSTATE_KEY", _vskey);
    }
 
    protected override object LoadPageStateFromPersistenceMedium()
    {
        string _vskey = Request.Form["_VIEWSTATE_KEY"];
 
        if (_vskey == null)
        {
            return null;
        }
        else
        {
            return Cache[_vskey];
        }
    }
}

Open in new window

0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

 
DanielWillmottCommented:
When you go to a different page somewhere and then go to the page above, the LoadPageStateFromPersistenceMedium whould fire and load the page state from the Cache value. Did you try that?
0
 
RTSolAuthor Commented:
Yes - I tried that, but the first thing that fires when you enter the page is SavePageStateToPersistenceMedium which seems a bit backwards. The firing sequence is as I described in my previous post.
-RTSol
0
 
Anurag ThakurTechnical ManagerCommented:
0
 
vbwizardryCommented:
The problem that I see in code is that if you live the page the next time you come back there will be no "_VIEWSTATE_KEY" since it has not been generated yt. (Unless you come back by using back button on web browser). So perhaps a better way to store you data in in the session. However what I think you want to do is this:

        public override PageStatePersister GetStatePersister() {
            return new CacheStatePersister(this.Page);
        }
 
 
        [System.Web.AspNetHostingPermission(System.Security.Permissions.SecurityAction.Demand, Level = System.Web.AspNetHostingPermissionLevel.Minimal)]
        private class CacheStatePersister : System.Web.UI.PageStatePersister
        {
 
            public CacheStatePersister(Page page)
                : base(page)
            { }
 
            private string CatchID
            {
                get
                {
                    return (Page.Session.SessionID + "_" + Page.Request.RawUrl + "_" + DateTime.Now.Date.Ticks);
                }
            }
 
            public override void Load()
            {
                var state = Page.Cache[CatchID] as Pair;
                if (state == null)
                {
                    base.ViewState = null;
                    return;
                }
                base.ViewState = state.First;
                base.ControlState = state.Second;
            }
 
            public override void Save()
            {
                if (ViewState != null || ControlState != null)
                {
                    if (Page.Cache == null)
                    { throw new InvalidOperationException("Caching is not enabled!"); }
                    Page.Cache.Remove(CatchID);
 
                    Page.Cache.Add(
                        CatchID,
                        new Pair(ViewState, ControlState),
                        null,
                        DateTime.Now.AddMinutes(Page.Session.Timeout),
                        TimeSpan.Zero,
                        System.Web.Caching.CacheItemPriority.Default,
                        null);
                }
            }
        }

Open in new window

0
 
RTSolAuthor Commented:
Hi vbwizardry,

I tried your piece of code but got the following error when building: Test2.GetStatePersister()': no suitable method found to override

Can you help me out? I attached the code.

Best regards
RTSol
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Caching;
 
public partial class Test2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
 
    }
    public override PageStatePersister GetStatePersister()
    {
        return new CacheStatePersister(this.Page);
    }
 
 
    [System.Web.AspNetHostingPermission(System.Security.Permissions.SecurityAction.Demand, Level = System.Web.AspNetHostingPermissionLevel.Minimal)]
    private class CacheStatePersister : System.Web.UI.PageStatePersister
    {
 
        public CacheStatePersister(Page page)
            : base(page)
        { }
 
        private string CatchID
        {
            get
            {
                return (Page.Session.SessionID + "_" + Page.Request.RawUrl + "_" + DateTime.Now.Date.Ticks);
            }
        }
 
        public override void Load()
        {
            var state = Page.Cache[CatchID] as Pair;
            if (state == null)
            {
                base.ViewState = null;
                return;
            }
            base.ViewState = state.First;
            base.ControlState = state.Second;
        }
 
        public override void Save()
        {
            if (ViewState != null || ControlState != null)
            {
                if (Page.Cache == null)
                { throw new InvalidOperationException("Caching is not enabled!"); }
                Page.Cache.Remove(CatchID);
 
                Page.Cache.Add(
                    CatchID,
                    new Pair(ViewState, ControlState),
                    null,
                    DateTime.Now.AddMinutes(Page.Session.Timeout),
                    TimeSpan.Zero,
                    System.Web.Caching.CacheItemPriority.Default,
                    null);
            }
        }
    }
}

Open in new window

0
 
vbwizardryCommented:
That because I used a PageAdapter. You need to override PageStatePersister in your page behind code.
        protected override System.Web.UI.PageStatePersister PageStatePersister
        {
            get
            {
                return new CacheStatePersister(this.Page);
            }
        }

Open in new window

0
 
RTSolAuthor Commented:
Thanks Guys,
I appreciate your effort and I am happy. I will use the solution provided by vbwizardry. The article in the codeproject given by ragi0017 was very enlightening.
Best regards
RTSol
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.