Caching Architecture Guide For .NET Framework Applications
Caching Architecture Guide For .NET Framework Applications
}
Both of these examples result in the same cache configuration.
Using Page Fragment Caching
Page fragment caching involves the caching of a fragment of the page, as opposed to
the entire page. Sometimes full page output caching is not feasible for example,
when portions of the page need to be dynamically created for each user request. In
such cases, it can be worthwhile to identify portions of the page or controls that
do not often change and that take considerable time and server resources to create.
After you identify these portions, you can wrap them in a Web Forms user control
and cache the control so that these portions of the page dont need to be recreated
each time.
Chapter 2: Understanding Caching Technologies 21
You can implement page fragment caching by adding the necessary directives (high-
level, declarative implementation) to the user control or by using metadata at-
tributes in the user control class declaration.
For more information about page fragment caching, see Caching Portions of an
ASP.NET Page, in the MSDN Library.
Determining What to Cache with Page Fragment Caching
Use page fragment caching when you cannot cache the entire Web page. There are
many situations that can benefit from page fragment caching, including:
G
Page fragments (controls) that require high server resources to create.
G
Sections on a page that contain static data.
G
Page fragments that can be used more than once by multiple users.
G
Page fragments that multiple pages share, such as menu systems.
Note: ASP.NET version 1.1, part of the Microsoft Visual Studio.NET 2003 development
system, introduces a new Shared attribute in the user controls <%@ OutputCache %> direc-
tive. This attribute allows multiple pages to share a single instance of a cached user control. If
you dont specify the Shared attribute, each page gets its own instance of the cached control.
Configuring Page Fragment Caching
The following example shows how to implement fragment caching in a Web user
control.
// Partial caching for 120 seconds
[System.Web.UI.PartialCaching(120)]
public class WebUserControl : System.Web.UI.UserControl
{
// Your Web control code
}
When the page containing the user control is requested, only the user control not
the entire page is cached.
Using the ASP.NET Cache in Non-Web Applications
The ASP.NET cache object is located in the System.Web namespace, and because it is
a generic cache implementation, it can be used in any application that references this
namespace.
The System.Web.Caching.Cache class is a cache of objects. It is accessed either
through the static property System.Web.HttpRuntime.Cache or through the helper
instance properties System.Web.UI.Page and System.Web.HttpContext.Cache. It is
therefore available outside the context of a request. There is only one instance of this
object throughout an entire application domain, so the HttpRuntime.Cache object
can exist in each application domain outside of Aspnet_wp.exe.
Caching Architecture Guide for .NET Framework Applications 22
The following code shows how you can access the ASP.NET cache object from a
generic application.
HttpRuntime httpRT = new HttpRuntime();
Cache cache = HttpRuntime.Cache;
After you access the cache object for the current request, you can use its members in
the usual way.
Managing the Cache Object
ASP.NET supports a host of application performance counters that you can use to
monitor the cache object activity. Monitoring these performance counters can help
you locate and resolve issues in the performance of your ASP.NET cache. Table 2.2
describes these counters.
Table 2.2: Application performance counters for monitoring a cache
Counter Description
Cache Total Entries The number of entries in the cache
Cache Total Hits The number of hits from the cache
Cache Total Misses The number of failed cache requests per application
Cache Total Hit Ratio The ratio of hits to misses for the cache
Cache Total Turnover Rate The number of additions and removals to the total cache per
second
Cache API Entries The number of entries in the application (programmatic cache)
Cache API Hits The number of hits from the cache when the cache is accessed
through the external cache APIs (programmatic cache)
Cache API Misses The number of failed requests to the cache when the cache is
accessed through the external cache APIs (programmatic cache)
Cache API Hit Ratio The cache ratio of hits to misses when the cache is accessed
through the external cache APIs (programmatic cache)
Cache API Turnover Rate The number of additions to and removals from the cache per
second, when accessed through the external cache APIs
(programmatic cache)
Output Cache Entries The number of entries in the output cache
Output Cache Hits The number of requests serviced from the output cache
Output Cache Misses The number of failed output cache requests per application
Output Cache Hit Ratio The percentage of requests serviced from the output cache
Output Cache Turnover Rate The number of additions to and removals from the output cache
per second
Chapter 2: Understanding Caching Technologies 23
Note that the Cache API counters do not track internal usage of the cache by
ASP.NET. The Cache Total counters track all cache usage.
The Turnover Rate counters help determine how effectively the cache is being used.
If the turnover is large, the cache is not being used efficiently because cache items
are frequently added and removed from the cache. You can also track cache effec-
tiveness by monitoring the Hit counters.
For more information about these performance counters, see Performance Counters
for ASP.NET, in the MSDN Library.
Using Remoting Singleton Caching
Microsoft .NET remoting provides a rich and extensible framework for objects
executing in different AppDomains, in different processes, and on different comput-
ers to communicate seamlessly with each other. Microsoft .NET remoting singleton
objects service multiple clients and share data by storing state information between
client invocations.
You can use .NET remoting when you need a custom cache that can be shared across
processes in one or several computers. To do this, you must implement a caching
service using a singleton object that serves multiple clients using .NET remoting.
To implement a cache mechanism using .NET remoting, ensure that the remote
object lease does not expire and that the remoting object is not destroyed by the
garbage collector. An object lease is the period of time that a particular object can
remain in memory before the .NET remoting system begins to delete it and reclaim
the memory. When implementing a remoting singleton cache, override the
InitializeLifetimeService method of MarshalByRefObject to return null. Doing so
ensures that the lease never times out and the object associated with it has an infinite
lifetime. The following example shows how to cause your object to have infinite
lifetime.
public class DatasetStore : MarshalByRefObject
{
// A hash table-based data store
private Hashtable htStore = new Hashtable();
//Returns a null lifetime manager so that GC won't collect the object
public override object InitializeLifetimeService() { return null; }
// Your custom cache interface
}
This code ensures that the garbage collector does not collect the object by returning
a null lifetime manager for the object.
Caching Architecture Guide for .NET Framework Applications 24
You can implement the remoting singleton as a caching mechanism in all layers of a
multilayer architecture. However, because of the relatively high development cost of
its implementation, youre most likely to choose this solution when a custom cache
is needed in the application and data tiers.
You can often use solutions based on Microsoft SQL Server instead of remoting
singleton caching solutions. It is tempting to choose remoting singleton caching
because it is simple to implement, but the poor performance and the lack of
scalability it produces mean that this choice is often misguided.
Using Memory-Mapped Files
Memory-mapped files offer a unique memory management feature that allows
applications to use pointers to access files on disk the same way that applications
access dynamic memory. With this capability, you can map a view of all or part of a
file on disk to a specific range of addresses in your processs address space. After
you do so, accessing the content of a memory-mapped file is as simple as
dereferencing a pointer in the designated range of addresses.
Both code and data are treated the same way in Windows: Both are represented by
pages of memory, and both have those pages backed by a file on disk. The only
difference is the type of file that backs them. Code is backed by the executable
image, and data is backed by the system pagefile.
Because of the way that memory-mapped files function, they can also provide a
mechanism for sharing data between processes. By extending the memory-mapped
file capability to include portions of the system pagefile, applications are able to
share data that is backed by that pagefile. Each application simply maps a view of
the same portion of the pagefile, making the same pages of memory available to
each application. Because all processes effectively share the same memory, applica-
tion performance increases.
You can use these unique capabilities of memory-mapped files to develop an effi-
cient custom cache that can be shared across multiple application domains and
processes within the same computer. A custom cache based on memory-mapped
files includes the following components:
G
Windows NT service Creates the memory-mapped file when it is started and
deletes the memory-mapped file when it is stopped. Because each process using
the cache needs a pointer to the memory-mapped file, you need a Windows NT
service to create the memory-mapped file and to pass handles to processes that
want to use the cache. Alternatively, you can use a named memory-mapped file
and get a handle to the memory-mapped file for each process by using the
memory-mapped file name.
Chapter 2: Understanding Caching Technologies 25
G
Cache management DLL Implements the specific cache functionality, such as:
G
Inserting and removing items from the cache.
G
Flushing the cache using algorithms such as Least Recently Used (LRU) and
scavenging. For more information about flushing, see Chapter 5, Managing
the Contents of a Cache.
G
Validating data to protect it against tampering or spoofing. For more informa-
tion about security, see Chapter 6, Understanding Advanced Caching Issues.
Because a memory-mapped file is a custom cache, it is not limited to a specific layer
or technology in your application.
Memory-mapped file caches are not easy to implement because they require the use
of complex Win32 application programming interface (API) calls. The .NET Frame-
work does not support memory-mapped files, so any implementations of a memory-
mapped file cache run as unmanaged code and do not benefit from any .NET
Framework features, including memory management features, such as garbage
collection, and security features, such as code access security.
Management functionality for memory-mapped file custom cache needs to be
custom developed for your needs. Performance counters can be developed to show
cache use, scavenging rate, hit-to-miss ratios, and so on.
Using Microsoft SQL Server 2000 or MSDE for Caching
You can use Microsoft SQL Server 2000, and its scaled down version, Microsoft SQL
Server 2000 Desktop Engine (MSDE), to cache large amounts of data. Although SQL
Server is not the ideal choice when caching small data items because of its relatively
slow performance, it can be a powerful choice when data persistency is critical or
when you need to cache a very large amount of data.
Note: In caching terms, SQL Server 2000 and MSDE provide the same capabilities. All refer-
ences to SQL Server in this section equally apply to MSDE.
If your application requires cached data to persist across process recycles, reboots,
and power failures, in-memory cache is not an option. In such cases, you can use a
caching mechanism based on a persistent data store, such as SQL Server or the NTFS
file system. It also makes sense to use SQL Server to cache smaller data items to gain
persistency.
SQL Server 2000 limits you to 8 KB of data when you are accessing VarChar and
VarBinary fields using Transact-SQL or stored procedures. If you need to store
larger items in your cache, use an ADO.NET SQLDataAdapter object to access
DataSet and DataRow objects.
Caching Architecture Guide for .NET Framework Applications 26
SQL Server caching is easy to implement by using ADO.NET and the .NET Frame-
work, and it provides a common development model to use with your existing data
access components. It provides a robust security model that includes user authenti-
cation and authorization and can easily be configured to work across a Web farm
using SQL Server replication.
Because the cache service needs to access SQL Server over a network and the data is
retrieved using database queries, the data access is relatively slow. Carefully com-
pare the cost of recreating the data versus retrieving it from the database.
SQL Server caching can be useful when you require a persistent cache for large data
items and you do not require very fast data retrieval. Carefully consider how much
memory you have and how big your data items are. Do not use all of your memory
to cache a few large data items because doing so degrades overall server perfor-
mance. In such cases, caching items in SQL Server can be a good practice. Remem-
ber, though, that implementing a SQL Server caching mechanism requires installing,
managing, and licensing at least one copy of SQL Server or MSDE.
When you use SQL Server for caching, you can use the SQL Server management
tools, which include a host of performance counters that can be used to monitor
cache activity. For example, use the SQLServer:Databases counters on your cache
database table to monitor your cache performance, and use counters such as Trans-
actions/sec and Data File(s) Size (KB) to monitor usage.
Using Static Variables for Caching
Static variables are often used to save class state, and you can use them to create
customized cache objects. To do so, declare your cache data store as a static variable
in your custom-developed cache class, and implement interfaces to insert, remove,
and access items in the data store.
Using static variables is simple if no special cache capabilities are needed, such as
dependencies, expiration, and scavenging. Because the cache is an in-memory
system, static variables provide fast, direct access to the cached data. Static variable
caching is useful to store state when other mechanisms are not available or are too
costly. Use a static variable cache when you do not have another key/value dictio-
nary available or when you need a fast in-process caching mechanism. In ASP.NET
applications, use the Cache object instead.
You can use static variables to cache large data items, provided that the items do not
often change. Because there is no mechanism for invalidating items, obsolete large
items can waste valuable memory.
When using a static variable cache, you must ensure that you either implement your
own thread safety mechanism or use a .NET Framework object that can be synchro-
nized, for example, a Hashtable object.
Chapter 2: Understanding Caching Technologies 27
The following example shows how to implement a static variable cache by using a
hash table.
static Hashtable mCacheData = new Hashtable();
The scope of the static variables can be limited to a class or a module or be defined
with project-level scope. If the variable is defined as public in your class, it can be
accessed from anywhere in your project code, and the cache will be available
throughout the application domain. The lifetime of static variables is directly linked
to their scope.
Using ASP.NET Session State
You can use ASP.NET session state (based on the HttpSessionState class) to cache
per-user session state. It solves many of the limitations that are inherent in ASP
session state, including:
G
The ASP session state is tied to the ASP hosting process, and as such is recycled
when the ASP process is recycled. You can configure ASP.NET session state to
avoid this.
G
ASP session state has no solution for functioning in a Web server farm. The
ASP.NET session state solution does not provide the best results when scalability
and availability are important, but it works well for small scalar values, such as
authentication information.
G
ASP session state depends on the client browser accepting cookies. If cookies are
disabled in the client browser, session state cannot be used. ASP.NET session state
can be configured not to use cookies.
The ASP.NET session state is much improved. This section describes how and where
session state is best used.
ASP.NET session state has three modes of operation:
G
InProc Session state is held in the memory space of the Aspnet_wp.exe process.
This is the default setting. In this setting, the session state is recycled if the pro-
cess or the application domain is recycled.
G
StateServer Session state is serialized and stored in a separate process
(Aspnet_state.exe); therefore, the state can be stored on a separate computer
(a state server).
G
SQLServer Session state is serialized and stored in a SQL Server database.
You can specify the mode to be used for your application by using the mode at-
tribute of the <sessionState> element of the application configuration file.
The scope of the ASP.NET session state is limited to the user session it is created in.
In out-of-process configurations for example, using StateServer or SQLServer
Caching Architecture Guide for .NET Framework Applications 28
mode in a Web farm configuration the session state can be shared across all servers
in the farm. However, this benefit does come at a cost. Performance may decrease
because ASP.NET needs to serialize and deserialize the data and because moving the
data over the network takes time.
For more information about ASP.NET session state, see ASP.NET Session State, in
the MSDN Library.
Choosing the Session State Mode
Each mode of operation, InProc, StateServer, and SQLServer, presents different
issues to consider when you design your caching policy.
Using InProc Mode
When you use InProc mode, you are storing the state in the Aspnet_wp.exe process.
You cannot use InProc mode in a Web garden environment because multiple in-
stances of Aspnet_wp.exe are running on the same computer.
InProc is the only mode that supports the Session_End event. The Session_End
event fires when a users session times out or ends. You can write code in this event
to clean up server resources.
Using StateServer Mode
StateServer mode stores the state in a dedicated process. Because it is an out-of-
process system, you must ensure that the objects you cache in it are serializable to
enable cross-process transmission.
When using the Session object for caching in a Web farm environment, ensure that
the <machineKey> element in Web.config is identical across all of your Web servers.
Doing so guarantees that all computers are using the same encryption formats so
that all computers can successfully access the stored data. For more information
about encryption, see <machineKey> Element, in the MSDN Library.
For session state to be maintained across servers in a Web farm, the application path
of the Web site (for example, \LM\W3SVC\2) in the Internet Information Services
(IIS) metabase must be identical across all servers in that farm. For more information
about this, see article Q325056, PRB: Session State Is Lost in Web Farm If You Use
SqlServer or StateServer Session Mode, in the Microsoft Knowledge Base.
Using SQLServer Mode
In SQLServer mode, ASP.NET serializes the cache items and stores them in a SQL
Server database, so you must ensure that the objects you are using are serializable.
If you specify integrated security in the connection string used to access your ses-
sion state (for example, trusted_connection=true or integrated security=sspi), you
cannot use impersonation in ASP.NET. For more information about this problem, see
Chapter 2: Understanding Caching Technologies 29
article Q324479, FIX: ASP.NET SQL Server Session State Impersonation Is Lost
Under Load, in the Microsoft Knowledge Base.
For session state to be maintained across different servers in a Web farm, the appli-
cation path of the Web site (for example, \LM\W3SVC\2) in the IIS metabase
should be identical across all servers in that farm. For details about how to imple-
ment this, see article Q325056, Session State Is Lost in Web Farm If You Use
SqlServer or StateServer Session Mode, in the Microsoft Knowledge Base.
You can configure ASP.NET session state to use SQL Server to store objects. Access to
the session variables is slower in this situation than when you use an in-process
cache; however, when session data persistency is critical, SQL Server provides a
good solution. By default, SQL Server stores session state in the tempdb database,
which is re-created after a SQL Server computer reboots. You can configure SQL
Server to store session data outside of tempdb so that it is persisted even across
reboots. For information about script files that you can use to configure SQL Server,
see article Q311209, Configure ASP.NET for Persistent SQL Server Session State
Management, in the Microsoft Knowledge Base.
When you use session state in SQL Server mode, you can monitor the SQL Server
tempdb counters to provide some level of performance monitoring.
Determining What to Cache in the Session Object
You can use the Session object to store any of the .NET Framework data types;
however, be aware of which sort of data is best suited to each cache mode.
You can use any mode to store .NET Framework basic types (such as Int, Byte,
String) because ASP.NET uses an optimized internal method for serializing and
deserializing basic data types when using out-of-process modes.
Store complex types (such as ArrayList) only in the InProc mode, because ASP.NET
uses the BinaryFormatter to serialize data, which can affect performance. Note that
serialization occurs only in the StateServer and SQLServer out-of-process modes.
For example, the Session object is ideal for storing user authentication data during
a user session. Because this information is likely to be stored as a .NET Framework
basic type (such as, String), it can use any of the three modes. However, you must
consider the security aspects of storing sensitive data in a cache. The data can
be accessed from different pages without requiring the user to re-enter logon
information.
Try to avoid using session state for large data items because this degrades your
application performance. Table 2.3 on the next page compares response times as the
size of the cache changes.
Caching Architecture Guide for .NET Framework Applications 30
Table 2.3: Caching performance
Cache size Responses per second Time to first byte Time to last byte
2 KB 447.38 19.43 19.65
200 KB 16.12 667.95 668.89
Because session state can function as both an in-process and an out-of-process cache,
it is suitable for a wide range of solutions. It is simple to use, but it does not support
data dependencies, expiration, or scavenging.
Implementing Session State
ASP.NET session state provides a simple interface for adding and removing vari-
ables and simple configuration using the Web.config file. Changes to this file are
reflected immediately without the need to restart the ASP.NET process.
The following example shows how to implement SQLServer mode session caching
in the Web.config file.
<sessionState
mode="SQLServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1; Integrated Security=SSPI"
cookieless="false"
timeout="20"
/>
The following example shows how you can use the session object to store and access
user credentials.
private void SaveSession(string CartID)
{
Session["ShoppingCartID"] = CartID;
}
private void CheckOut()
{
string CartID = (string)Session["ShoppingCartID"];
if(CartID != null)
{
// Transfer execution to payment page.
Server.Transfer("Payment.aspx");
}
else
{
// Display error message.
}
}
Chapter 2: Understanding Caching Technologies 31
Remember to secure any credentials when caching them. For more information
about securing custom caches, see Securing a Custom Cache, in Chapter 6,
Understanding Advanced Caching Issues.
Using ASP.NET Client-Side Caching and State
You can reduce the workload on your server by storing page information using
client-side options. This approach has minimal security support but results in faster
server performance because the demand on server resources is modest. Because you
must send information to the client before it can be stored, there is a practical limit
on how much information you can store this way.
The main mechanisms to implement client-side caching are:
G
Hidden fields
G
View state
G
Hidden frames
G
Cookies
G
Query strings
Each of these mechanisms is useful for caching different types of state in different
scenarios.
Using Hidden Fields
You can store page-specific information in a hidden field on your page to maintain
the state of that page. For more information about hidden fields, see Introduction
to Web Forms State Management, in the MSDN Library.
It is best to store only small amounts of frequently changing data in hidden fields
because this data is included in the roundtrips to the server on every postback.
Storing a large amount of data slows your application because of network traffic
load. ASP.NET provides the HtmlInputHidden control, which offers hidden field
functionality.
Note: If you use hidden fields, you must submit your pages to the server by using the HTTP
POST method rather than by requesting the page using the HTTP GET method.
Benefits and Limitations of Hidden Fields
The benefits of using hidden fields to store client-side state include:
G
No server resources are required. The hidden field is stored and read directly
from the page.
G
Almost all browsers and client devices support forms with hidden fields.
Caching Architecture Guide for .NET Framework Applications 32
G
Hidden fields are simple to implement.
G
Hidden fields are good for caching data in Web farm configurations because the
data is cached on the client.
The limitations of using hidden fields are:
G
The hidden field can be tampered with. The information in this field can be seen
if the page output source is viewed directly, creating a potential security issue.
G
The hidden field does not support rich structures; it offers only a single value
field in which to place information. To store multiple values, you must imple-
ment delimited strings and write the code required to parse those strings.
G
Page performance decreases when you store large values because hidden fields
are stored in the page.
Hidden fields are a good solution for caching small amounts of noncritical, string
data for use in Web pages.
Implementing Hidden Fields
The following example shows how to declare a hidden field on a Web page.
<input id="HiddenValue" type="hidden" value="Initial Value" runat="server"
NAME="HiddenValue">
This code creates a hidden field containing the string data Initial Value.
If you cannot use hidden fields because of the potential security risk, consider using
view state instead.
Using View State
Web Forms pages and controls all have a ViewState property, which is a built-in
structure for automatically retaining values among multiple requests for the same
page. The view state is internally maintained as a hidden field on the page but is
hashed, providing greater security than developer-implemented hidden fields do.
For more information about view state, see Introduction to Web Forms State Man-
agement, in the MSDN Library.
You can use view state to store your own page-specific values across roundtrips
when the page posts back to itself. For example, if your application is maintaining
user-specific information, such as a user name that is displayed in a welcome
message, you can store the information in the ViewState property.
Performance of view state varies depending on the type of server control to which it
is applied. Label, TextBox, CheckBox, RadioButton, and HyperLink are server
controls that perform well with ViewState. DropDownList, ListBox, DataGrid, and
DataList suffer from poor performance because of their size and the large amounts
of data making roundtrips to the server.
Chapter 2: Understanding Caching Technologies 33
In some situations, using view state is not recommended because it can degrade
performance. For example:
G
Avoid using view state in pages that do not post back to the server, such as logon
pages.
G
Avoid using view state for large data items, such as DataSets, because doing so
increases time in roundtrips to the server.
G
Avoid using view state when session timeout is required because you cannot time
out data stored in the ViewState property.
View state is a simple and easy-to-use implementation of hidden fields that provides
some security features. Most of the performance considerations, benefits, and
limitations of view state and hidden fields are similar.
For more information about ViewState performance, see Maintaining State in a
Control in the MSDN Library.
Benefits and Limitations of View State
The benefits of using view state include:
G
No server resources are required because state is contained in a structure in the
page code.
G
It is simple to implement.
G
Pages and control state are automatically retained.
G
The values in view state are hashed, compressed, and encoded, thus representing
a higher state of security than hidden fields.
G
View state is good for caching data in Web farm configurations because the data
is cached on the client.
Limitations to using view state include:
G
Page loading and posting performance decreases when large values are stored
because view state is stored in the page.
G
Although view state stores data in a hashed format, it can still be tampered with
because it is stored in a hidden field on the page. The information in the hidden
field can also be seen if the page output source is viewed directly, creating a
potential security risk.
For more information about using view state, see Saving Web Forms Page Values
Using View State, in the MSDN Library.
Caching Architecture Guide for .NET Framework Applications 34
Implementing View State
The following example shows how to use the ViewState property to store and access
user-specific information between page postbacks.
public class ViewStateSample : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsPostBack)
{
// Save some data in the ViewState property.
this.ViewState["EnterTime"] = DateTime.Now.ToString();
this.ViewState["UserName"] = "John Smith";
this.ViewState["Country"] = "USA";
}
}
#region Web Form Designer generated code
#endregion
private void btnRefresh_Click(object sender, System.EventArgs e)
{
// Get the saved data in the view state and display it.
this.lblTime.Text = this.ViewState["EnterTime"].ToString();
this.lblUserName.Text = this.ViewState["UserName"].ToString();
this.lblCountry.Text = this.ViewState["Country"].ToString();
}
}
When your application runs on a low bandwidth client for example, a mobile
device you can store the view state on the server by using Losformatter and
thereby returning slimmer pages with less of a security risk.
Using Hidden Frames
You can use hidden frames to cache data on the client, avoiding the roundtrips to
the server that are inherent in hidden field and view state implementations. You
create a hidden frame in your page that loads a Web page into the frame containing
your data. The pages in your application can access this data using client-side
scripting. This implementation does not require any server resources because the
data fields in the hidden frame are stored and read directly from the page.
Hidden frames let you secretly load images for use on other pages within the site.
When those images are required, they can be obtained from the client cache rather
than from the server.
Chapter 2: Understanding Caching Technologies 35
Benefits and Limitations of Hidden Frames
The benefits of using hidden frames to store client-side state include:
G
The ability to cache more than one data field.
G
The avoidance of roundtrips of data during postbacks.
G
The ability to cache and access data items stored in different hidden forms.
G
The ability to access JScript variable values stored in different frames if they
come from the same site.
The limitations of using hidden frames are:
G
Functionality of hidden frames is not supported by all browsers. Do not rely on
hidden frames to provide data for the essential functionality of your pages.
G
The hidden frame can be tampered with, and the information in the page can be
seen if the page output source is viewed directly, creating a potential security
threat.
G
There is no limit to the number of frames (embedded or not) that you can hide. In
frames that bring data from the database and that contain several Java applets or
images, a large number of frames can negatively affect performance of the first
page load.
Hidden frames are useful for storing many items of data and resolve some of the
performance issues inherent in hidden field implementations.
Implementing Hidden Frames
The following example shows how to declare a hidden frame in a Web page.
<FRAMESET cols="100%,*">
<FRAMESET rows="100%,*">
<FRAME src="contents_of_frame1.html">
</FRAMESET>
<FRAME src="contents_of_hidden_frame.html">
<FRAME src="contents_of_hidden_frame.html" frameborder="0" noresize
scrolling="yes">
<NOFRAMES>
<P>This frameset document contains:
<UL>
<LI>
<A href="contents_of_frame1.html" TARGET="_top">
Some neat contents</A>
<LI>
<A href="contents_of_hidden_frame.html" TARGET="_top">
Some other neat contents</A>
</UL>
</NOFRAMES>
</FRAMESET>
You can then use the data stored in this frame in your Web page by using client-side
scripting.
Caching Architecture Guide for .NET Framework Applications 36
Using Cookies
You can use cookies to store small amounts of infrequently changing information on
the client. That information can then be included in a request to the server.
Benefits and Limitations of Cookies
Cookies are useful because:
G
No server resources are required. The cookie is stored on the client, sent to the
server in a request, and then read by the server after the post.
G
They are simple to use. The cookie is a lightweight, text-based structure contain-
ing simple key/value pairs.
G
They support configurable expiration. The cookie can expire when the browser
session ends, or it can exist indefinitely on the client computer, subject to the
expiration rules on the client.
The use of cookies may be limited by:
G
Size restrictions. Most browsers place a 4096-byte limit on the size of a cookie,
although support for 8192-byte cookies is becoming more common in the new
browser and client-device versions available today.
G
User-configured refusal. Some users disable their browser or client devices
ability to receive cookies, thereby limiting the use of cookies.
G
Security breaches. Cookies can be subject to tampering. Users can manipulate
cookies on their computer, which can potentially represent a security compromise
or cause a cookie-dependent application to fail.
G
Possible expirations. The durability of the cookie on a client computer is subject
to cookie expiration processes on the client and to user intervention.
Note: Cookies are often used for personalization, in which content is customized for a known
user. In most cases, identification is the issue rather than authentication, so it is usually
enough to merely store the user name, account name, or a unique user ID (such as a GUID) in
a cookie and use it to access the user personalization infrastructure of a site.
For more information about creating and reading cookies, see
HttpResponse.Cookies Property and HttpRequest.Cookies Property, in the
MSDN Library.
Implementing Cookies
The following example shows how to store and retrieve information that cookies
hold.
Chapter 2: Understanding Caching Technologies 37
public class CookiesSample : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
if (this.Request.Cookies["preferences1"] == null)
{
HttpCookie cookie = new HttpCookie("preferences1");
cookie.Values.Add("ForeColor","black");
cookie.Values.Add("BackColor","beige");
cookie.Values.Add("FontSize","8pt");
cookie.Values.Add("FontName","Verdana");
this.Response.AppendCookie(cookie);
}
}
private string getStyle(string key)
{
string val = null;
HttpCookie cookie= this.Request.Cookies["preferences1"];
if (cookie != null)
{
val = cookie.Values[key];
}
return val;
}
}
Never rely on cookies for essential functionality in your Web applications, because
users can disable them in their browsers.
Using Query Strings
A query string is information sent to the server appended to the end of a pages
URL. You can use a query string to submit data back to your page or to another page
through the URL.
Query strings provide a simple but limited way of maintaining some types of state
information. For example, they make it easy to pass information from one page to
another, such as passing a product number to another page, where it is processed.
Note: Query strings are a viable option only when a page is requested through its URL using
HTTP GET. You cannot read a query string from a page that has been submitted to the server
using HTTP POST.
Caching Architecture Guide for .NET Framework Applications 38
Benefits and Limitations of Query Strings
Query strings offer the following benefits:
G
No server resources are required. The query string is contained in the HTTP
request for a specific URL.
G
They provide broad support. Almost all browsers and client devices support
passing values in a query string.
G
They are simple to implement. ASP.NET provides full support for the query
string method, including methods for reading query strings using the
HttpRequest.Params property.
Query strings do have some limitations; for example:
G
The information in the query string is directly visible to the user in the browser
user interface. The query values are exposed to the Internet in the URL, so in
some cases, security might be an issue.
G
Most browsers and client devices impose a 255-character limit on URL length.
Query strings can be very useful in certain circumstances, such as when you are
passing parameters to the server to customize the formatting of the data returned.
Implementing Query Strings
The following example shows how to include a query string in a URL.
http://www.cache.com/login.asp?user=ronen
The following example shows how to access the information at the server.
// Check for a query string in a request.
string user = Request.QueryString["User"];
if( user != null )
{
// Do something with the user name.
}
Query strings enable you to send string information directly from the client to the
server for server-side processing.
Using Client-Side Caching Technologies
Table 2.4 shows recommendations for the use of each client-side caching technology
discussed.
Chapter 2: Understanding Caching Technologies 39
Table 2.4: Client-side state technologies
Mechanism Recommended uses
Hidden fields To store small amounts of information for a page that posts back to itself or to
another page when security is not an issue. You can use a hidden field only on
pages that are submitted to the server.
View state To store small amounts of information for a page that posts back to itself.
Using view state provides basic security.
Hidden frames To cache data items on the client and to avoid the roundtrips of the data to the
server.
Cookies To store small amounts of information on the client when security is not an
issue.
Query strings To transfer small amounts of information from one page to another when
security is not an issue. You can use query strings only if you are requesting
the same page or another page using a link.
Using Internet Explorer Caching
Microsoft Internet Explorer provides mechanisms for caching pages or page objects
on the users computer. In Internet Explorer, you can cache data on the client rather
than on the server, thus reducing server and network load to a minimum.
Internet Explorer caching is not suitable for all situations. In this section, you learn
how to best utilize Internet Explorer caching in your applications.
Note: Internet Explorer caching is supported only in an Internet Explorer client environment. If
other client browsers are also being used, you must use customization code in your application
and provide an alternative caching solution for other types of browser.
Understanding Internet Explorer Cache Types
You can store information in the Internet Explorer cache either by specifying a time
that the page should expire from the cache or by using dynamic HTML (DHTML)
behaviors:
G
You can add an EXPIRES directive to the header of objects so that Internet
Explorer caches them for the specified time period. When the browser needs to
access this data, the expiration date is queried, and if the date is in the future, the
cached version of the data is used. If the expiration date has passed, the browser
contacts the server for the current version of the data. As a result, any sites that
use the EXPIRES header perform better.
Caching Architecture Guide for .NET Framework Applications 40
G
You can use persistence through DHTML behaviors that allow you to store
information on the client. Doing so reduces the need to query a server database
for client-specific information, such as color settings or screen layout preferences,
and increases the overall performance of the page. Persistence stores the data
hierarchically, making it easier for the Web developer to access.
Note: Users can choose to work offline by selecting Work Offline on the File menu in Internet
Explorer. When Work Offline is selected, the system enters a global offline state independent
of any current network connection, and content is read exclusively from the cache.
Another method of making Internet Explorer cache pages is by manually setting the
page expiration by using the Web pagefile properties in IIS. The site administrator
can perform this operation.