Nine Options for Managing Persistent User State in Your ASP.NET Application

SUMMARY
ASP.NET provides many different ways to persist data between user requests. You can use the Application object, cookies, hidden fields, the Session or Cache objects, and lots of other methods. Deciding when to use each of these can sometimes be difficult. This article will introduce the aforementioned techniques and present some guidelines on when to use them. Although many of these techniques existed in classic ASP, best practices for when to use them have changed with the introduction of the .NET Framework. To persist data in ASP.NET, you'll have to adjust what you learned previously about handling state in ASP.


Since the dawn of the Web, managing state in the stateless world of HTTP has been a problem for Web developers. More recently, various techniques for storing and retrieving data have emerged. In this article I will describe how ASP.NET developers can maintain or pass state across page requests.
In ASP.NET, there are several different ways to persist data between user requests—so many, in fact, that the novice developer is often confused about which object to use in a particular situation. In order to answer this question, there are three criteria that should be considered:
  • Who needs the data?
  • How long does the data need to be persisted?
  • How large is the set of data?
By answering these questions, you can determine which object provides the best solution for persisting data between requests in an ASP.NET application. Figure 1 lists the different state management objects and describes when they should be used. In ASP.NET, four new objects have been added: Cache, Context, ViewState, and the Web.Config file. Classic ASP objects that are also available in ASP.NET include Application, Cookie, Form Post with a hidden form field, QueryString, and Session. Note that the proper use of these five data containers has changed, so experienced ASP programmers may have some "unlearning" to do when considering these familiar objects.



Persistence MethodWho Needs the Data?For How Long?How Much Data?
ApplicationAll usersUntil the next application restartCan be almost any size—it will only be stored once
CookieOne userAs short as desired, or for months or even years if the user doesn't delete their cookiesMinimal, simple data
Form PostOne userFor the next request (can be reused across many requests)Virtually any size—the data is sent back and forth with every page
QueryStringOne user or one group of usersFor the next request (can be reused across many requests)Minimal, simple data
SessionOne userAs long as the user is active, plus a timeout period (typically 20 minutes)Can be almost any size, but should be minimized since every user has their own separate session store
CacheAll users or a subset of usersAs long or as short as neededCan be used for large or small, simple or complex data
ContextOne userThis request onlyCan hold large objects, but typically does not since it is often used for every request
ViewStateOne userOne Web formMinimal; as with Form Post, this data is sent back and forth with every page
Config fileAll usersUntil the configuration file is updatedCan hold a lot of data; usually organized as many small strings or XML structures

Application
Let's set the object use criteria by answering the state questions I asked earlier. Who needs this data? All users need access to it. How long does this data need to be persisted? It has to live forever, or for the life of the application. How large is this data? It can be almost any size—only one copy of the data will exist at any given time.
In classic ASP, the Application object provided a great place to store frequently used pieces of data that changed infrequently, such as the contents of menus or other reference data. While the Application object is still available as a data container in ASP.NET, other objects are generally better suited for the kinds of data that would have been stored in the Application collection of a classic ASP application.
In classic ASP, the Application object was an ideal choice if the data that was to be stored did not vary at all (or very rarely) for the life of the application (such as read-only or read-mostly data). Connection strings were one of the more common pieces of data stored in Application variables, but in ASP.NET such configuration data is best stored in the Web.config file. One thing to consider if you are using the Application object is that any writes to it should be done either in its Application_OnStart event (in global.asax) or within an Application.Lock section. While using Application.Lock is necessary to ensure that writes are performed properly, it also serializes requests for the Application object, which can be a serious performance bottleneck for the application. Figure 2 demonstrates how to use the Application object; it consists of a Web form and its code-behind file. An example of its output is shown in Figure 3.



Application.aspx
<form id="Application" method="post" runat="server">
    <asp:validationsummary id="valSummary" Runat="server">
        </asp:validationsummary>
    <table>
        <tr>
            <td colSpan="3">Set Application Variable:</td>
        </tr>
        <tr>
            <td>Name</td>
            <td><asp:textbox id="txtName" Runat="server"></asp:textbox>
                </td>
            <td><asp:requiredfieldvalidator id="nameRequired" 
                 runat="server" Display="Dynamic" ErrorMessage="Name is 
                 required." ControlToValidate="txtName">*
                 </asp:requiredfieldvalidator></td>
        </tr>
        <tr>
            <td>Value</td>
            <td><asp:textbox id="txtValue" Runat="server">
                </asp:textbox></td>
            <td><asp:requiredfieldvalidator id="valueRequired" 
                 Runat="server" Display="Dynamic" ErrorMessage="Value is 
                 required." ControlToValidate="txtValue">*
                 </asp:requiredfieldvalidator></td>
        </tr>
        <tr>
            <td colSpan="3"><asp:button id="btnSubmit" Runat="server" 
                             Text="Update Value"></asp:button></td>
        </tr>
    </table>
    <asp:Label ID="lblResult" Runat="server" />
</form>
Application.aspx.cs
private void btnSubmit_Click(object sender, System.EventArgs e)
{
    if(IsValid)
    {
        Application.Lock();
        Application[txtName.Text] = txtValue.Text;
        Application.UnLock();

        lblResult.Text = "The value of <b>" + txtName.Text + 
            "</b> in the Application object is <b>" + 
            Application[txtName.Text].ToString() + "</b>";
    }
}


Figure 3 Contents of Application Object 
Note that in Figure 3 the contents of the Application object are displayed in the trace output. Tracing is a really great debugging tool, but you can expect that at some point, a page with tracing turned on will accidentally make it into your production environment. When that happens, you really won't want anything sensitive to be shown. This is one of the primary reasons why the Application object is no longer the recommended place to store sensitive information like connection strings.

Cookies
Cookies are handy when a particular user needs a specific piece of data, and it needs to be persisted for a variable period of time. It can be as brief as the life of the browser window, or as long as months or even years. As far as size goes, cookies are very small. Cookies can be as small as only a few bytes of data, and since they are passed with every browser request, their contents should be kept as small as possible.
[ Editor's Update - 1/11/2005: The best way to secure sensitive state that should not be viewed or modified by a hostile user is to store that state on the server. If sensitive data must be sent to the client, it should be encrypted beforehand, regardless of the storage mechanism employed.]
A particular named cookie can store a single value or a collection of name/value pairs. Figure 4 shows an example of both single- and multi-value cookies, as output by the built-in trace features of ASP.NET. These values can be manipulated within an ASP.NET page by using the Request.Cookies and Response.Cookies collections, as Figure 5 demonstrates.



Cookies.aspx.cs
// Setting a cookie's value and/or subvalue using the HttpCookie class
HttpCookie cookie;
if(Request.Cookies[txtName.Text] == null)
    cookie = new HttpCookie(txtName.Text, txtValue.Text);
else
    cookie = Request.Cookies[txtName.Text];
if(txtSubValueName.Text.Length > 0)
    cookie.Values.Add(txtSubValueName.Text, txtSubValueValue.Text);
cookie.Expires = System.DateTime.Now.AddDays(1); // tomorrow
Response.AppendCookie(cookie);

// Retrieving a cookie's value(s)
if(!Request.Cookies[txtName.Text].HasKeys)
    lblResult.Text = "The value of the <b>" + txtName.Text + "</b> 
        cookie is <b>" + Request.Cookies[txtName.Text].Value.ToString() + 
        "</b>";
else
{
    lblResult.Text = "The value of the <b>" + txtName.Text + "</b> 
        cookie is <b>" + Request.Cookies[txtName.Text].Value.ToString() + 
        "</b>, with subvalues:<br>";
    foreach(string key in Request.Cookies[txtName.Text].Values.Keys)
    {
        lblResult.Text += "[" + key + " = " + 
            Request.Cookies[txtName.Text].Values[key].ToString() + "]<br>";
    }
}
Delete a Cookie
// Set the value of the cookie to null and
// set its expiration to some time in the past
Response.Cookies[txtName.Text].Value = null;
Response.Cookies[txtName.Text].Expires = 
    System.DateTime.Now.AddMonths(-1); // last month


Form Post / Hidden Form Field
Form data is needed by a particular user, and it must be persisted for any period from a single request to the life of the application. The data can be virtually any size; it's sent back and forth over the network with each form post.
In classic ASP, this was a common way to retain state within an application, especially in a multi-page form. However, in ASP.NET, this technique is rarely appropriate since Web controls and ViewState handle this automatically as long as you use the postback model (that is, pages that post back to themselves). ViewState is an ASP.NET implementation of this technique, which I will describe later in this article. Access to form values sent through a POST is done using the HttpRequest object's Form collection. In Figure 6, a user ID is set by one ASP.NET page, after which it is persisted in a hidden form field. Subsequent requests to either page retain the value as long as the pages use Submit buttons to link to each other.



Form1.aspx
<h1>Form 1</h1>
<form id="Application" method="post" runat="server">
    <p>Your username: 
<asp:Label ID="lblUsername" Runat="server" />
</p>
    <asp:Panel Runat="server" ID="pnlSetValue">
    <asp:validationsummary id="valSummary" Runat="server">
        </asp:validationsummary>
    <TABLE>
    <TR>
        <TD colSpan="3">Set Hidden Form Username Variable:</TD></TR>
    <TR>
        <TD>Username</TD>
        <TD>
    <asp:textbox id="txtName" Runat="server"></asp:textbox></TD>
        <TD>
    <asp:requiredfieldvalidator id="nameRequired" runat="server" 
        ControlToValidate="txtName" ErrorMessage="Name is required." 
        Display="Dynamic">*</asp:requiredfieldvalidator></TD></TR>
    <TR>
        <TD colSpan="3">
    <asp:button id="btnSubmit" Runat="server" Text="Set Value">
        </asp:button></TD></TR></TABLE>
    </asp:Panel>
    <asp:Label ID="lblResult" Runat="server" />
</form>
<form action="form2.aspx" method="post" name="form2" id="form2">
    <input type="hidden" name="username" value="<%# username %>" >
    <input type="submit" value="Go to Form2.aspx"
</form>
Form1.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
    if(!IsPostBack) // new request or request from form2.aspx
    {
        // check Forms collection
        if(Request.Form["username"] == null)
            pnlSetValue.Visible = true;
        else
        {
            // need to set the username value
            pnlSetValue.Visible = false;
            username = Request.Form["username"].ToString();
            lblUsername.Text = username;
            // Databind to set the hidden form field's value
            this.DataBind();
        }
    }
}

private void btnSubmit_Click(object sender, System.EventArgs e)
{
    if(IsValid)
    {
        // Hide the form to set the value.
        pnlSetValue.Visible = false;
        username = txtName.Text;
        lblResult.Text = "Username set to " + txtName.Text + ".";
        lblUsername.Text = username;
        this.DataBind();
    }
}
Form2.aspx
<h1>Form 2</h1>
<form id="Application" method="post" runat="server">
    <p>Your username: <asp:Label ID="lblUsername" Runat="server" /></p>
</form>
<form action="form1.aspx" method="post" id="form2" name="form2">
    <input type="hidden" name="username" value="<%# username %>" >
    <input type="submit" value="Go to Form1.aspx"
</form>
Form2.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
    if(Request.Form["username"] != null)
    {
        username = Request.Form["username"].ToString();
        lblUsername.Text = username;
        this.DataBind();
    }
}

In ASP.NET, only one server-side form can exist on a page, and that form must submit back to itself (client-side forms can still be used, without limitations). One of the major reasons that hidden form fields are no longer used to pass data around applications built on the Microsoft® .NET Framework is that all .NET Framework controls are capable of maintaining their own state automatically using ViewState. ViewState simply encapsulates the work involved in setting and retrieving values using hidden form fields into a simple-to-use collection object.

QueryString
The data stored in the QueryString object is used by the individual user. Its lifetime can be as brief as a single request, or as long as the user continues to use the application (if architected appropriately). This data is typically less than 1KB. Data in a QueryString is passed in the URL and is visible to the user, so as you might guess, sensitive data or data that can be used to control the application should be encrypted when using this technique.
That said, the QueryString is a great way to send information between Web forms in ASP.NET. For example, if you have a DataGrid with a list of products, and a hyperlink in the grid that goes to a product detail page, it would be an ideal use of the QueryString to include the product ID in the QueryString of the link to the product details page (for example, productdetails.aspx?id=4). Another advantage of using QueryStrings is that the state of the page is contained in the URL. This means that a user can put a page in their Favorites folder in its generated form when it's created with a QueryString. When they return to it as a favorite, it will be the same as when they actually made it a favorite. Obviously, this only works if the page doesn't rely on any state outside the QueryString and nothing else changes.
Along with sensitive data, any variable that you don't want the user to be able to manipulate should be avoided here (unless encryption is used to remove human-readability). Also, keep in mind that characters that are not valid in a URL must be encoded using Server.UrlEncode, as Figure 7 shows. When dealing with a single ASP.NET page, ViewState is a better choice than QueryString for maintaining state. For long-term data storage, Cookie, Session, or Cache are more appropriate data containers than QueryStrings.



Querystring.aspx
<form id="Querystring" method="post" runat="server">
    <asp:validationsummary id="valSummary" Runat="server">
        </asp:validationsummary>
    <table>
        <tr>
            <td colSpan="3">Set Querystring Variable:</td>
        </tr>
        <tr>
            <td>Name</td>
            <td><asp:textbox id="txtName" Runat="server"></asp:textbox>
                </td>
            <td><asp:requiredfieldvalidator id="nameRequired" 
                 runat="server" Display="Dynamic" ErrorMessage="Name is 
                 required." ControlToValidate="txtName">*
                 </asp:requiredfieldvalidator></td>
        </tr>
        <tr>
            <td>Value</td>
            <td><asp:textbox id="txtValue" Runat="server">
                    </asp:textbox></td>
            <td><asp:requiredfieldvalidator id="valueRequired" 
                 Runat="server" Display="Dynamic" ErrorMessage="Value is 
                 required." ControlToValidate="txtValue">*
                 </asp:requiredfieldvalidator></td>
        </tr>
        <tr>
            <td colSpan="3"><asp:button id="btnSubmit" Runat="server" 
                             Text="Update Value"></asp:button></td>
        </tr>
    </table>
    <asp:Label ID="lblResult" Runat="server" />
    <a href="http://querystring.aspx?x=1">Set querystring x equal to 1</a>
</form>
Querystring.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
    // Retrieving a cookie's value(s)
    if(Request.QueryString.HasKeys())
    {
        lblResult.Text = "The values of the <b>" + txtName.Text + 
                         "</b> querystring parameter are:<br>";
        foreach(string key in Request.QueryString.Keys)
        {
            lblResult.Text += "[" + key + " = " + 
                Request.QueryString[key].ToString() + "]<br>";
        }
    }
}

private void btnSubmit_Click(object sender, System.EventArgs e)
{
    if(IsValid)
    {
        string url = "querystring.aspx?";
        foreach(string key in Request.QueryString.Keys)
        {
            url += key + "=" + Request.QueryString[key].ToString() + "&";
        }
        Response.Redirect(url + txtName.Text + "=" + 
            Server.UrlEncode(txtValue.Text));
    }
}

Session
Session data is specific to a particular user. It lives for as long as the user continues to makes requests plus some period of time afterward (typically 20 minutes). The Session object can hold large or small amounts of data, but total storage should be kept minimal if the application is intended to scale to hundreds of users or more.
Unfortunately, the Session object earned itself a very bad name in classic ASP because it tied an application to a particular machine, precluding the use of clustering and Web farms for scalability. In ASP.NET, this is less of an issue, since it is a simple matter to change the location where the session is stored. By default (and for best performance), session data is still stored in the memory of the local Web server, but ASP.NET also supports an external state server or database for managing Session data.
Using the Session object is easy and its syntax is identical to classic ASP. However, the Session object is one of the less efficient ways of storing user data, since it is held in memory for some time even after the user has stopped using the application. This can have serious effects on scalability for a very busy site. Other options allow more control over the release of memory, such as the Cache object, which may be better suited for some large data values. Also, ASP.NET sessions rely on cookies by default so if the user disables or doesn't support cookies, sessions won't work. Support for cookie-free sessions can be configured, however. For small amounts of data, the Session object can be a perfectly valid place to store user-specific data that needs to persist only for the duration of the user's current session. The following example demonstrates how to set and retrieve values from the Session object:
private void btnSubmit_Click(object sender, System.EventArgs e)
{
    if(IsValid)
    {
        // Set the Session value.
        Session[txtName.Text] = txtValue.Text;

        // Read and display the value we just set
        lblResult.Text = "The value of <b>" + txtName.Text + 
            "</b> in the Session object is <b>" + 
            Session[txtName.Text].ToString() + "</b>";
    }
}
The Web form is almost identical to the one used for the Application object, and the contents of the Session collection are also visible when page tracing is enabled.
You should be aware that even when not in use, sessions carry some overhead for an application. You can squeeze a little bit more performance out of your pages if you turn off sessions on pages that do not use it. Also, setting session state to read-only can also optimize pages that read but do not write data to sessions. Configure sessions in this fashion by adding an attribute to the @Page directive in one of these two ways::
<%@ Page EnableSessionState="false" %>
<%@ Page EnableSessionState="readonly" %>
ASP.NET sessions can be configured in the Web.config or Machine.config with the sessionState element. This element supports the attributes listed in Figure 8.



AttributeOptionsDescription
modeOffDisables sessions.
InprocSame as classic ASP. Stored in the Web server's local memory. This option provides the best performance, but it is not clusterable. This is the default option.
StateServerSession data is stored in memory on another server.
SqlServerSession data is stored in a SQL Server database.
cookielessTrueEnables cookieless sessions. Session ID is automatically passed in the QueryString instead of in a cookie for all relative URLs in the application.
FalseThis is the default setting. Sessions use cookies.
timeoutSession timeout in minutes. The default is 20.
sqlConnectionStringConnection string used for SqlServer mode sessions.
stateConnectionStringConnection string used for StateServer mode sessions.

Here is an example of the settings in the Web.config:
<sessionState timeout="10" cookieless="false" mode="Inproc" />

New State Containers in ASP.NET
As mentioned earlier, ASP.NET adds several new ways to store data during and between user requests. This gives you much finer control over how state information is persisted. These new techniques narrow the scope down to as small as a single request (the Context object), or widen the scope to as large as the whole Web server and all applications on that server (the Machine.config file). In many cases, you will have several options available to you when you need to store a particular piece of data—use the questions and answers provided with each method description to determine if it is appropriate for your situation.

Cache
Cache data is specific to the single user, a subset of users, or even all users. This data persists for multiple requests. It can persist for a long time, but not across application restarts. Also, data can expire based on time or other dependencies. It can hold both large and small amounts of data effectively.
The Cache is one of the coolest objects in all of ASP.NET. It offers incredible flexibility, versatility, and performance, and is therefore often a better choice than Application or Session for persisting data within an ASP.NET application. A complete description of the ways in which the Cache object can be used (both declaratively and programmatically) is beyond the scope of this article, but suffice to say, it's a versatile object. Like the other collection objects, it is simply a name-value collection, but by using a key value that is specific to a user, you can make the cached values user-specific. Similarly, you can cache multiple sets of data for different related data, like several sets of car data with keys like "fordcars", "chevycars", and "gmcars". Data in the Cache can be given an expiration period that is absolute, sliding, or based on changes to a file. They also implement a callback function that is invoked whenever the cached value is ejected from the cache, which is useful because you can then check to see if there is a more recent version of the data available, and if not (or if the data source is unavailable), re-cache the value that was just expired.
Adding and accessing data in the cache is done using a syntax similar to what I have already covered. However, in addition to the standard indexer method of accessing this collection's contents, Cache also supports a number of methods to allow more control over the data that is cached. The method you will most often use is Insert, which supports several overloads that allow you to specify dependencies, timeouts, priority, and callbacks. Some simple examples are shown in the following code:
// Add item to cache
Cache["myKey"] = myValue;

// Read item from cache
Response.Write(Cache["myKey"]);

// Set a CacheDuration of 10 seconds and add item to cache
Cache.Insert("myKey",myValue, null, System.DateTime.Now.AddSeconds(10),
System.Web.Caching.Cache.NoSlidingExpiration);
One of the more powerful features of the Cache object is its ability to execute a callback when an item in the cache expires. This uses delegates or function pointers, a fairly advanced topic that I won't be covering in this article. Fortunately, once you have a bit of sample code showing how this technique works, you can take advantage of it in your applications by simply cutting and pasting, without knowing all the intricacies of how delegates work. There are many reasons why you might use this functionality, the most common being to refill the cache with current data whenever it expires, or restoring the old cache data if the data source to repopulate the cache is unavailable.
In my example, I am simply going to cache the current time, and whenever the cache expires, I am going to add an asterisk character (*) to the end of the string in the cache. Over time, you will be able to determine how many times the cache has expired by counting the asterisks. Figure 9 demonstrates the important concept of callbacks and provides a good template for building more functional callback routines into your use of the cache.


private void Page_Load(object sender, System.EventArgs e)
{
    string cacheKey = "myKey";
    string data = "";
    // Check to see if the data is in the cache already
    if(Cache[cacheKey]==null)
    {
        // Get the data since it isn't in the cache
        data = System.DateTime.Now.ToString();
    
        //create an instance of the callback delegate
        CacheItemRemovedCallback callBack =
            new CacheItemRemovedCallback(onRemove);

        Label1.Text = "Generated: " + data;
        
        Cache.Insert(cacheKey,data,null, 
            System.DateTime.Now.AddSeconds(5),
            System.Web.Caching.Cache.NoSlidingExpiration, 
            System.Web.Caching.CacheItemPriority.Default,
            callBack);
        }
    else
    {
        Label1.Text = "Cached: " + Cache[cacheKey].ToString();
    }
}

private void onRemove(string key, object val, 
    CacheItemRemovedReason reason)
{
    //create an instance of the callback delegate
    CacheItemRemovedCallback callBack =
        new CacheItemRemovedCallback(onRemove);
    Cache.Insert(key,val.ToString() +   
        "*",null,System.DateTime.Now.AddSeconds(5),Cache.NoSlidingExpiration,
        System.Web.Caching.CacheItemPriority.Default, callBack);        
}

One important feature to note in Figure 9 is the pattern used in the Page_Load to determine whether or not to use the data in the cache. You will always want to use this pattern when you deal with items in the cache. Use an if statement to check if the current contents of the cache are null (use a variable for your cache key since you'll be referencing it several times). If it is null, generate the data from its source and place it in the cache. If it is not null, return the data from the cache. If you have some very complex data access logic, you should place the whole if statement in a separate function that's tasked with retrieving the data.
The Cache object has a lot more functionality than most of the other objects I have discussed. It is one of the more powerful features of ASP.NET, and I would definitely recommend reading more on it. The summary at the beginning of this article lists some places to start your search for more information.

Context
The Context object holds data for a single user, for a single request, and it is only persisted for the duration of the request. The Context container can hold large amounts of data, but typically it is used to hold small pieces of data because it is often implemented for every request through a handler in the global.asax.
The Context container (accessible from the Page object or using System.Web.HttpContext.Current) is provided to hold values that need to be passed between different HttpModules and HttpHandlers. It can also be used to hold information that is relevant for an entire request. For example, the IBuySpy portal stuffs some configuration information into this container during the Application_BeginRequest event handler in the global.asax. Note that this only applies during the current request; if you need something that will still be around for the next request, consider using ViewState.
Setting and getting data from the Context collection uses syntax identical to what you have already seen with other collection objects, like the Application, Session, and Cache. Two simple examples are shown here:
// Add item to Context
Context.Items["myKey"] = myValue;

// Read an item from the Context
Response.Write(Context["myKey"]);

ViewState
ViewState holds the state information for a single user, for as long as he is working with this ASPX page. The ViewState container can hold large amounts of data, but care must be taken to manage the size of ViewState since it adds to the download size of every request and response.
ViewState is one of the new containers in ASP.NET that you're probably already using, even if you don't know it. That's because all of the built-in Web controls use ViewState to persist their values between page postbacks. This is all done behind the scenes, so you don't need to worry about it most of the time. You should be aware of it, though, since it does impose a performance penalty on your application. How big this penalty is depends on how much ViewState you are carrying between postbacks—for most Web forms the amount of data is quite small.
The easiest way to determine the amount of ViewState being used by each control on a page is to turn on page tracing and examine how much ViewState each control is carrying. If a particular control doesn't need to have its data persisted between postbacks, turn off ViewState for that control by setting EnableViewState to false. You can also see the total size of the ViewState on a given ASP.NET page by viewing the HTML source of the page in a browser and examining the hidden form field, __VIEWSTATE. Note that the contents are Base64-encoded to prevent casual viewing and manipulation. ViewState can also be disabled for an entire page by adding EnableViewState="false" to the @Page directive.
A typical Web form won't need to manipulate ViewState directly. If you build custom Web controls, however, you will want to understand how ViewState works and implement it for your controls so that they work similarly to the Web controls that ship with ASP.NET. Reading and writing values to and from ViewState is done using the same syntax I've used for the other collection objects:
// Add item to ViewState
ViewState["myKey"] = myValue;

// Read an item from the Context
Response.Write(ViewState["myKey"]);
When building your own custom Web controls, you may also want them to take advantage of ViewState. This is simply done at the property level in your controls. Figure 10 shows how you might store the PersonName property of a simple custom control in ViewState, and use it in the control's Render method.


namespace MSDN.StateManagement
{
    public class HelloPerson : System.Web.UI.Control
    {
        public string PersonName
        {
            get
            {
                string s = (string)ViewState["PersonName"];
                return ((s == null) ? "" : s);
            }
            set
            {
                ViewState["PersonName"] = value;
            }
        }
        protected override void Render(System.Web.UI.HtmlTextWriter 
            writer)
        {
            writer.Write("Hello " + PersonName);
        }
    }
}

Web.config and Machine.config Files
The data in these files is available to all users of an application. Data stored in the Web.config file is available for the life of the application. The data is generally small and the object works well for holding strings for file locations and database connections. Larger pieces of data are better kept elsewhere.
In addition to the various collection objects available, ASP.NET introduces a set of XML configuration files that are used to manage many of the settings for your applications, and even for your whole server. Each ASP.NET application uses a Web.config file to set many of its properties, and each server has a Machine.config file located in its system folder that is used as a basis for all applications. These settings are used as defaults unless overridden. In addition to storing configuration data, these files can store data that your application (or many applications, in the case of the Machine.config) needs.
Configuration information is read whenever the application starts, and is then cached. Since it is cached, the application can read this data very quickly, so you should not be concerned that your application will have a bottleneck because it has to constantly refer to a text file for some integral information. In addition, changes to the Web.config result in an application restart for that application (or all applications on the machine with Machine.config). This ensures that changes to configuration information are always reflected immediately by the application.
Database connection information, default image paths, and paths to XML data files are some of the more common pieces of data that are stored in the Web.config file. The syntax for storing data in the Web.config file is as follows, although ideally you might want to use integrated SQL authentication:
<configuration>
    <!-- application specific settings  -->
    <appSettings>
        <add key="connectionString" value="server=myDBServer;
            uid=myUID;pwd=myPassword;database=myDB" />
    </appSettings>
    <system.web>
        <!-- all wsb settings go here -->
    </system.web>
</configuration>
To access these values within your ASP.NET pages, you use the ConfigurationSettings collection, which is in the System.Configuration namespace. The following simple example demonstrates how to extract the previous connection string into a local variable:
using System.Configuration;
•••
String strConnString =  
  ConfigurationSettings.AppSettings["connectionString"];
Adding a reference to the System.Configuration namespace reduces the amount of code required to reference these values. Since changes to the Web.config or Machine.config result in an immediate application restart, these values are typically only modified by the server administrator, usually by hand. Thus, you should think of these files as being a good place to store read-only data, not data that you will need to modify within your application.

Conclusion
Effective state management can mean the difference between a frustrating user experience with the potential for data corruption and a smooth, fast page or transaction process. While state management in ASP 3.0 was somewhat unwieldy, ASP.NET brings it under control with the state objects discussed here. With their careful use, you'll be on your way to presenting the best Web experience possible to your customers

The difference between Viewstate, SessionState, Cookies and Cache in ASP.NET

Web Applications are natively statesless, means once a web page renders from server to client, nothing remains on server and the next time user submits the page you have to create the page again.
Solutions in ASP.NET
ASP.NET provides multiple simple solutions to this problems like:
1- Viewstate
2- Session Variables
3- Application Variables
4- Cache
5- Cookies
Now the question arises that when to use what?
1- Viewstate
Viewstate is a hidden fields in an ASP.NET page, contains state of those controls on a page whose “EnableViewstate” property is “true”.
You can also explicitly add values in it, on an ASP.NET page like:
Viewstate.Add( “TotalStudents”, “87″ );
Viewstate should be used when you want to save a value between diferent roundtrips of a single page as viewstate of a page is not accessible by another page.
Because Viewstate renders with the page, it consumes bandwith, so be careful to use it in applications to be run on low bandwith.
2- Session Variable
Session variables are usually the most commonly used.
When a user visits a site, it’s sessions starts and when the user become idle or leave the site, the session ends.
Session variables should be used to save and retrive user specefic information required on multiple pages.
Session variables consumes server memory, so if your may have a huge amount visiters, use session very carefully and instead of put large values in it try to put IDs and references
3- Application variables
Application variables are shared variables among all users of a web application
Application variables behave like static variables and they are substitute of static variables as static variables are stateless in web applications
Only shared values should be persisted in Application variables, and as soon as they are not in use they should be removed explicitly.
4- Cache
Cache is probably the least used state feature of ASP.NET.
Cache is basically a resource specific state persistence feature, means unlike session it stick with resource instead of user, for instance: pages, controls etc.
Cache should be used for frequently used pages, controls, and data structures
Data cache can be used to cache frequently used list of values e.g. list of products
6- Cookies
Cookies are some values saved in browsers for a particular website o publicly accessible
The purpose of cookies is to help websites to identify visitors and retrieve their saved preferences
Cookies are also used to facilitate auto login by persisting user id in a cookie save in user’s browser
Because cookies have been saved at client side, they do not create performance issues but may create security issues as they can be hacked from browser
Finally remember the following points on your finger-tips:
1- Viewstate is bandwidth hungry
2- Session variables are memory hungry as per number of users
3- Applications variables are shared
4- Cache is memory hungry as per number of resources
5- Cookies are the least secure

JSON

JSON Tutorial

 JSON: JavaScript Object Notation.
JSON is syntax for storing and exchanging text information. Much like XML.
JSON is smaller than XML, and faster and easier to parse.

JSON Example

{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}
The employees object is an array of 3 employee records (objects).

What is JSON?

  • JSON stands for JavaScript Object Notation
  • JSON is lightweight text-data interchange format
  • JSON is language independent *
  • JSON is "self-describing" and easy to understand
* JSON uses JavaScript syntax for describing data objects, but JSON is still language and platform independent. JSON parsers and JSON libraries exists for many different programming languages.

JSON - Evaluates to JavaScript Objects

The JSON text format is syntactically identical to the code for creating JavaScript objects.
Because of this similarity, instead of using a parser, a JavaScript program can use the built-in eval() function and execute JSON data to produce native JavaScript objects.


JSON - Introduction


Try it Yourself

With our editor, you can edit JavaScript code online and click on a button to view the result:

JSON Example

<html>
<body>
<h2>JSON Object Creation in JavaScript</h2><p>
Name: <span id="jname"></span><br />
Age: <span id="jage"></span><br />
Address: <span id="jstreet"></span><br />
Phone: <span id="jphone"></span><br />
</p>
<script type="text/javascript">
var JSONObject= {
"name":"John Johnson",
"street":"Oslo West 555",
"age":33,
"phone":"555 1234567"};
document.getElementById("jname").innerHTML=JSONObject.name
document.getElementById("jage").innerHTML=JSONObject.age
document.getElementById("jstreet").innerHTML=JSONObject.street
document.getElementById("jphone").innerHTML=JSONObject.phone
</script>


</body>
</html>


Try it yourself »
Click on the "Try it yourself" button to see how it works



Much Like XML

  • JSON is plain text
  • JSON is "self-describing" (human readable)
  • JSON is hierarchical (values within values)
  • JSON can be parsed by JavaScript
  • JSON data can be transported using AJAX

Much Unlike XML

  • No end tag
  • Shorter
  • Quicker to read and write
  • Can be parsed using built-in JavaScript eval()
  • Uses arrays
  • No reserved words

Why JSON?

For AJAX applications, JSON is faster and easier than XML:
Using XML
  • Fetch an XML document
  • Use the XML DOM to loop through the document
  • Extract values and store in variables
Using JSON
  • Fetch a JSON string
  • eval() the JSON string


JSON Syntax


JSON syntax is a subset of JavaScript syntax

JSON Syntax Rules

JSON syntax is a subset of the JavaScript object notation syntax.
  • Data is in name/value pairs
  • Data is separated by comma
  • Curly brackets holds objects
  • Square brackets holds arrays

JSON Name/Value Pairs

JSON data is written as name/value pairs.
A name/value pair consists of a field name (in double quotes), followed by a colon, followed by a value:
"firstName" : "John"
This is simple to understand, and equals to the JavaScript statement:
firstName = "John"



JSON Values

JSON values can be:
  • A number (integer or floating point)
  • A string (in double quotes)
  • A Boolean (true or false)
  • An array (in square brackets)
  • An object (in curly brackets)
  • null

JSON Objects

JSON objects are written inside curly brackets,
Objects can contain multiple name/values pairs:
{ "firstName":"John" , "lastName":"Doe" }
This is also simple to understand, and equals to the JavaScript statements:
firstName = "John"
lastName = "Doe"



JSON Arrays

JSON arrays are written inside square brackets.
An array can contain multiple objects:
{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}
In the example above, the object "employees" is an array containing three objects. Each object is a record of a person (with a first name and a last name).

JSON Uses JavaScript Syntax

Because JSON uses JavaScript syntax, no extra software is needed to work with JSON within JavaScript.
With JavaScript you can create an array of objects and assign data to it like this:

Example

var employees = [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName": "Jones" }
];
The first entry in the JavaScript object array can be accessed like this:
employees[0].lastName;
The returned content will be:
Doe
The data can be modified like this:
employees[0].lastName = "Jonatan";


Try it yourself »
 In the next chapter you will learn how to convert a JSON text to a JavaScript object.



JSON Files

  • The file type for JSON files is ".json"
  • The MIME type for JSON text is "application/json"

JSON HowTo


Converting a JSON Text to a JavaScript Object

One of the most common use of JSON is to fetch JSON data from a web server (as a file or as an HttpRequest), convert the JSON data to a JavaScript object, and then use the data in a web page.
For simplicity, this can be demonstrated by using a string as input (instead of a file).

JSON Example - Object From String

Create a JavaScript string containing JSON syntax:
var txt = '{ "employees" : [' +
'{ "firstName":"John" , "lastName":"Doe" },' +
'{ "firstName":"Anna" , "lastName":"Smith" },' +
'{ "firstName":"Peter" , "lastName":"Jones" } ]}';
Since JSON syntax is a subset of JavaScript syntax, the JavaScript function eval() can be used to convert a JSON text into a JavaScript object.
The eval() function uses the JavaScript compiler which will parse the JSON text and produce a JavaScript object. The text must be wrapped in parenthesis to avoid a syntax error:
var obj = eval ("(" + txt + ")");
Use the JavaScript object in your page:

Example

<p>
First Name: <span id="fname"></span><br />
Last Name: <span id="lname"></span><br />
</p>


<script type="text/javascript">
document.getElementById("fname").innerHTML = obj.employees[1].firstName
document.getElementById("lname").innerHTML = obj.employees[1].lastName
</script>


JSON Parser

lamp  The eval() function can compile and execute any JavaScript. This represents a potential security problem.
It is safer to use a JSON parser to convert a JSON text to a JavaScript object. A JSON parser will recognize only JSON text and will not compile scripts.
In browsers that provide native JSON support, JSON parsers are also faster.
Native JSON support is included in newer browsers and in the newest ECMAScript (JavaScript) standard.
Web Browsers SupportWeb Software Support
  • Firefox (Mozilla) 3.5
  • Internet Explorer 8
  • Chrome
  • Opera 10
  • Safari 4
  • jQuery
  • Yahoo UI
  • Prototype
  • Dojo
  • ECMAScript 1.5
Try it yourself »
For older browsers, a JavaScript library is available at https://github.com/douglascrockford/JSON-js
The JSON format was originally specified by Douglas Crockford

Access DataKeyField value in the update command

 Dim metadataid As Integer = CInt(Gridname.DataKeys(e.Item.ItemIndex))

Basic Difference between ArrayList and List

Basic Difference between ArrayList and List

Lets find out some important differences for two collection types – ArrayList & List<T> , both are designed / exist in framework for grouping the objects together and perform various operations on them as per our requirments.

ArrayList -

1) Namespace System.Collections contain ArrayList ( This namespace is added by default when we we creat any aspx page in C#)
2) Create ArrayList :
ArrayList stringArrayList = new ArrayList();
Here we dont need to specify object type arraylist going to contain,store different type of objects/items/
3) In ArrayList each item is stored as an Object so while reteriving we can get object only.
4) It is like Array of Objects.

List<T> -

1) Namespace System.Collections.Generic List<T> ( we need to add namespace if we want to use Generic Types)
2) Create List<T>:
List<string> stringList = new List<string>();
i.e.
List<type> nameOfList = new List<type>(); & type means object type which List<T> going to hold.
3) In List<T> , it can hold/contain only type of object which is mentioned while initialising the List<T>
Just like in above example stringList will only contain object of type string, the type supplied as generic parameter.
4) It is newly added in .Net 2.0 & onwards, fast processing no need of casting explicitly.
Lets see one example.
string first = “First String”;
string second = “Second String”;
int firstInt = 1;
int secondInt = 2;
ArrayList stringArrayList = new ArrayList(); // No need to specify the object type,can store anything.
stringArrayList.Add(first); // string type
stringArrayList.Add(second); // string type
stringArrayList.Add(firstInt); // Can contain any type so no problem in storing int

List<string> stringList = new List<string>(); // Need to specify the object type, will contain only string types.
stringList.Add(first);
stringList.Add(second);
1) Lets consider Case :
stringList.Add(firstInt); // adding int in string type List.
we will get the exceptions below as List need to contain only string types. others are not allowed.
1) ‘The best overloaded method match for ‘System.Collections.Generic.List<string>.Add(string)’ has some invalid arguments’
2) ‘Argument ’1′: cannot convert from ‘int’ to ‘string’
2) Lets consider another case :
string abcd = stringArrayList[1];
Suppose if we try to get an ArrayList item without using the casting then we can get following exception, as arraylist contain Objects only we need to cast as pre our requirments.
We will get Exception –
‘Cannot implicitly convert type ‘object’ to ‘string’. An explicit conversion exists (are you missing a cast?)’
We can avoid it as
string abcd = stringArrayList[1].ToString(); // Needs casting ,memory overhead.