uber1024's WebLog

It's not hot wings and beer, but it's still okay

Storing Viewstate in other places by overriding the Page object

When building the messageboards of the 700level, I was coming across a situation where my ViewState was winding up being on the order of 50K-100K which was unacceptable for dialup users. In addition, they were the most heavily trafficked pages with users sitting on them clicking "refresh" to see the latest posts so I was afraid of what would happen to our bandwidth usage during playoff times (the site is a Philadelphia Eagles fansite). At the time, I needed the viewstate to handle events such as the PageChanged event of the DataGrid. I've since rewritten one of the DataGrids as a Repeater and implemented all my own paging code, so this code will soon come out of my site, but I wanted to document it here before that happened in case anyone else might find this useful ... perhaps on an intranet-type of project where the userbase can be calculated in advance.

I'll just paste the code and talk about it more at the end:

public class ViewStateService : System.Web.UI.Page
{
  public
ViewStateService()
  {
  }
  protected override object LoadPageStateFromPersistenceMedium()
  {
    LosFormatter oLosFormatter =
new LosFormatter();
    if (Session["ViewState"] == null)
    {
      Response.Redirect( "/fansview/default.aspx",
true );
    }
    return oLosFormatter.Deserialize(Session["ViewState"].ToString());
  }
  protected override void SavePageStateToPersistenceMedium(object viewState)
  {
    LosFormatter oLosFormatter =
new LosFormatter();
    StringWriter oStringWriter =
new StringWriter();

    oLosFormatter.Serialize(oStringWriter, viewState);
    Session["ViewState"] = oStringWriter.ToString();
  }
  protected override void Render(HtmlTextWriter writer)
  {
    if (Request.Path != null)
    {
      writer =
new MyWriter(writer);
    }
    base.Render (writer); 
  }
}

Okay, looking over this, the important parts are LoadPageStateFromPersistanceMedium which now checks a Session variable instead of the hidden field on the page and SavePageStateFromPersistanceMedium which does the same thing in reverse. Notice how I check to see if the Session variable exists and, if not, I bounce the user back to the default page for that section. I couldn't think of anything better to do with a user with an expired session and I didn't want their page to blow up with the viewstate error, so I sent them back to the list of forums. The LosFormatter objects pretty much just serialize and deserialize all of the state information into the garbage that you see when you look at the viewstate.

The overriding of the Render method is being done to override the default HtmlTextWriter behavior like I describe in this post about removing the action attribute from the form tag. You can remove that safely and still have your ViewState functionality working. I just included it in this post because I said I would in my last one.

The implications of this were that I would wind up using about 80K (on average) of Session space for each user. I usually have around 30 users on the site, maybe 50 or 60 during the playoffs, and it handled it well. A quick calculation shows that 50 users would use about 4 megs of RAM ... very doable today and in my mind and adequate tradeoff for not having to force that 80K of data down a 56K pipe, especially since my graphic designer uses a lot of graphics in our sites that our users have to download, so I didn't want to make users download anything more than they needed from me. Most of the site does not use this new Page object and the pages have viewstate as normal, but the pages that form the engine that drives the messageboards do use this page (and they are by far the most heavily used pages ... I think the page that displays threads gets about 40 times the number of hits as the next most heavily used section of the site).

So I hope this helps someone out there, or at least gets them thinking about some of the possibilities of things you can do with ASP.NET. If you have time, I suggest you dig through the Page class's protected methods and see what kinds of things it's doing under the hood. You'll get a much better understanding of how pages are built by the runtime.  By the way, I'm not saying that this is the BEST way to do this or that storing ViewState in Sessions is the BEST approach to handling this.

Comments

Scott Galloway said:

Hi, you'll have to be a bit careful when doing this - especially in the case where a user hits the 'back' key - in that instance the Session held Viewstate would no longer be valid for the postback. You can read about some of the issues here: http://www.artima.com/forums/flat.jsp?forum=152&thread=36577
In general, you need to ensure that your Session hel;d viewstate is for the correct request path and request - possibly by using an ID held in-page and some outside persistence medium.
# April 8, 2004 2:12 PM

Scott Galloway said:

Oh, incidentally, this is the best one I've come across: http://authors.aspalliance.com/robertb/articles.aspx?articleId=2
# April 8, 2004 2:13 PM

uber said:

Those are good articles. Strangely, I've implemented this in TWO different projects, one is the website I linked, and the other was a relatively large application wherein users provisioned events for an international marketing company (it had to keep track of people, bars, hotels, drinks, accounts, special rules, etc) and there was never a problem. Nine times out of ten, my viewstates are not that troublesome, but with large datagrids they seem to get out-of-hand.

I guess my solution works because I don't normally have two data-entry pages back-to-back. Also, the programming model I tend to use is to collect the data from the querystring and build the page and, after a data update, do a Response.Redirect with the right querystring which doesn't use viewstate. Huh. I guess my simple programming model lends itself well to storing the session in the viewstate.
# April 8, 2004 2:26 PM

rajbk said:

Did you consider using the built in compression with IIS 6.0 before you did this?

-raj
# April 8, 2004 4:52 PM

uber said:

> Did you consider using the built in compression with IIS 6.0 before you did this?

All my sites are hosted on Windows 2000. And they were all written, for the most part, before I ever even saw Windows 2003.
# April 8, 2004 4:59 PM

Jerry Pisk said:

IIS 5 supports compression as well, but hey, it works without it so why would we care ;)
# April 8, 2004 6:44 PM

TrackBack said:

# April 8, 2004 9:20 PM

TrackBack said:

# April 29, 2004 10:31 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)