ASP.NET provides a Cache class within the Application scope to let you cache frequently used application data and reduce expensive trips to the database. However, ASP.NET Cache is an in-process and stand-alone cache and therefore has many limitations and problems.
ASP.NET Cache Deployment Limitations:
Since ASP.NET Cache is always in-process, it creates many limitations and problems. None of these problems occur if you use NCache in your ASP.NET application. Here is a list of problems and limitations.
ASP.NET allows you to use the SqlCacheDependency class to create a cache item dependency on a table or row in a database. When a change occurs in that table or specific row, the item in the cache that has this dependency is invalidated and removed from the cache. With SQL Server 2000, you can only create a table level dependency but SQL Server 2005 allows you to also create a row level dependency.
Although, SqlCacheDependency tries to address the severe scalability limitations in ASP.NET Cache mentioned above, it is unable to completely resolve these problems. Here are the problems associated with SqlCacheDependency:
ASP.NET Cache Deployment Limitations:
Since ASP.NET Cache is always in-process, it creates many limitations and problems. None of these problems occur if you use NCache in your ASP.NET application. Here is a list of problems and limitations.
- Data Integrity Problem in Web : A web garden is configured on a web server by specifying multiple worker processes for an application pool. However, in this situation, ASP.NET creates multiple isolated instances of the Cache class, one for each worker process. And, the Cache in each worker process is not synchronized with other worker processes thereby creating data integrity problem.
- Data Loss with Worker Process Recycling: ASP.NET always runs in worker processes and these worker processes recycle by default. Once a process recycles, the entire Cache is lost because it was within this process. This can lead to serious problems if you don't have a backup storage of the cached data. At the minimum, it is a performance issue because you now have to reload the entire cache.
- Cache Size Limitation: An in-process Cache is limited by how much a single process can store. Most ASP.NET applications these days run on 32-bit platforms and therefore there is a 2GB or 3GB memory size limit which has to be shared between the Cache and your ASP.NET application. Although on a 64-bit platform this limit goes away, process recycling becomes an even more serious performance issue since the cache is now much larger and has to be reloaded at runtime.
- Single Point of Failure: The entire Cache is stored on a single server and therefore is lost if this server goes down for any reason.
- Data Integrity Problem in Web Farms: A web farm consists of multiple web servers connected together through a load balancer. The load balancer routes user requests to all web servers thereby distributing the load evenly. In a web farm configuration, each web server creates its own isolated copies of ASP.NET Cache that is not synchronized with other web servers. This creates data integrity problems.
- Scalability Problem in Web Farms: The ideal way to distribute load evenly in a web farm is for the load balancer to send each request to the most appropriate web server based on the load on all web servers. However, since ASP.NET Cache is stand-alone and in-process, the load balancer has to send the request to the same web server where the user was originally serviced. This severely limits scalability because you end up with situations where some of the servers are extremely overloaded and slow while others are free and adding more servers doesn't increase the total processing throughput.
ASP.NET allows you to use the SqlCacheDependency class to create a cache item dependency on a table or row in a database. When a change occurs in that table or specific row, the item in the cache that has this dependency is invalidated and removed from the cache. With SQL Server 2000, you can only create a table level dependency but SQL Server 2005 allows you to also create a row level dependency.
Although, SqlCacheDependency tries to address the severe scalability limitations in ASP.NET Cache mentioned above, it is unable to completely resolve these problems. Here are the problems associated with SqlCacheDependency:
- Performance Issue: The whole idea behind the cache is to reduce expensive database trips. However, SqlCacheDependency is stored in the database and therefore causes major performance degradation. Every time your ASP.NET application adds, updates, or removes anything from the cache, the same information is updated once in the application database and secondly in the SqlCacheDependency database. It is then propagated from the databases to all the other Cache instances, whether in a web garden or in a web farm configuration. This makes cache updates extremely slow.
- Scalability Issue: Database server is not able to scale out as your server farm grows. You may be able to build an active-active cluster of your database but even this cannot grow beyond 2-3 database servers without giving major performance degradation. In addition, this type of a configuration is extremely expensive. Hence, as your server farm grows, if you're using SqlCacheDependency, you'll see a major drop in performance.
The main benefits of caching are performance-related operations like accessing database information can be one of the most expensive operations of an ASP page's life cycle. If the database information is fairly static, this database-information can be cached.
Here we look at many of the Cache methods you can use in ASP.NET code-behind and other code files. These methods and properties are used to control the HTTP cache settings on your ASP.NET response. They must be called on the HttpResponse object, using the Response.Cache...() style syntax.
::Method name & It's usage::
AddValidationCallback: You will need this when using callbacks, which I have no experience with.
AppendCacheExtension: You can use this to add a custom header to the Cache-Control header, which could be used for future changes in HTTP 1.1 or proprietary options.
SetAllowResponseInBrowserHistory: This overrides certain settings made by SetCacheability, such as NoCache and ServerAndNoCache.
SetCacheability: This is important and sets the Cache-Control header, which is the preferred mechanism for caching dynamic pages. See the list of HttpCacheability enums below.
SetETag: This allows you to specify a string that is considered the 'tag' of a resource. This is not recommended by Yahoo and not normally needed.
SetETagFromFileDependencies: Tells ASP.NET to assign random etags to your resources that are keyed to the file contents. Simplifies ETag usage. Not normally needed.
SetExpires: Very important and useful for static resources such as logo images or web site layout images. Recommended by Yahoo for static resources.
SetLastModified: This can be used to date your file and return a 304 when a user requests the same one again. This doesn't save an HTTP request. Yahoo recommends modified dates over ETags.
SetLastModifiedFromFileDependencies: Same as above but tells ASP.NET to read in the file metadata automatically.
SetMaxAge: Very important. This gives you a relative time window you can specify a resource can be cached for. This is an alternative to the Expires header, and it overrides the Expires header.
SetNoServerCaching: This seems to remove the HttpCacheability.Server setting. It seems like a really poor design in ASP.NET.
SetNoStore: Applies the "Cache-Control: no-store" header. This is useful for advertisements and dynamic responses.
SetNoTransforms: Some proxy caches can change the format of your files when they store them. This setting should tell them not to.
SetOmitVaryStar: Changes header when using vary parameters. Not often useful.
SetProxyMaxAge: Not likely to be useful. It suggests that proxy caches can expire or keep resources for a specific time. I doubt they would honor this exactly.
SetRevalidation: Indicates when validation should occur. See Cache-Control header section.
SetSlidingExpiration: Changes the logic of when the server expires its cache. Has many quirks and you must test it carefully.
SetValidUntilExpires: Don't listen to browsers when they say a resource is expired or stale. Otherwise, they can invalidate caches.
SetVaryByCustom: Allows you to set the custom vary header, which is useful when you have the Vary header. See section on Vary.
VaryByContentEncodings,VaryByHeaders,VaryByParams: These are public getters only, meaning you cannot set these properties. They are useful for debugging and diagnostics of your Vary header.
HttpCacheability enumeration values in ASP.Net
You need to call SetCacheability on the Response.Cache to set the main Cache-Control header. This header controls the location and general behavior of the cache. You need to combine this setting with other Cache class method calls to achieve many behaviors. However, these enums define the general setting.
::Enum value & It's usage::
HttpCacheability.NoCache: Tells the browser, the server, and proxies to never cache this resource. This can be useful for advertisements and resources that are always changing.
HttpCacheability.Private: Only cache on the browser. This will provide bandwidth savings for your users, but your server won't store a cached copy of the output. This is adequate for many sites.
HttpCacheability.Public: The ultimate cache setting: tells the server to save the page, proxy caches to save the page, and the browser to save the page.
HttpCacheability.Server: Only cache the page on the server (output caching without browser caching). However, when your visitors click on your static pages, they will be reloaded.
HttpCacheability.ServerAndNoCache: The same as NoCache except it allows the server to store the page. Has slightly different meaning for remote clients and proxies. Not often useful.
HttpCacheability.ServerAndPrivate: Tells proxy caches to never cache this page, but to allow the browser and the server to cache it.
Here we look at many of the Cache methods you can use in ASP.NET code-behind and other code files. These methods and properties are used to control the HTTP cache settings on your ASP.NET response. They must be called on the HttpResponse object, using the Response.Cache...() style syntax.
::Method name & It's usage::
AddValidationCallback: You will need this when using callbacks, which I have no experience with.
AppendCacheExtension: You can use this to add a custom header to the Cache-Control header, which could be used for future changes in HTTP 1.1 or proprietary options.
SetAllowResponseInBrowserHistory: This overrides certain settings made by SetCacheability, such as NoCache and ServerAndNoCache.
SetCacheability: This is important and sets the Cache-Control header, which is the preferred mechanism for caching dynamic pages. See the list of HttpCacheability enums below.
SetETag: This allows you to specify a string that is considered the 'tag' of a resource. This is not recommended by Yahoo and not normally needed.
SetETagFromFileDependencies: Tells ASP.NET to assign random etags to your resources that are keyed to the file contents. Simplifies ETag usage. Not normally needed.
SetExpires: Very important and useful for static resources such as logo images or web site layout images. Recommended by Yahoo for static resources.
SetLastModified: This can be used to date your file and return a 304 when a user requests the same one again. This doesn't save an HTTP request. Yahoo recommends modified dates over ETags.
SetLastModifiedFromFileDependencies: Same as above but tells ASP.NET to read in the file metadata automatically.
SetMaxAge: Very important. This gives you a relative time window you can specify a resource can be cached for. This is an alternative to the Expires header, and it overrides the Expires header.
SetNoServerCaching: This seems to remove the HttpCacheability.Server setting. It seems like a really poor design in ASP.NET.
SetNoStore: Applies the "Cache-Control: no-store" header. This is useful for advertisements and dynamic responses.
SetNoTransforms: Some proxy caches can change the format of your files when they store them. This setting should tell them not to.
SetOmitVaryStar: Changes header when using vary parameters. Not often useful.
SetProxyMaxAge: Not likely to be useful. It suggests that proxy caches can expire or keep resources for a specific time. I doubt they would honor this exactly.
SetRevalidation: Indicates when validation should occur. See Cache-Control header section.
SetSlidingExpiration: Changes the logic of when the server expires its cache. Has many quirks and you must test it carefully.
SetValidUntilExpires: Don't listen to browsers when they say a resource is expired or stale. Otherwise, they can invalidate caches.
SetVaryByCustom: Allows you to set the custom vary header, which is useful when you have the Vary header. See section on Vary.
VaryByContentEncodings,VaryByHeaders,VaryByParams: These are public getters only, meaning you cannot set these properties. They are useful for debugging and diagnostics of your Vary header.
HttpCacheability enumeration values in ASP.Net
You need to call SetCacheability on the Response.Cache to set the main Cache-Control header. This header controls the location and general behavior of the cache. You need to combine this setting with other Cache class method calls to achieve many behaviors. However, these enums define the general setting.
::Enum value & It's usage::
HttpCacheability.NoCache: Tells the browser, the server, and proxies to never cache this resource. This can be useful for advertisements and resources that are always changing.
HttpCacheability.Private: Only cache on the browser. This will provide bandwidth savings for your users, but your server won't store a cached copy of the output. This is adequate for many sites.
HttpCacheability.Public: The ultimate cache setting: tells the server to save the page, proxy caches to save the page, and the browser to save the page.
HttpCacheability.Server: Only cache the page on the server (output caching without browser caching). However, when your visitors click on your static pages, they will be reloaded.
HttpCacheability.ServerAndNoCache: The same as NoCache except it allows the server to store the page. Has slightly different meaning for remote clients and proxies. Not often useful.
HttpCacheability.ServerAndPrivate: Tells proxy caches to never cache this page, but to allow the browser and the server to cache it.
ASP.NET provides easier methods to control caching. You can use the @ OutputCache directive to control page output caching in ASP.NET. Use the HttpCachePolicy class to store arbitrary objects, such as datasets, to server memory. You can store the cache in applications such as the client browser, the proxy server, and Microsoft Internet Information Services (IIS). By using the Cache-Control HTTP Header, you can control caching.
Cache ASP.NET pages
Use the @ OutputCache directive to cache, or you can cache programmatically through code by using Visual Basic .NET or Visual C# .NET. The @ OutputCache directive contains a Location attribute. This attribute determines the location for cached item. You can specify the following locations:
1.To store the output cache for a specified duration
Declarative Approach:
<%@ OutputCache Duration="60" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
2.To store the output cache on the browser client where the request originated
Declarative Approach:
<%@ OutputCache Duration="60" Location="Client" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Private);
3.To store the output cache on any HTTP 1.1 cache-capable devices including the proxy servers and the client that made request
Declarative Approach:
<%@ OutputCache Duration="60" Location="Downstream" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetNoServerCaching();
4.To store the output cache on the Web server
Declarative Approach:
<%@ OutputCache Duration="60" Location="Server" VaryByParam="None" %>
Programmatic Approach:
TimeSpan _timespan = new TimeSpan(0,0,0,60);
DateTime now = DateTime.Now;
Response.Cache.SetExpires(now.Add(_timespan));
Response.Cache.SetMaxAge(_timespan);
Response.Cache.SetCacheability(HttpCacheability.Server);
Response.Cache.SetValidUntilExpires(true);
5.To cache the output for each HTTP request that arrives with a different EmpID:
Declarative Approach:
<%@ OutputCache duration="60" varybyparam="EmpID" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.VaryByParams["EmpID"] = true;
For the VaryByCustom attribute, the VaryByHeader attribute, and the VaryByParam attribute in the @ OutputCache directive, the HttpCachePolicy class provides the VaryByHeaders property and the VaryByParams property, and the SetVaryByCustom method.
Turn off client and proxy caching
To turn off the output cache for an ASP.NET Web page at the client location and at the proxy location, set the Location attribute value to none, and then set the VaryByParam value to none in the @ OutputCache directive. Use the following code samples to turn off client and proxy caching.
Declarative Approach:
<%@ OutputCache Location="None" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Cache arbitrary objects in server memory
ASP.NET includes a powerful, easy-to-use caching mechanism that you can use to store objects that require a lot of server resources to create in memory. The Cache class implements this method. Instances are private to each application and the lifetime is tied to the corresponding application. To cache the arbitrary objects in ASP.Net by using the Cache class:
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<script language="C#" runat="server">
void Page_Load(Object Src, EventArgs E) {
DataView Source;
// Retrieve the DataView object from Cache. If not exist, then add DataView object to the Cache.
Source = (DataView)Cache["MyDataSet"];
if (Source == null) {
SqlConnection myConnection = new SqlConnection("Server=ServerName; database=MyDB; user id=UID; password=PWD;");
SqlDataAdapter myCommand = new SqlDataAdapter("select * from Employee", myConnection);
DataSet ds = new DataSet();
myCommand.Fill(ds, "Employee");
Source = new DataView(ds.Tables["Employee"]);
Cache["MyDataSet"] = Source;
MsgCache.Text = "Dataset created explicitly";
}
else {
MsgCache.Text = "Dataset retrieved from cache";
}
// Binding the DataView object with DataGrid.
TestDataGrid.DataSource=Source;
TestDataGrid.DataBind();
}
</script>
<body>
<form method="GET" runat="server">
<h3><font face="Arial">Caching Data</font></h3>
<ASP:DataGrid id="TestDataGrid" runat="server"
Width="700"
BackColor="#ccccff"
BorderColor="blue"
ShowFooter="false"
CellPadding=3
CellSpacing="0"
Font-Name="arial"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaad" />
<p>
<i><asp:label id="MsgCache" runat="server"/></i>
</form>
</body>
</html>
Cache ASP.NET pages
Use the @ OutputCache directive to cache, or you can cache programmatically through code by using Visual Basic .NET or Visual C# .NET. The @ OutputCache directive contains a Location attribute. This attribute determines the location for cached item. You can specify the following locations:
- Any - This stores the output cache in the client's browser, on the proxy server that participates in the request, or on the server where the request is processed. By default, Any is selected.
- Client - This stores output cache in the client's browser.
- Downstream - This stores the output cache in any cache-capable devices that participate in the request.
- Server - This stores the output cache on the Web server.
- None - This turns off the output cache.
1.To store the output cache for a specified duration
Declarative Approach:
<%@ OutputCache Duration="60" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
2.To store the output cache on the browser client where the request originated
Declarative Approach:
<%@ OutputCache Duration="60" Location="Client" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Private);
3.To store the output cache on any HTTP 1.1 cache-capable devices including the proxy servers and the client that made request
Declarative Approach:
<%@ OutputCache Duration="60" Location="Downstream" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetNoServerCaching();
4.To store the output cache on the Web server
Declarative Approach:
<%@ OutputCache Duration="60" Location="Server" VaryByParam="None" %>
Programmatic Approach:
TimeSpan _timespan = new TimeSpan(0,0,0,60);
DateTime now = DateTime.Now;
Response.Cache.SetExpires(now.Add(_timespan));
Response.Cache.SetMaxAge(_timespan);
Response.Cache.SetCacheability(HttpCacheability.Server);
Response.Cache.SetValidUntilExpires(true);
5.To cache the output for each HTTP request that arrives with a different EmpID:
Declarative Approach:
<%@ OutputCache duration="60" varybyparam="EmpID" %>
Programmatic Approach:
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.VaryByParams["EmpID"] = true;
For the VaryByCustom attribute, the VaryByHeader attribute, and the VaryByParam attribute in the @ OutputCache directive, the HttpCachePolicy class provides the VaryByHeaders property and the VaryByParams property, and the SetVaryByCustom method.
Turn off client and proxy caching
To turn off the output cache for an ASP.NET Web page at the client location and at the proxy location, set the Location attribute value to none, and then set the VaryByParam value to none in the @ OutputCache directive. Use the following code samples to turn off client and proxy caching.
Declarative Approach:
<%@ OutputCache Location="None" VaryByParam="None" %>
Programmatic Approach:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Cache arbitrary objects in server memory
ASP.NET includes a powerful, easy-to-use caching mechanism that you can use to store objects that require a lot of server resources to create in memory. The Cache class implements this method. Instances are private to each application and the lifetime is tied to the corresponding application. To cache the arbitrary objects in ASP.Net by using the Cache class:
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<script language="C#" runat="server">
void Page_Load(Object Src, EventArgs E) {
DataView Source;
// Retrieve the DataView object from Cache. If not exist, then add DataView object to the Cache.
Source = (DataView)Cache["MyDataSet"];
if (Source == null) {
SqlConnection myConnection = new SqlConnection("Server=ServerName; database=MyDB; user id=UID; password=PWD;");
SqlDataAdapter myCommand = new SqlDataAdapter("select * from Employee", myConnection);
DataSet ds = new DataSet();
myCommand.Fill(ds, "Employee");
Source = new DataView(ds.Tables["Employee"]);
Cache["MyDataSet"] = Source;
MsgCache.Text = "Dataset created explicitly";
}
else {
MsgCache.Text = "Dataset retrieved from cache";
}
// Binding the DataView object with DataGrid.
TestDataGrid.DataSource=Source;
TestDataGrid.DataBind();
}
</script>
<body>
<form method="GET" runat="server">
<h3><font face="Arial">Caching Data</font></h3>
<ASP:DataGrid id="TestDataGrid" runat="server"
Width="700"
BackColor="#ccccff"
BorderColor="blue"
ShowFooter="false"
CellPadding=3
CellSpacing="0"
Font-Name="arial"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaad" />
<p>
<i><asp:label id="MsgCache" runat="server"/></i>
</form>
</body>
</html>