Table of Contents
In this Article, I am going to explore the View State
. View state is one thing that always I liked to use. It makes our life easier. As we all know that Viewstate is one way of maintaining the states in the web applications.
As we know, a web page is created every time when a page is posted to the server.It means The values that user entered in the webpage is going to be vanished after the postback or submit. To get rid of this problem, ASP.NET framework provides a way to maintain these values by virtue of View State
. When we enable the viewstate of any control, the value is going to be maintained on every postbacks or server roundtrips.
But how these values get maintained? It doesn't come free.View State uses hidden variable
that resides on the page to store the controls values. It means that if a page have lots of controls with viewstate enabled the page size would become heavy, in several of kilobytes ie it will take longer time to download.And also on every postback all the data is posted to the server i e increasing the network traffic as well.
As in new era application, we use lots of heavy controls like gridview etc, on our page which makes page size exponentially heavy.It is always recommended to use View State judiciously and even some programmers try to avoid using this cause of performance overhead.
Here , I am going to discuss how we can reduce the performance overhead caused by View State.
As we know
Web is stateless
medium ie states are not maintained between the requests by default.A web page is created every time when a page is posted to the server. ASP.NET framework provides us several ways to maintain the state.These are
Fig: Various State Management technique in ASP.NET
Here we going to discuss the one of the ClientState management technique ViewState
.We can persist the data during the postback with the help of viewstate. Why we call viewstate as clientside? because the data is going to be stored on the page, if we move from one page to another the data would be lost.
So where the view state gets stored?
View state is stored on the page in form hidden field named as __viewstate
Here I will not discuss the basics of view state in detail, for detail have a look to one of the very good article on cp itself. That is
Beginner's Guide To View State [
^]
In our new era application, we generally have lots of rich and heavy controls on our page and also provide lots of functionality on the page with the help of few latest technology AJAX etc. To accomplish our task we use
View State
a lot but as we know it doesn't come free it has a performance overhead.
As we know viewstate is stored on the page in form of hidden variable. Its always advised to use viewstate as less as possible. we have also other ways to reduce the performance overhead. So we have several ways,here I am going to discuss the following ways
- By compressing decompressing the viewstate
- Another way to store the view state at some other server say on web server.
We will see all these with an example.
So here I will be taking an example and will show you, How we can achieve better performance with the help of above techniques
First lets see a normal scenario!!
Here, I have a webpage a gridview which is showing a lot of data (16 no of rows).I have enabled the viewstate so that I dont need to repopulate the whole grid on every postback. But what I am paying for that? Let's see the example.
First lets see the pagesize on postback with
enableviewstate true
which is true by Default.
Fig: Page with View State enabled
Here we can see the request size 4.9 k
. Also we can see the viewstate of the page by viewing the viewsource. Let's see it
Fig: __Viewstate hidden form field with Viewstate enabled
So you can see the __viewstate
variable on the screen and the amount of data it has. Now we can imagine, if we have several control like this what will your page size .
But the benefit, we dont need hit the database to fetch the data and bind it on every postback.
Now lets see what happens when we disable the viewstate ie setting the enableviewstate false
. Here I clicked on postback,
Fig:"Page with Viewstate disabled
and there is no data on page because I have loaded the data first time on page load on subsequent postbacks I didn,t bind it that's why when I click on PostBack the data got lost but the page size is here is just 773 B
. Also lets examine the viewsource of the page
Fig: __Viewstate hidden form field with Viewstate disabled
Here we also see __viewstate
variable but with very less data. But this much also.I'll answer it, Although we have disabled the viewstate, ASP.NET uses viewstate some data to maintain the page state but this is very less not going to cause performance overhead.
But what we get from the viewstate? we didn't need to repopulate the grid again. Just bind it on first pageload and on rest postbacks the data got populated from viewstate.
Note: Here I am using Firebug for the analysis purpose.
So Now we can imagine, the overhead of viewstate.Even you can check of your application (if you are using viewstate), and check the page size increased by the viewstate. So, here I am going to discuss one way to reduce the page size.
We can compress the viewstate to reduce the pagesize. By compressing the viewstate we can reduce the viewstate size by more than 30%. But here the question arises, where to compress and decompress the viewstate. For that we have to dig into the Page life cycle. As we know, viewstate is used by the ASP.NET to populate the controls. So we should compress the viewstate after all the changes are done in the viewstate and saving it after compression and we have to decompress the viewstate just before it is used by asp.net to load all the controls from viewstate . So lets jump to thepage life cycle and see our we can fit our requirement.
Fig: ASP.NET: Page Life Cycle
As we can see there are two methods,One SaveViewState
that is responsible for collecting the view state information for all of the controls in its control hierarchy in this method and persist it it in __viewstate hiddenform field
. The view state is serialized to the hidden form field in the SavePageStateToPersistenceMedium()
method during the save view state stage, and is deserialized by the Page class's LoadPageStateFromPersistenceMedium()
method in the load view state stage. So here in these methods we can compress and decompress the viewstate. Lets take a pictorial view.
Fig: ASP.NET: How viewstate gets maintained
So here, we need to override the methods SavePageStateToPersistenceMedium()
for compressing the viewstate and SavePageStateToPersistenceMedium()
for decompressing the viewstate. Here I am going to use GZip
for compression that is provided by the .NET itself.And this is available in th namespace System.IO.Compression
. So Lets jump to the code
I have made one Class CompressViewState
that is inherited from System.Web.UI.Page
. Here I have overridden the above said two methods. I also made two private methods one for compressing a byte stream and another for decompressing it. Lets have a look for the compressing one:
private byte[] Compress(byte[] b)
{
MemoryStream ms = new MemoryStream();
GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true);
zs.Write(b, 0, b.Length);
zs.Close();
return ms.ToArray();
}
As you can see the Compress
method is taking a byte array as a parameter and returning compress data in byte array form.In the method, I have used GZipStream
for compressing the data.Now lets have a look for the decompressing one
private byte[] Decompress(byte[] b)
{
MemoryStream ms = new MemoryStream();
GZipStream zs = new GZipStream(new MemoryStream(b), CompressionMode.Decompress, true);
byte[] buffer = new byte[4096];
int size;
while (true)
{
size = zs.Read(buffer, 0, buffer.Length);
if (size > 0)
ms.Write(buffer, 0, size);
else break;
}
zs.Close();
return ms.ToArray();
}
As you can see, this method is taking compressed data as a parameter and returning decompressed data.
Now lets have look to the overridden methods. First LoadPageStateFromPersistenceMedium
protected override object LoadPageStateFromPersistenceMedium()
{
System.Web.UI.PageStatePersister pageStatePersister1 = this.PageStatePersister;
pageStatePersister1.Load();
String vState = pageStatePersister1.ViewState.ToString();
byte[] pBytes = System.Convert.FromBase64String(vState);
pBytes = Decompress(pBytes);
LosFormatter mFormat = new LosFormatter();
Object ViewState = mFormat.Deserialize(System.Convert.ToBase64String(pBytes));
return new Pair(pageStatePersister1.ControlState, ViewState);
}
So you can see, in this method we have taken the viewstate in a string variable from PageStatePersister
Decompressed it(As it is compressed in saveviewstate stage
, we'll discuss after this) and deserialized it in an object and returned the new Pair
.
Now moving to the SavePageStateToPersistenceMedium
.
protected override void SavePageStateToPersistenceMedium(Object pViewState)
{
Pair pair1;
System.Web.UI.PageStatePersister pageStatePersister1 = this.PageStatePersister;
Object ViewState;
if (pViewState is Pair)
{
pair1 = ((Pair)pViewState);
pageStatePersister1.ControlState = pair1.First;
ViewState = pair1.Second;
}
else
{
ViewState = pViewState;
}
LosFormatter mFormat = new LosFormatter();
StringWriter mWriter = new StringWriter();
mFormat.Serialize(mWriter, ViewState);
String mViewStateStr = mWriter.ToString();
byte[] pBytes = System.Convert.FromBase64String(mViewStateStr);
pBytes = Compress(pBytes);
String vStateStr = System.Convert.ToBase64String(pBytes);
pageStatePersister1.ViewState = vStateStr;
pageStatePersister1.Save();
}
So Here, what we are doing, we are reading the viewstate information from pageStatePersister
and then serialize it and finally after compressing it, saved it in page persister.
So this is all about the compressing and decompressing the viewstate. I have put the class in the App_Code
folder so that it is available to entire application. And where ever we need to use it we should inherit it from CompressViewState
By this although we can not remove the viewstate size fully but we can reduce it size significantly and making our application's performance much better :).
Now Lets move to the Another methodology That is Saving the viewstate into the file system.
-This methodology should be used only you have enough data in viewstate else you will be more time in compressing and decompressing the viewstate between request without much gain.
Here I am going
to explan two approach.
Using Session
Using Hidden Field:
This way we can reduce the viewstate size to zero now you can assume still you are using the viewstate significantly there is no performance overhead on round trip to server.Still there is bit overhead to reading and saving the viewstate in file system. We'll discuss it later.
Now in this methodology also, we need to use the two methods
-LoadPageStateFromPersistenceMedium
-SavePageStateToPersistenceMedium
Here we are going saving to save the viewstate in file system. But how we'll save.What would be the name of the file? (As it has to be unique for every user? Do we need multiple files for the same user session.
There are a lot of questions.One answer, we dont need multiple for the same user at the same time because viewstate is confined to every page and when user moves to other page, earlier page's View State get ripped off. So at a time we just need to save the current page View State.
As sessionid is unique for every user, so why should we not use the sessionid in the file to make it unique and whenever we'll need to get the file we'll just pick by session id.
So lets jump to the code.
Here I have a file name PersistViewStateToFileSystem
that is inherited from System.web.UI.Page
and residing in the App_code
folder so that it is available through the whole application. Here we have a property which returns the full path of the viewstate file. Here I have used the sessionid as a name of the file and .vs as a extension. here we have a property that returns the path of the viewstate file, that is
public string ViewStateFilePath
{
get
{
if (Session["viewstateFilPath"] == null)
{
string folderName = Path.Combine(Request.PhysicalApplicationPath, "PersistedViewState");
string fileName = Session.SessionID + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace("/", "-") + ".vs";
string filepath = Path.Combine(folderName, fileName);
Session["viewstateFilPath"] = filepath;
}
return Session["viewstateFilPath"].ToString();
}
}
Again here we have implemented both the function
LoadPageStateFromPersistenceMedium
is loading the file from the View State file if it exists. So lets have a look for the code for LoadPageStateFromPersistenceMedium
protected override object LoadPageStateFromPersistenceMedium()
{
if (!File.Exists(ViewStateFilePath))
return null;
else
{
StreamReader sr = File.OpenText(ViewStateFilePath);
string viewStateString = sr.ReadToEnd();
sr.Close();
LosFormatter los = new LosFormatter();
return los.Deserialize(viewStateString);
}
}
and
SavePageStateToPersistenceMedium
is saving the file in file system instead of
pagepersister
. So moving to the code of
LoadPageStateFromPersistenceMedium
protected override void SavePageStateToPersistenceMedium(object state)
{
LosFormatter los = new LosFormatter();
StringWriter sw = new StringWriter();
los.Serialize(sw, state);
StreamWriter w = File.CreateText(ViewStateFilePath);
w.Write(sw.ToString());
w.Close();
sw.Close();
}
We need to inherit our page from the class PersistViewStateToFileSystem
to use it.
What is the best place to remove the
viewstate file from server? Our requirement is to remove the file at session end.So we can use
Application level
Session_End
(that is defined in
Global.asax
file) to remove the file from webserver.I have saved the
viewstate file path in session and accessing the file path from there. Lets see the code
of
Session_End
void Session_End(object sender, EventArgs e)
{
string filePath = Session["viewstateFilPath"] as string;
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
{
File.Delete(filePath);
}
}
You can get the full sample application in the attachment.
Now lets move to our example. Lets see the request size .
Fig: Viewstate saved on server
Ohh its just 2.5 K. Now we can see our page size reduced dramatically.Now lets see the view source of the page
Fig:__Viewstate hidden form field with Viewstate saved on server
Cool!!!. There is no data in the viewstate variable.
-This methodolgy only works, if cookies are not disabled on client machines.
-We need to remove the viewstate file after using it.Here
I have taken the approach to remove it at Session_End
which works only in
InProc
mode
-Only use if viewstate size is heavy else no need. Because it will take more to save the viewstate in file system and on reading.
-We can also compress the viewstate while saving viewstae on server.
- This option might not work on webfarm and webgarden scenario.
First I would say thanks all who shared their valuable feedback. I am adding section
because of them.
As Session Id approach has many limitation
as I mentioned in
Points to remember
section. So I have added the following New Approach
Using hidden field
We can use
GUID
instead of session Id to uniquely
identify the View State file.And to get the GUID we will be using a hiddenfield
to store the guid, so that we can get file name as n when we require.
So now here, we only need to change the View State File path property
and need to have a hidden field on every page.The hidden field on the page can be as
<asp:hiddenfield runat="server" id="hfVSFileName">
So actually, In my demo application,
I have added a key isSessionId in app.config
section of
web.config
, if it set true then we are using SessionId approach else HiddenField Approach
for making it configurable.
So now lets see the property Code
public string ViewStateFilePath
{
get
{
bool isSessionId = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["isSessionId"]);
string folderName = Path.Combine(Request.PhysicalApplicationPath, "PersistedViewState");
string fileName = string.Empty;
string filepath = string.Empty;
if (!isSessionId)
{
HiddenField hfVSFileName = null;
string VSFileName = "";
hfVSFileName = FindControl(this, "hfVSFileName") as HiddenField;
string hfVSFileNameVal = GetValue(hfVSFileName.UniqueID.ToString());
if (!string.IsNullOrEmpty(hfVSFileNameVal))
{
VSFileName = hfVSFileNameVal;
}
if (!Page.IsPostBack)
{
VSFileName = GenerateGUID();
hfVSFileName.Value = VSFileName;
RemoveFilesfromServer();
}
fileName = VSFileName + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace("/", "-") + ".vs";
filepath = Path.Combine(folderName, fileName);
return filepath;
}
else
{
if (Session["viewstateFilPath"] == null)
{
fileName = Session.SessionID + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace("/", "-") + ".vs";
filepath = Path.Combine(folderName, fileName);
Session["viewstateFilPath"] = filepath;
}
return Session["viewstateFilPath"].ToString();
}
}
}
Here in the code, you can see that based on the configuration, I am using Hiddenfield
or sessionId approach.In hiddenfield approach, I am creating a GUID for uniqueness
of the filename and also that is created only once on Pageload.
Also a change I have made regarding removing files from server. Here, I
am removing files from the server which is older than 3 days.Lets
see the code
private void RemoveFilesfromServer()
{
try
{
string folderName = Path.Combine(Request.PhysicalApplicationPath, "PersistedViewState");
DirectoryInfo _Directory = new DirectoryInfo(folderName);
FileInfo[] files = _Directory.GetFiles();
DateTime threshold = DateTime.Now.AddDays(-3);
foreach (FileInfo file in files)
{
if (file.CreationTime <= threshold)
file.Delete();
}
}
catch (Exception ex)
{
throw new ApplicationException("Removing Files from Server");
}
}
I am calling this method from once on every new page request. You can
call this
method based on your design
.
We can also make the number of days configurable.
At last, I just want to say, we generally use lots of viewstae
controls on our page
so at least we should use one of the discussed approach.
Feedback is the key for me. Feedback is the key for me.I would request to you
all to share your feedback and give me some suggestions, which which would
encourage and help in more writing.
First Posted: 15 Aug 2010
Added Section 'Removing ViewState file from server': 17 Aug 2010
Added Section 'Using Hiddden Field': 20 Aug 2010