State management is the persistence of objects or values throughout the lifetime of a web application or for the duration of a user's interaction with the application. ASP.NET provides four ways to manage state for your application (we will cover each in more detail later in the chapter):
User state (session):User state is controlled through the
Session object.
Session allows us to maintain data for a limited duration of time (the configurable default is 20 minutes), for a particular user and isolate that data from other users. For example, we could use
Session state to track the ad banners we have shown a particular user. If the user doesn't interact with the site within the configurable
Session time limit, their data expires and is deleted.
Application state:Application state is controlled through the
Application object.
Application allows us to maintain data for a given ASP.NET application. Settings made in
Application are accessible to all resources (ASP.NET page, web services, and so on) within our web application. For example, if we wanted to retrieve some expensive records out of a database and share it throughout our application, storing the data using
Application state would be very useful.
Transient application state (cache):Transient Application state is controlled through the
Cache object.
Cache is similar in functionality to
Application , in that it is accessible (shared memory) for the entire web application.
H owever, it adds some functionality not available to
Application , in the form of dependencies, callbacks, and expiration. For example, when our ASP.NET application started we might populate an object used by all ASP.NET pages from an XML file. We could store this object in the
Cache and also create a dependency for that item on the XML file the data originated from. If the XML file changed, ASP.NET will detect the file change and notify the
Cache to invalidate the entry. Caching is a very powerful feature of ASP. NET. The differences between
Application and
Cache are summarized later in the chapter.
Static variables:In addition to using the
Application or
Cache sytate, we can also use one of the object-oriented facilities of ASP.NET – static variables. When we can declare a static variable, only one copy of the variable is created no matter how many instances of the class are created. The static variable is accessible throughout our application and in some cases is more efficient than
Application . This is an advanced option and is discussed at the end of the chapter.
The use of
Application and
Session (and now
Cache ) in ASP.NET is identical to the use of
Application and
Session in ASP. You can simply use a string key and set a value:
' Set an Application value
Application("SomeValue") = "my value"
' Read an Application value
Dim someString As String
These familiar semantics are carried forward and used for the
Cache , too:
' Set a Cache value
Cache("SomeValue") = "my value"
' Read a Cache value
Dim someString As String
someString = Cache("SomeValue")
Let's take a closer look at
Session ,
Application , and
Cache and how they relate to building web applications.
Classic ASP's familiar
Session object is new and improved for ASP.NET. The major caveats for
Session use in classic ASP are:
Web farm challenges:
Session data is stored in memory on the server it is created on. In a web farm scenario, where there are multiple web servers, a problem could arise if a user was redirected to a server other than the server upon which they stored their
Session state. Normally, this can be handled by an IP routing solution where the IP address of the client is used to route that client to a particular server. However, some ISPs use farms of reverse proxies, where the client request may come through a different IP on each request. When a user is redirected to a server other than the server that contains their
Session data, poorly designed applications can break.
Supporting clients that don't accept HTTP cookies:Since the Web is inherently a stateless environment, to use
Session state the client and web server need to share a key that the client can present to identify its
Session data on subsequent requests. Classic ASP shared this key with the client through an HTTP cookie. While this scenario worked well for clients that accept HTTP cookies, it broke for the one percent of users that rejected HTTP cookies.
Both of these issues have been addressed in ASP.NET's
Session state, which supports several new features:
Web farm support:ASP.NET
Session now supports storing the
Session data in-process (in the same memory that ASP.NET uses), out-of-process using Windows NT Service (in separate memory from ASP.NET), and in SQL Server (persistent storage). Both the Windows Service and SQL Server solutions support a web farm scenario where all the web servers can be configured to share a common
Session store. So, as users get routed to different servers, each server is able to access that user's
Session data. To the developer using
Session , this is completely transparent and does not require any changes in the application code. Rather, we must configure ASP.NET to support one of these out-of-process options. We will discuss configuring
Session next chapter.
Cookieless mode:Although somewhat supported in ASP through the use of an ISAPI filter (available as part of the IIS 4.0 SDK), ASP.NET makes cookieless support for
Session a first class feature. However, by default,
Session still uses HTTP cookies. When cookieless mode is enabled (details in the next chapter), ASP.NET will munge the URL that it sends back to the client with a
Session ID, rather than storing the
Session ID in an HTTP cookie. When the client makes a request using the munged URL containing the
Session ID, ASP.NET is able to extract it and map the request to the appropriate
Session data.
We will cover how to configure both of these options in the next chapter, when we discuss ASP.NET configuration. From our perspective as developers coding and using
Session , these features are completely transparent.
Session is dedicated data storage for each user within an ASP.NET application. It is implemented as a
Hashtable and stores data based on key/value pair combinations.
In ASP.NET, the use of
Session follows the same pattern as in classic ASP. To set a
Session value in Visual Basic .NET, simply state:
Session("[String key]") = Object
The C# equivalent is:
Session["[String key]"] = Object;
You can provide
Session with a key that identifies the item we are storing. This
Session stores items of type
Object . Since all types in .NET inherit from
Object , this allows you to store anything in
Session . However, objects that contain live references, such as a
DataReader containing an open connection to a database, should not be stored in
Session .
For example, to store the string
Hello World using a key of
SimpleSession , write the following code in Visual Basic .NET:
Session("SimpleSession") = "Hello World"
And in C#:
Session["SimpleSession"] = "Hello World";
Underneath the covers, the CLR knows that the type
String originated from the type
Object , and is able to store that value correctly in memory.
Since
Session is available throughout your web application, you can set values in
global.asax code and access a
Session value from ASP.NET pages.
For example, to retrieve your
Hello World value from
Session , you only need to provide
Session with your key for it to return the value. This is the Visual Basic .NET code:
Dim sessionValue As String
And in C#:
string sessionValue;
sessionValue = Session["SimpleSession"];
For types other than
String , the semantics of accessing the value stored in
Session are a bit more explicit. Because
Session stores its data as an
Object type, giving it the flexibility to store any .NET item, when you wish to retrieve data (other than type
String ) you have to cast the return value to the correct type.
For example, if you stored a custom class you defined called
PurchaseOrder in
Session , here is how you would need to retrieve it in Visual Basic .NET:
Important |
For a class instance to be stored in out-of-process Session state, the class must be marked with the [Serializable] attribute. |
Dim po As PurchaseOrder
po = CType(Session("po"), PurchaseOrder)
And in C#:
PurchaseOrder po;
po = (PurchaseOrder) Session["po"];
In both examples, the
Object returned is cast by the key
po to type
PurchaseOrder .
The
Session API provides additional properties that you can use in code to determine what mode
Session is in:
IsCookieless :Returns
True or
False indicating whether or not
Session is using cookieless mode to maintain the
Session ID. By default, this is
False , meaning that
Session is using cookies.
IsReadOnly :Returns
True or
False indicating whether or not
Session is in read-only mode. Read-only mode is an optimization that does not allow ASP.NET to update
Session data. This can be particularly useful for out of process modes on pages that only read
Session state and don't need write access. When a
Session is read-only, a lock does not have to be maintained and the round-trip back to an out-of-process
Session store for an update can be skipped. By default, this value is
False , and
Session is read/write. We will discuss how to enable
ReadOnly for
Session in the next chapter.
Mode :Returns the value of an enumeration,
SessionStateMode , (found in
System.Web.SessionState ) that indicates the storage mode that
Session is configured for. Values include
InProc ,
Off ,
SQLServer , and
ASP.NET session state is quite different from ASP session state. The new capability of session state that is not bound to the ASP.NET process means that developers can begin to use session state in server farm environments without worrying about whether the client is coming through a proxy server. With the cookieless state functionality, it is even easier to use session state and guarantee that all clients can take advantage of the session state feature. In the next chapter, you will learn how to configure
Session to support a read-only mode as well the other 'mode' options (in-process, Windows Service, and SQL Server).
Configuring and using Session State is covered in more depth in Chapter 13.
Unlike
Session , which is basically dedicated storage for each user,
Application is shared application storage. This shared storage is quite useful, especially if there are resources that all users share, such as an XML representation of a site's shopping catalog. Similar to
Session ,
Application state is simply a
Hashtable that stores key/value pair combinations.
Unlike
Session , however,
Application does not support the concept of storing data separate from the ASP.NET process. Instead,
Application stores its data in process with ASP.NET. If the ASP.NET process is recycled (covered in the next chapter)
Application data is lost. The trade-off is that storing the data in-process is faster than going to another process, or possibly across the network, to retrieve data.
The syntax used for setting and accessing values with
Application is identical to that of
Session , with one exception.
Since
Application is accessible in a multi-user environment, updates to
Application values should be synchronized. This simply means that whenever
Application data is being updated, you should prevent other users or applications from updating the data simultaneously. Luckily,
Application provides you with this capability through a simple set of locking methods. Note these are the same locking methods
Lock and
UnLock supported in ASP.
We read and write data in
Application in a similar manner to
Session using key/value pairs, such as the following in Visual Basic .NET:
Application("HitCounter") = 10
Or in C#:
Application["HitCounter"] = 10;
Similarly, if you wish to read the value back simply use your key, like this in Visual Basic .NET:
Dim HitCount As Integer
HitCount = Application("HitCounter")
Or in C#:
int HitCount = Application["HitCounter"];
However, to update
HitCounter you must synchronize access using the
Lock and
UnLock methods of
Application . Otherwise, the potential exists for two requests to attempt to update
HitCounter simultaneously, causing a potential deadlock or update failure.
Although this is an illustrative example, when you Lock, you are effectively blocking other applications that may be attempting to update the
HitCounter value, causing them to serialize – that is, perform operations one after another. We definitely don't want to Lock/UnLock on each request, as this would negatively affect performance. If the data stored in Application must be updated frequently, it is probably not a good candidate for Application state, unless recreating the data is more costly than the time spent serializing the updates.
Let's look at an illustrative example using
Application.Lock and
Application.UnLock , first in Visual Basic .NET:
Public Sub Application_OnStart()
Application("HitCount") = 0
End Sub
Public Sub Application_OnBeginRequest()
Application.Lock()
Application("HitCounter") = Application("HitCounter") + 1
Application.UnLock()
End Sub
And now in C#:
public void Application_OnStart() {
Application["HitCounter"] = 0;
}
public void Application_OnBeginRequest(){
Application.Lock();
int tmpInt = (int)Application["HitCounter"];
Application["HitCounter"] = tmpInt + 1;
Application.UnLock();
}
In the preceding code, we call
Application.Lock to ensure that while we update
HitCounter , some other thread cannot update the value simultaneously.
Note |
When the ASP.NET process is stopped or recycled, Application state is lost. However, when the process is recycled, the Application_OnEnd event (discussed later) is raised and values can be persisted to a database or file. |
Since ASP.NET is a multi-threaded system,
Application memory can be accessed by multiple processes simultaneously. To use
Application and set values, you must either:
Know that the object stored in
Application is doing its own thread management (not shown).
Or
Perform our own synchronization using
Application.Lock and
Calling
Lock instructs ASP.NET to block any other threads from modifying this resource until
UnLock is called, giving your code exclusive access. However, if you don't explicitly call
UnLock , ASP.NET will call it when the application completes the request, the request times out, or an unhandled error occurs. Although this is done for us, you should always aim to write code that explicitly calls
UnLock .
Classic ASP VB objects could not be hosted in
Application state due to the default threading model these components supported (Apartment Model threading). In effect, accessing an instance of a VB component stored in
Application would cause ASP to serialize (execute one request after another) access to that component. .NET components are free threaded by default and don't have this thread affinity problem. Therefore, there are no performance penalties for storing a Visual Basic .NET object in
Application and accessing it across multiple requests.
Next, let's look at a new object,
Cache , used to store transient application data.
Many developers use
Application as a cache for frequently used resources, for example, reading an XML file that represents a product catalog and storing the object representing that XML file in
Application memory.
However, what happens when this XML file representing the product catalog changes? In most cases, developers who use
Application to manage this data simply force the web application to restart, thus forcing
Application to get refreshed.
The design goal of the
Cache was to give developers the benefits of
Application , but with additional features that went above and beyond those provided by
Application , such as the ability to evict an item from the
Cache when a file changes, it is then your responsibility through code to add the item back to the
Cache if you desire.
Cache is an instance of the
Cache class found in the namespace
System.Web.Caching . In addition to being a simple key/value pair
Hashtable like
Application , the
Cache also supports:
Dependency-based expiration:Dependencies can be other
Cache keys, files, or a timestamp. When one of the dependencies changes or expires (timestamp), the
Cache item is invalidated and removed from the
Cache .
Lock management:Unlike
Application , the
Cache class does its own internal lock management. Therefore, while
Application required us to explicitly
Lock and
UnLock when updating
Application ,
Cache doesn't require this. Keep in mind that we do still need to manage concurrency for objects stored in the
Cache just as we do with objects stored in
Application .
Resource management:When the
Cache detects memory pressure, a least recently used algorithm walks the
Cache and automatically evicts items used less frequently. Therefore, before we request an item, we always need to check if the item exists.
Callbacks:The
Cache supports allows us to run code when items are removed from the
The
Cache supports two methods of inserting items:
Implicit:We are familiar with this syntax from working with
Session or
Application using the key/value pairs.
In Visual Basic .NET:
Dim productDataSet As New DataSet()
' Populate DataSet
Cache("products") = productDataSet
And in C#:
DataSet productDataSet = new DataSet();
// Populate DataSet
Cache["products"] = productDataSet;
Explicit:Using the
Insert method, it allows us to set up special relationships such as dependencies. In VB.NET, the code to do this is.
Dim productDataSet As New DataSet()
' Populate DataSet
Cache.Insert("products", productDataSet, Nothing)
In C#:
DataSet productDataSet = new DataSet();
// Populate DataSet
Cache.Insert("products", productDataSet, null)
The
Cache also supports an
Add method. The
Add method behaves similar to
Insert , with the exception that it will only add them item to the
Cache if it does not already exist – whereas the
Insert method will always add the item into the
Cache , even if it already exists.
When using the
Cache , you will mostly use the explicit
Insert . Let's look at some examples.
Dependency-based expiration is very powerful. It allows you to create a relationship between an item in the
Cache and either a file, another
Cache key, or a defined point in time. For example, if your site used XML and XSL transforms to control aspects of content, you could load the XML into an
XmlDocument class and store the value within the
Cache . You could also establish a relationship between the cached
XmlDocument and the file that it is reading, using the file-based dependency feature of the
Cache . Let's build this sample.
<?xml version="1.0"?>
<books>
<book>
<name>Professional ASP.NET 2nd Edition</name>
<isbn>1861007035</isbn>
<publisher>Wrox Press</publisher>
<authors>
<author name="David Sussman"/>
<author name="Brian Francis"/>
<author name="Alex Homer"/>
<author name="Karli Watson"/>
<author name="Rich Anderson"/>
<author name="Rob Howard"/>
</authors>
<description>
ASP.NET is a unified web development
platform that provides the services necessary
for developers to build enterprise-class web
applications.
</description>
</book>
</books>
The file is saved as
1861007035.xml , which is the ISBN for the book Professional ASP.NET 1.0 Special Edition. You also have an XSL transform for this file, called
book.xsl :
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method=l"/>
<xsl:template match="/">
<l>
<head>
<title><xsl:value-of select="books/book/name"/></title>
</head>
<style>
body { font-family: Arial; font-size: 18; color:white; }
li { list-style: square outside; }
</style>
<body bgcolor="black">
<xsl:apply-templates/>
</body>
<l>
</xsl:template>
<xsl:template match="name">
<h1><font color="red"><xsl:value-of select="."/></font></h1>
</xsl:template>
<xsl:template match="description">
<h6><xsl:value-of select="."/></h6>
</xsl:template>
<xsl:template match="isbn">
<font size="1">ISBN: <xsl:value-of select="."/></font><br/>
</xsl:template>
<xsl:template match="publisher">
<font size="1">Publisher: <xsl:value-of select="."/></font><br/>
</xsl:template>
</xsl:stylesheet>
The following code snippet is the ASP.NET page (
SingleFilevb.aspx ) that uses the
Cache and creates a file dependency on the XML file only – in this particular example we are not caching the XSL file:
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<Script runat="server">
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim dom As XmlDocument
Dim xsl As New XslTransform()
' Do we have the Wrox Pro ASP.NET 2nd Ed book in the Cache?
If (IsNothing(Cache("1861007035.xml"))) Then
CacheStatus.Text = "Item not present, updating the Cache..."
UpdateCache("1861007035.xml")
Else
CacheStatus.Text = "Retrieving from Cache"
End If
' Load the transform
xsl.Load(Server.MapPath("book.xsl"))
dom = CType(Cache("1861007035.xml"), XmlDocument)
BookDisplay.Document = dom
BookDisplay.Transform = xsl
End Sub
Public Sub UpdateCache(strItem As String)
Dim strPath As String
Dim dom As New XmlDocument()
' Determine the file path of the file to monitor
strPath = Server.MapPath(strItem)
' Load the file into an Xml Dom
dom.Load(strPath)
' Create a CacheDependency on the file
Dim dependency as New CacheDependency(strPath)
' Cache the XML document
Cache.Insert(strItem, dom, dependency)
End Sub
</Script>
Status: <asp:label id="CacheStatus" runat=server/>
<br>
<asp:xml id="BookDisplay" runat=server/>
The interesting code appears in the
UpdateCache subroutine, which is called if the
Cache key
1861007035.xml is not present. We first map the path to the XML file, which is in the same directory, and load that XML file into an
XmlDocument class. Then, we create a new
CacheDependency class passing in the path to the XML file. Finally, we use the Cache's
Insert method and create a new
Cache entry using the name of the file (
1861007035.xml ), the
XmlDocument instance,
dom , and the
CacheDependency class instance,
dependency .
On requesting this page for the first time, you would see the screen shown in Figure 12-9:
Figure 12-9:
On subsequent requests you would see the Status: Retrieving from Cache message.
If you open the
1861007035.xml file and modify the name from
Professional ASP.NET 1.0 Special Edition to
Pro ASP.NET 1.0 , the file change notification would be enforced and the
XmlDocument storing the XML from the file would be removed from the
Cache . Requesting the ASP.NET page would bring up the screen shown in Figure 12-10:
Figure 12-10:
What if instead of monitoring a file, you wanted to remove an entry (or series of entries) from the
Cache when another item in the
Cache changed? This option is supported through a key-based dependency.
The syntax for supporting key-based dependencies is very similar to that used in file-based dependencies. For example, you can easily change the preceding code to support a key-based dependency by modifying only a couple of lines.
If you cached multiple XML documents for each Wrox book on .NET, you could set up a dependency relationship where the
Cache entries for the books could be invalidated (and reloaded) whenever a master key, for example
The following code example, called
KeyBasedvb.aspx , creates such a relationship:
<%@ Import Namespace="System.Xml" %>
<Script runat="server">
Public Sub Create(sender As Object, e As EventArgs)
' Create the Cache entry for the dependency relationship
' the value of the key doesn't matter
Cache("booksDependencyKey") = "Book Dependency"
' Create a string array with the key names for the
' dependencies to be created upon
Dim dependencyKey(0) As String
dependencyKey(0) = "booksDependencyKey"
' Create a CacheDependency on this key
Dim dependency as New CacheDependency(nothing, dependencyKey)
' Cache the XML document
Cache.Insert("1861007035.xml", Load("1861007035.xml"), dependency)
Status()
End Sub
Private Function Load(xmlFile As String) As XmlDocument
Dim dom As New XmlDocument()
dom.Load(Server.MapPath(xmlFile))
Return dom
End Function
Public Sub Invalidate(sender As Object, e As EventArgs)
Cache.Remove("booksDependencyKey")
Status()
End Sub
Public Sub Status()
If (IsNothing(Cache("1861007035.xml"))) Then
lblStatus1.Text = "No value..."
Else
lblStatus1.Text = "Cache entry exists..."
End If
End Sub
</Script>
<form runat=server>
<input type="submit" OnServerClick="Create"
value="Create Cache Entries" runat="server" />
<input type="submit" OnServerClick="Invalidate"
value="Invalidate Key" runat="server" />
</form>
Status for cache key: 1861007035.xml: <b><asp:label id="lblStatus1"
When you run this code, you need to press the Create Cache Entries button to create the
Cache entry for the XML file, as well as the dependency relationship. You can then press Invalidate Key, which raises the
Invalidate event. Within this event, we explicitly remove the cache key
booksDependencyKey . This enforces the dependency and also removes the
Cache entry for your XML document.
Finally, in addition to file and key-based dependencies, you can also create dependencies on time values. Consider an example where Wrox were to store all of its book titles in a single table in the database, and you knew that this data was only updated once a week. You could cache a
DataSet that represents this data with an explicit expiration of 60 minutes. This will save you going to the database for every request, but in case an update occurs, you can still guarantee that the data will be fresh within the following hour.
Here's the code from
TimeBasedvb.aspx that does this:
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat=server>
Private DSN As String
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim strCacheKey As String
Dim titlesDataSet As DataSet
strCacheKey = "Titles"
If (IsNothing(Cache(strCacheKey))) Then
lblStatus.Text = "Getting data from database..."
LoadTitles(strCacheKey)
Else
lblStatus.Text = "Getting data from Cache..."
End If
titlesDataSet = CType(Cache(strCacheKey), DataSet)
TitleList.DataSource = titlesDataSet
TitleList.DataBind()
End Sub
Public Sub LoadTitles(strCacheKey As String)
Dim connection As SqlConnection
Dim command As SqlDataAdapter
Dim sqlSelect As String
Dim strDsn As String
Dim dataset As New DataSet()
sqlSelect = "SELECT title, pub_id, price, notes, pubdate FROM titles"
strDsn = "server=localhost;uid=sa;pwd=;database=pubs"
connection = New SqlConnection(strDsn)
command = New SqlDataAdapter(sqlSelect, connection)
command.Fill(dataset, "Author-Titles")
Cache.Insert(strCacheKey, dataset, nothing, _
DateTime.Now.AddMinutes(60), TimeSpan.Zero)
End Sub
</script>
<font size=6>
<asp:label id="lblStatus" runat="server"/>
</font>
<P>
<ASP:DataGrid id="TitleList" HeaderStyle-BackColor="#aaaadd"
BackColor="#ccccff"
runat="server" />
In this example, we have some logic at the beginning that checks for an entry in the
Cache named
Titles . If the
Cache entry doesn't exist, we then call the subroutine
LoadTitles , which connects to a database, performs a select on the titles table, fills a
DataSet , and finally inserts the
DataSet into the
Cache . We are using the explicit
Insert method of the
Cache :
Cache.Insert(strCacheKey, dataset, nothing, _ DateTime.Now.AddMinutes(60), TimeSpan.Zero)
This adds a
Cache entry with the key
titles , the populated
dataset , and also instructs the cache to expire the item after 60 minutes.
Cache additionally supports a very useful callback capability. The callback allows you to run your code when an item is removed from the cache, giving you the opportunity to add it back.
We could make the following modification to the preceding code (highlighted), which would guarantee that our item is always served from the cache:
...If (loadedFromCallback) Then
lblStatus.Text = lblStatus.Text + "loaded from callback"
loadedFromCallback = false
End If sqlSelect = "SELECT title, pub_id, price, notes, pubdate FROM titles" connection = New SqlConnection("server=localhost;uid=sa;pwd=00password;database=pubs") command = New SqlDataAdapter(sqlSelect, connection) command.Fill(dataset, "Author-Titles")
' Create the a CacheItemRemovedCallback
Dim onRemove As New CacheItemRemovedCallback(AddressOf _
Me.RemovedCallback)
Cache.Insert(strCacheKey, dataset, nothing,
DateTime.Now.AddMinutes(60), TimeSpan.Zero, _
CacheItemPriority.High, onRemove) End Sub
' This method represents the callback
Public Sub RemovedCallback(key As String, value As Object,
reason As CacheItemRemovedReason)
' Let's always re-add the item if removed
LoadTitles(key)
End Sub </script> <font size=6> <asp:label id="lblStatus" runat="server"/> </font> <P> <ASP:DataGrid id="TitleList" HeaderStyle-BackColor="#aaaadd" BackColor="#ccccff" runat="server" />
Caching adds a lot of powerful new features to manage data that you ordinarily would have stored in
Application state. Dependencies allow you to set up relationships with items that can invalidate the cache, and callbacks allow you to execute your own code whenever an item is removed from the
Cache .
State management in ASP.NET should be very familiar to developers who have worked with ASP. Both
Session and
Application state remain identical in use and you now have the
Cache option. It is very important to understand state management and when to use the options provided by it. Here are some basic guidelines:
Session :Used to store data that should be available to the user on each request. Be efficient about what you store in
Session , since each
Session will get its own individual copy of the data. Remember that class instances stored in out-of-process session state must be attributed with the
[Serializable] attribute at the class level.
Application :Used to store data that needs to be available to the entire application. A good candidate for
Application is data that remains fairly static and must be available on each request. Remember to use the
Lock and
Unlock methods to control access to
Application when updating the data.
Cache :Used to store data that may be used on each request, or data where a dependency relationship needs to be established. In many cases,
Cache can be used in place of
Application .