Tuesday, August 08, 2006

 

View State: The Silent Perf Killer



In some ways, view state is the greatest thing since sliced bread. After all, it’s view state that allows pages and controls to persist state across postbacks. That’s why you don’t have to write code to keep the text in a TextBox from disappearing when a button is clicked as you did in classic ASP, or requery a database and rebind a DataGrid following a postback.

But view state has a dark side, too: when it grows too large, it’s a silent performance killer. Some controls, such as TextBoxes, are judicious with view state. Others, notably DataGrids and GridViews, emit view state in proportion to the amount of information displayed. I cringe when I see a GridView displaying 200 or 300 rows of data. Even though ASP.NET 2.0 view state is roughly half the size of ASP.NET 1.x view state, one lousy GridView can easily cut the effective bandwidth of a connection between a browser and a Web server by 50 percent or more.

You can turn off view state for individual controls by setting EnableViewState to false, but some controls, particularly DataGrids, lose some of their functionality when denied the freedom to use view state. A much better solution to taming view state is keeping it on the server. In ASP.NET 1.x, you can override a page’s LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium methods and handle view state however you like. The overrides shown in the code below prevent view state from being persisted in a hidden field and persist it in session state instead.




protected override object LoadPageStateFromPersistenceMedium ()
{
string key = Request.RawUrl + "_VIEWSTATE";
object state = Session[key];
return (state == null) ?
base.LoadPageStateFromPersistenceMedium () : state;
}

protected override void
SavePageStateToPersistenceMedium (object viewState)
{
string key = Request.RawUrl + "_VIEWSTATE";
Session[key] = viewState;
}

Storing view state in session state is particularly effective when paired with the default session state process model—that is, when session state is stored in memory in the ASP.NET worker process. If session state is stored in a database instead, then only testing will show whether keeping view state in session state improves or degrades performance.

The same technique works in ASP.NET 2.0, but ASP.NET 2.0 offers a simpler means for persisting view state in session state. You begin by defining a custom page adapter whose GetStatePersister method returns an instance of the .NET Framework SessionPageStatePersister class:



public class SessionPageStateAdapter :
System.Web.UI.Adapters.PageAdapter
{
public override PageStatePersister GetStatePersister ()
{
return new SessionPageStatePersister(this.Page);
}
}


Then you register the custom page adapter as the default page adapter by dropping an App.browsers file like the following into the application’s App_Browsers folder:



<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.Page"
adapterType="SessionPageStateAdapter" />
</controlAdapters>
</browser>
</browsers>


(You can name the file anything you like as long as it has a .browsers extension.) Thereafter, ASP.NET will load the page adapter and use the returned SessionPageStatePersister to persist all page state, including view state.

One downside to using a custom page adapter is that it acts globally for every page in the application. If you’d prefer to persist view state in session state for some pages but not for others, use the technique shown in the first snippet of this article. Additionally, you can run into issues with this technique if a user creates multiple browser windows within the same session.


Comments:
Thank you very much for this post !

Anyway, I have noticed strange behaviour with GridView when using
return new SessionPageStatePersister(this.Page);
Sounds like DataKeys GridView property was not persisted.

I have noticed that PageStatePersister accessor is queried several times during a page cycle when I debug a form that uses a GridView with custom paging, sorting and so on.

So I tried :

SessionPageStatePersister _Persister;

...
get
{
if (_Persister == null)
_Persister = new SessionPageStatePersister(this.Page);

return _Persister;
}


And all my GridViews are now working fine.
 
Lame am I !!!

What I did is overriding the GetStatePersister of the Page object...

Using PageAdapters as you did is a far cleaner solution on my mind, and works perfectly the way you did.

Never mind :-)
 
Thanks, this was just what I was looking for.

One detail, the file should have the extension .browser and not .browsers as your article says.

/MÖ
 
Thanks Laurent for your comment on the GridView ViewStage issues. I was experiencing them myself, and your suggestion made my code work fine again.

Furthermore, I use a Page derived class in a class library. Then I reference this in my ASPX file or code-behind file. This approach is useful to provide some page-wide changes for your website. Furthermore, you can optionally derive a page from this custom class (or maybe give it a property to switch page persistence?). You could separate logical block of code into partial classes, so you easily can manage that base page class (that might have a lot of logic, like DB access).
 
I was having the same issue as laurent and your fix worked great. Many thanks to both the blogger and laurent. =]
 
ups sorry delete plz [url=http://duhum.com].[/url]
 
You have tested it and writing form your personal experience or you find some information online?
 
Post a Comment





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]