Thursday, March 12, 2009

Server Side ViewState + Performance Improvement

I assume you all who are reading this article knows about ViewState. So now some times our webpage contains lot of controls, or datagrid/gridview or some dead controls. In this situation it can grow very large. And if we are using viewstate then It will dead effect on performance.

So the solution is to remove viewstate from the client side and keep it on Seaver. There are some drawbacks to store the it on Searver Side. What I am doing is that I have override the method that store and retrieves the ViewState, namely SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium. By overriding these two intrinsic methods, we can intercept the ViewState process and perform our magic. What we are doing is simply this: You have a bunch of baggage. Probably way too much. But you only really need it when you visit the server (such as on a postback). So, instead of making you carry it all with you (which can slow down the plane and make other passengers very unhappy), we are going to arrange for you to leave it in a special place at the server, and pick it up again when you get back there. Everything works the same; you just don't have to lug it all with you. Make sense?

This is far from a new idea; there are a number of implementations of this technique. The best one I found is by Robert Boedigheimer here. Robert's solution provides a new BasePage class which handles these operations, and a viewStateServerMgr class that handles the serialization and deserialization. His implementation is the only one I've seen that also accounts for the fact that with IE, users can hit the back button and we would need to "go back" to the previous viewstate for that page in the cache. Robert made the assumption that since ViewState is unique to each user, he would store and retrieve the ViewState for each page in Session state. However, there are at least three other "places" that we can stick our serialized ViewState object, and we can still account for unique users with a unique key such as the SessionID. If we do this, we can set Session to be readonly (assuming we don't need to write to it) and thus get an additional performance boost. Those options are Application, Cache, and a static global class instance holding, for example, a Hashtable.

A simplified code example of this model, with a different implementation of a unique user key, could be as follow:
protected override void SavePageStateToPersistenceMedium(object viewState)
string str = "VIEWSTATE_" + Request.UserHostAddress + "_" + DateTime.Now.Ticks.ToString();
Cache.Add(str, viewState, null, DateTime.Now.AddMinutes(Session.Timeout),TimeSpan.Zero, CacheItemPriority.Default, null);
RegisterHiddenField("__VIEWSTATE_KEY", str);
RegisterHiddenField("__VIEWSTATE", "");

protected override object LoadPageStateFromPersistenceMedium()
string str = Request.Form["__VIEWSTATE_KEY"];
if (!str.StartsWith("VIEWSTATE_")) {
throw new Exception("Invalid viewstate key:" + str);
return Cache[str];

So what I did was to wire up Robert's class with some choices that could be set in the web.config -- to make it automatically use Session, Application, Cache, or my global static class, depending on the web.config setting. I then set about to create two pages. The first page uses Robert's BasePage class to inherit from, and implements the server - side ViewState scheme. The second page inherits from the typical System.Web.UI.Page class, and Viewstate is stored "in the page" as usual. Each page is essentially the same, and each page creates 1000 small viewstate entries in the Page_Load handler on first load. Each page also has a bit of javascript written to it with "Defer" - which makes the script wait until the page and all other script is rendered, and then it causes the page to postback. In this manner, I could easily run a series of web stress tests with Homer (now called "Web Application Stress") and I wouldn't have to bother with making a GET and a POST in my tests. All I am really interested in is the throughput and average requests per second under load for each scenario.

As an informational note, many developers will ask "Why didn't you use ACT from Visual Studio.NET?". ACT is great for demos where you want to show people a nice real-time graph, but my personal opinion is that it is nowhere near as reliable or feature-rich as Homer. After a number of years of this testing thing, including several eye-opening weeks at the MS Testing Lab in Charlotte, I have come to trust Homer.

Before going any further, let's take a look at the test results, which may
surprise you. We ran this test with a client machine and a server machine over a
wireless network. The server is a P4 with 1 GB RAM running Windows Server 2003
and IIS in Worker Process Isolation (HTTP.SYS) mode. We ran a two minute test
with 20 simultaneous threads and no delay. This can be considered moderate
stress. None of the tests had any HTTP or socket errors. The regular ViewState
test without the server-side scheme is in the first column, then the four server
side schemes follow:
NUMBER OF HITS 3322 18483 18476 20170 16723
REQUESTS /SEC 27.64 153.8 153.74 167.84 140.32
TOTAL BYTES REC'D (KB) 68016.63 22923.25 22977.13 25074.51 20798


456.44% 456.22% 507.24% 407.67%

As can be seen above, the winner is - surprise - storing the ViewState in
Cache, at almost 168 requests per second. That is an approximate 500
percent improvement in throughput
over regular ViewState. All of the
server-side options outperformed regular ViewState, with static global Hashtable
storage being the worst performer. You can download the solution I used to
create these tests below, and tweak it if you like. I'd be interested in anyone
else's results in this area.

Conclusion: ASP.NET ViewState is a great invention that makes the developer's life easier. It also can create a lot of HTML baggage that slows down performance. By storing ViewState in either Session or Cache, you can have your ViewState and eat it, too.
Taking the time to develop a quality stress testing scenario to prove out (or disprove) one's hypotheses provides the scientific basis in fact to help developers make educated, sound decisions about their application architecture.

You can get an example of it from the following link:

Download the Solution that accompanies this article

Reference: Peter A. Bromberg :
Vijay Modi

No comments:

Post a Comment