Tuesday, April 6, 2010

State management in ASP.NET

A web application runs over HTTP, a stateless communication mode. That means, each request for a page is a new request for the server, no matter if the same page is being requested again. When a page makes a round trip to the server (for example when you fill up a form and submit it), you can naturally expect the data you filled in to be lost when the page loads back...unless you somehow manage to save the data somewhere and fill them back in the controls when the page loads back. This is called "maintaining the state".

In traditional environments like classic ASP, it was a painful responsibility of the developer to maintain state using Request collection. ASP.NET realized the pain and has come up with multiple ways to maintain state for an ASP.NET page.

State management can be done either client side or server side. In this article and the following ones, we will look at possible state management techniques and also talk about when best to use what.

In case of ASP.NET, the features available for preserving data across page or application are as follows:

  • View state
  • Control state
  • Hidden fields
  • Cookies
  • Query strings
  • Session state
  • Application state
  • Profile properties
  • Database
We will also evaluate each of these features in terms of implementation overhead, resource requirements, client side support (for client side methods), performance and security.


Managing state client side

Client side state management mostly involves storing state either in the page's HTML, the client browser's session or some physical location on the client machine.


View state

View state is the default mechanism provided by ASP.NET to maintain the value of controls in a page across a round trip i.e. postback. When a page is being rendered on the server, the values in all controls that have view state enabled (by default all controls have view state enabled) are serialized into XML and then encoded using base64 encoding. This value is then stored in a hidden field named "__VIEWSTATE". You can view this field using the "view source" option in the browser. A typical example would be:

<input type="hidden" name="__VIEWSTATE" value="dDwtNTI0ODU5MDE1Ozs+ZBCF2ryjMpeVgUrY2eTj79HNl4Q=" />

So, view state is typically an encoded string containing IDs and values of controls in a page so that when the page is posted back, the server automatically puts the values back into the controls before sending the page back to client (rather than developers required to do it themselves in traditional environment).

Besides storing control's values, the view state collection (which is nothing but a dictionary object) can be used to store other values as well, as shown below:

ViewState("MyPostBackCount") = 2;

A view state can store data of multiple data types, viz. strings, integers, boolean values, arrays, array lists and hash tables.

However, in case of large amount of data being loaded in controls e.g. in case of grids, view state can result into a huge string and can have negative impact on performance by slowing down page load on the browser. Huge view state also means huge amount of data flowing between the client and the server. ASP.NET provides an option to disable view state at the page level and also at control level. When it is a choice between comfort and performance, disabling view state can be an option; however the developer will then have to implement an alternative for maintaining the state. Also, in case of data bound grids, disabling view state can create problems in default paging and sorting behaviour.

Implementation - View state is maintained by default and hence needs no specific programming to be done.
Resource requirements - Since the view state is maintained in a hidden field, it does not consume server resources. There is an overhead involved in encryption and decryption but it is so insignificant that you don't need to bother about it.
Client side support - Hidden fields are allowed by most browsers and do not need specific permission from users. However, for devices that have constraints loading huge data (e.g. mobile devices) or if there are firewall restrictions on the limit of data allowed in hidden fields, large amount of data in view state can create problems.
Performance - As discussed, large amount of view state data can be a serious bottleneck. If view state can result into performance issues, it is wise to disable view state and implement an alternative.
Security - View state is an encrypted string. It provided optimum security, but still there is a risk of view state data being tampered because it is after all hidden in the form itself and can be viewed on browser end.


Control state

Like view state, control state is also an encrypted string generated at server and stored in a hidden field to persist data across postbacks. But control state only contains critical data about controls for the controls to function properly and unlike view state, control state cannot be disabled. If you were wondering, how could controls function properly if view state was disabled...control state is your answer, but this is very simply put. The truth gets worse if we dive deep...glad, we won't ;-).

Controls state is a separate object than view state and is initialized by the PageStatePersister class while view state is an instance of the StateBag class.

Implementation - Control state is custom state persistence mechanism and hence requires some programming to be done. We will look at control state with example in a later article.
Resource requirements - Like view state, the control state is also maintained in a hidden field and does not consume server resources.
Client side support - It's just a hidden field!
Performance - Unlike view state, data in custom state never gets large enough to pose a worry.
Security - No worries...custom state is an encrypted string and it does not store user provided data.


Hidden fields

A hidden field is a control that renders a hidden input control that can store some value and can be used for persisting data across postback. Unlike view state and control state that is handled by ASP.NET, hidden strings are to be added by the developer wherever required. Hidden fields are visible on client and not encrypted either. Hence they should never be used for storing sensitive data.

An .aspx page can contain,

<asp:HiddenField ID="MyPostBackCount" runat="server" />

and this can be accessed in codebehind as:

HiddenField1.Value = "2";

Implementation - Hidden fields are easy to implement as shown in example above.
Resource requirements - The hidden field control generates an equivalent input control that is hidden and not displayed on browser. No server resource required.
Client side support - This is also just a hidden field!
Performance - Issues related to amount of data stored in the hidden field can pose similar problems as with the view state. Hidden fields are never advised for large amount of data.
Security - As mentioned, hidden fields are visible on client using the "view source" option in browser and the stored values are not encrypted either. They can be easily tampered with and are strictly not suggested for storing sensitive data.


Cookies

Cookies are well known in state management world. They are small bunch of data stored on client side either in browser memory or text files. Cookies are not ASP.NET specific but since they are also state management measures, let us evaluate cookies as an option. Cookies can be temporary or permanent (persistent). Also, cookies can have multiple values in a single cookie. We will discuss cookies in a separate discussion.

In ASP.NET, cookies are accessed through the Response object.

Response.Cookies["UserName"].Value = "guest";
Response.Cookies["UserName"].Expires = DateTime.Now.AddDays(1);

Implementation - Cookies are simple collections and easy to use with less programming required.
Resource requirements - Cookies are client side storage option, hence they either consume space in the client browser's memory or physical disk. They do not pose any demand on server resources.
Client side support - Cookies can be disabled by client and hence has restricted applicability. Also, cookies have limited allowed size on client, often up to 4 KB.
Performance - Cookies have size limits and hence do not contribute to performance bottlenecks
Security - Cookies can be easily tampered with and is a known threat area. It is strongly advised to use encryption and decryption with cookies and not to store sensitive data either.


Query strings

Query string is another option and a traditional one for persisting data. It is data appended to an URL in a pre-defined form that can be read as parameters. ASP.NET exposes the parameter collection through Request object.

Implementation - Query strings are well known and simple to implement.
Resource requirements - Since parameters are appended to URL, it has nothing to do with serer or client resources. However, the larger the data, the more the packets transferred.
Client side support - Query strings are well supported but fall within the size limit of about 2083 characters for URLs.
Performance - Query strings do not contribute to performance bottlenecks for obvious reasons.
Security - Query strings are the easiest to play around with and tamper. It is visible with the URL and should only be used for limited non-sensitive data.


Maintaining state server side

Maintaining state server side often means storing data in server memory or some data store.


Session state

Session state is a server side data storage mechanism that stores data in key-value pair format in server memory and is maintained by server. This state is maintained as long as the browser session is active, i.e. data persists in memory across multiple page requests as long as the session is active. Each user connected to the server has its own session id and its own session state. Session state should be used only for data that need to persist across multiple page requests or throughout the session.

Session["UserName"] = "guest";

Implementation - Session state is easy to use as shown in example above.
Resource requirements - Session state resides in memory on server. If large amount of data or objects are stored in session state, it will end up consuming a lot of memory on server and badly degrade server performance.
Performance - Large amount of data in server state can be a performance issue since the server will have to resort to virtual memory paging in absence of the memory consumed by server state.
Security - Session state is maintained in memory on server. Security is not an issue.


Application state

Application state is a global storage mechanism that stores data in key-value pair format and is maintained by server, like session state. However, this state is maintained at application level, i.e. data persists across multiple page requests and even multiple sessions. It should be obvious that application state is a very precious store and has the longest life span among the methods we know. Use it wisely!

Application["ClickCounter"] = clickCounter + 1;

Implementation - Application state is easy to use as shown in example above.
Resource requirements - Like session state, application state consumes server memory. Worse, it persists across multiple sessions as well. If large amount of data is stored in application state, it will end up consuming a lot of memory on server and hence degrade server performance.
Performance - Large amount of data in application state can choke up server memory and degrade server performance.
Security - Application state is maintained in memory on server. Security is not an issue.


Profile properties

Profile properties use external storage medium (data store) to persist data rather than in memory. This feature uses ASP.NET profile to maintain user specific data that requires to be stored and used across multiple sessions of an individual user. We will talk about profile properties in a separate article in detail.

Implementation - Profile properties are easy to use, given that the developer can configure the profile provider.
Resource requirements - Since data is stored in data store rather than memory, it does not consume any resource in server memory at least. And since the storage is done in an external medium, there is no limit on data storage.
Performance - Since data is stored in data store than memory, storage and retrieval of data is relatively slower than other server side methods. But this should not be a concern.
Security - Well, it is not as secure as other server side methods, but it does not pose huge threat either.


Database

Often, database is also used along with cookies or session states to store data in order to persist it. In simple terms, if you think that you need to store some data in your database related to user's authentication or preferences or whatever, you can store it in database as well.

Implementation - Maintaining state in database is as simple as performing normal database operations. Of course, it is not automatic and requires programming.
Resource requirements - Database gives you an unlimited storage and there is no server memory in concern here.
Performance - Obvious as it is, database operations would consume some time and hence this method is not as quick as the rest. I would say, performance here is specific to implementation.
Security - Security relies on what measures are taken to secure database. Adequate authentication and authorization can introduce required security factor.


We are now familiar with the possible methods of maintaining state in ASP.NET. In the next article, we will talk about which method is best in what circumstances.

0 comments: