ASP.NET Caching
by Wei-Meng Lee12/30/2002
Caching is an important concept in computing. When applied to ASP.NET, it can greatly enhance the performance of your Web applications. In this article, I will discuss some of the techniques for caching ASP.NET pages on the server side.
Output Caching
Output caching caches the output of a page (or portions of it) so that a page's content need not be generated every time it is loaded.
Consider the following page where a user logs in to a site and reads the latest news. The page will display the user's name and retrieve the latest news since he last logged in.
![]() |
| Figure 1: Displaying the latest news |
In a typical ASP.NET page, every time the user views the page, the Web server will have to dynamically generate the content of the page and perform the relevant database queries (which is a very expensive task to do).
Considering the fact that the page does not change for a certain period of time, it is always a good idea to cache whatever is non-static so that the page can be loaded quickly.
Let's add a new OutputCache page directive to the ASP.NET page:
<%@ OutputCache Duration="15" VaryByParam="*" %>
<%@ Page Language="vb" AutoEventWireup="false"
Codebehind="WebForm1.aspx.vb" Inherits="Caching.WebForm1"%>
The OutputCache directive specifies the various criteria for caching the page.
In this case, the page will be cached for 15 seconds. This means that if the
page is loaded and within the next 15 seconds it is refreshed, the Web server
will serve the same content without needing to dynamically regenerate the page.
This can be verified by the time displayed on the page.
|
Related Reading Programming ASP .NET |
The VaryByParam attribute specifies how the caching should be performed, based
on the query string supplied to the page. For example, if I used the following
URL:
http://localhost/Caching/WebForm1.aspx?name=John&newsid=12
The query string passed to the page is name=John&newsid=12. So now, if I
change the VaryByParam attribute to:
<%@ OutputCache Duration="15" VaryByParam="Name" %>
The page will be cached according to the Name key. This means that if I issue
the following two URLs, the second page will still be from the cache, as the
cache will only be refreshed if the Name value changes:
http://localhost/Caching/WebForm1.aspx?name=John&newsid=12
http://localhost/Caching/WebForm1.aspx?name=John&newsid=45
The following URLs will cause the second page to be refreshed:
http://localhost/Caching/WebForm1.aspx?name=John&newsid=12
http://localhost/Caching/WebForm1.aspx?name=Michael&newsid=12
If you want to cause the page to be regenerated if the Name and NewsID keys
change, then you simply add the NewsID key into the VaryByParam attribute:
<%@ OutputCache Duration="15" VaryByParam="Name;NewsID" %>
In this case, this is equivalent to using a "*", which means all keys will
cause the page to be regenerated:
<%@ OutputCache Duration="15" VaryByParam="*" %>
If you want to cache the page regardless of query string, you can use the
value "none":
<%@ OutputCache Duration="15" VaryByParam="none" %>
Caching Objects in a Page
While output caching is useful, a much more powerful and flexible application would be to cache individual objects in your Web application.
For example, I have a Web application that retrieves news from a SQL Server
database and displays the news titles in a ComboBox. As users are expected to
read the news by selecting the title from the ComboBox, I want to minimize the
number of times that the application connects to SQL Server for retrieving the
news content. So I cache the DataSet containing the news.
![]() |
| Figure 2: Caching the DataSet containing the news |
The first time the page is loaded, the user has to click on the Get News button to get the news from the SQL Server:
Private Sub Button1_Click(ByVal sender As _
System.Object, _
ByVal e As System.EventArgs)_
Handles Button1.Click
Dim ds As DataSet
ds = loadData()
Dim i As Integer
DropDownList1.Items.Clear()
For i = 0 To ds.Tables("News").Rows.Count - 1
Dim item As New _
ListItem(ds.Tables("News").Rows(i).Item(2).ToString,_
ds.Tables("News").Rows(i).Item(0).ToString)
DropDownList1.Items.Add(item)
Next
End Sub
This calls the loadData() method, which loads the data from SQL server and then
displays the data in the ComboBox.
Public Function loadData() As DataSet
Dim ds As New DataSet
If Cache("News") Is Nothing Then
Dim sql As String = "SELECT * FROM NewsHeader"
Dim conn As New SqlConnection ( _
"server=localhost; uid=sa;" & _
" password=; database=News")
Dim comm As New SqlCommand(sql, conn)
Dim dataAdapter As New SqlDataAdapter(comm)
dataAdapter.Fill(ds, "News")
Cache("News") = ds
Else
ds = CType(Cache("News"), DataSet)
End If
Return ds
End Function
Note that I use a Cache object to see if it already contains a copy of the
DataSet (which contains the news). If it doesn't (Is Nothing), I will retrieve
it from the SQL Server and then store it using the Cache object, using the key
"News". Subsequent requests to the loadData() method will load the data from the cached DataSet.
When the user selects a new title from the ComboBox, the news content is retrieved from cache:
Private Sub DropDownList1_SelectedIndexChanged(ByVal _
sender As System.Object, _
ByVal e As System.EventArgs) Handles _
DropDownList1.SelectedIndexChanged
Dim index As Integer = _
DropDownList1.SelectedIndex()
Dim ds As DataSet
ds = CType(Cache("News"), DataSet)
If ds Is Nothing Then
ds = loadData()
End If
Label3.Text = _
ds.Tables("News").Rows(index).Item(1).ToString()
Label1.Text = _
ds.Tables("News").Rows(index).Item(3).ToString()
End Sub
Note that you have to perform a type conversion using the CType() method.
Using this method, I can reduce the number of connections I have to make to SQL
Server. This will improve the performance of my Web application.
What happens if there are new items in the database and you need to display them? You need to explicitly clear the cache via the Clear Cache button:
Private Sub Button2_Click(ByVal sender As _
System.Object, ByVal e As _
System.EventArgs) Handles Button2.Click
Cache.Remove("News")
End Sub
Smart Caching with Dependencies
The caching technique described in the last section is useful but not brilliant. You don't expect the reader to know when to clear the cache. A better way would be to design the cache to automatically refresh itself when some external events happen. Let me extend the example.
Suppose our application loads a text file containing the header (that changes daily) for the day's news:
![]() |
| Figure 3: Displaying the header |
Assuming that the news changes daily, so it is logical that whenever the
header changes, the data in the cache should be refreshed as well. So there is
a dependence on the header.txt file. To express the cache's dependency on the
file, use the System.Web.Caching.CacheDependency class.
Hence, rewriting my loadData() method:
Public Function loadData() As DataSet
Dim ds As New DataSet
Dim header As String
Dim file As New _
System.IO.StreamReader(Server.MapPath("header.txt"))
header = file.ReadLine
file.Close()
lblHeader.Text = header
If Cache("News") Is Nothing Then
Dim sql As String = "SELECT * FROM NewsHeader"
Dim conn As New _
SqlConnection("server=localhost; " & _
"uid=sa; password=; database=News")
Dim comm As New SqlCommand(sql, conn)
Dim dataAdapter As New SqlDataAdapter(comm)
dataAdapter.Fill(ds, "News")
Dim depends As New _
System.Web.Caching.CacheDependency _
(Server.MapPath("Header.txt"))
Cache.Insert("News", ds, depends)
Else
ds = CType(Cache("News"), DataSet)
End If
Return ds
End Function
Notice that I have used the insert() method of the Cache class to insert the
DataSet and file dependency:
Cache.Insert("News", ds, depends)
From now on, if the content of the header.txt file is changed, the content in the cache would be cleared.
Time-Based Caching
Another technique for caching is based on time. For example, the cache can expire on a certain date, or it will only be available for a certain period of time. There are two ways in which you can use time-based caching:
- Absolute Expiration. The cache is set to expire on a particular date and time.
- Sliding Expiration. The cache is set to expire after a certain period of inactivity.
For example, if you have:
'===Absolute expiration===
Cache.Insert("News", ds, Nothing, _
DateTime.Now.AddMinutes(2), _
Cache.NoSlidingExpiration)
The cache is set to expire exactly two minutes after the user has retrieved the data.
For sliding expiration, you can use:
'===Sliding expiration===
Cache.Insert("News", ds, Nothing, _
Cache.NoAbsoluteExpiration, _
TimeSpan.FromMinutes(1))
This will cause the cache to be cleared if the user does not reload the page within one minute. If the user reloads the page within the one-minute time frame, the data in the cache will be valid for another minute.
Use Caching Sparingly
As in life, anything that is good comes with a price. Enabling caching in ASP.NET causes the cache content to be stored in the Web server's memory. Caching takes up valuable system resources and can easily eat up all of your available memory.
When server memory runs out, the contents of your cache will be evicted. The criteria for cache eviction is based on priority, which you can optionally set when adding data to your cache:
Cache.Insert("News", ds, Nothing, _
Cache.NoAbsoluteExpiration, _
TimeSpan.FromMinutes(1), _
System.Web.Caching.CacheItemPriority.High, _
Nothing)
There are seven levels of priority:
NotRemovable, High, AboveNormal, Default, Normal, BelowNormal, and Low.
Conclusion
Caching of Web pages is an effective way of increasing performance while minimizing the use of precious server resources. Choosing the appropriate level for caching data is important for balancing caching versus memory usage. One of the most effective strategies to good Web application performance is to cache data only when necessary.
Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.
Return to ONDotnet.com
Showing messages 1 through 17 of 17.
-
Limitations of ASP.NET
2010-03-29 03:41:14 wesnur [View]
-
Caching problem
2009-12-23 13:51:35 Francisco Goldenstein [View]
Hi! I'm from Argentina and I'm facing a problem that I could solve but I'm not sure if I did it in the best way. I was caching page that has a Master Page and the user was able to change de currency (dollar, euro, etc.). Depending on the selected currency, the page should display prices in the desired currency (price converted from original currency to selected currency). The problem is that after changing the selected currency, prices are not updated because they are cached. The selected currency is being saved in a session variable and after debugging the web application I can assure you that it was OK. How did i solve this issue? I added a "VaryByParam=currency" option to my cache directive and now I have to send the currency parameter in every page that shows prices. I guess that this is not the best solution and that's why I'm posting this message. I hope to read from you soon. Thanks in advance.
-
Simple question
2009-01-17 15:43:05 cdenby [View]
Just now looking into caching as a possible solution for some of my controls.
The biggest question is regarding sessions. Are objects stored in the cache shared across sessions from different clients? Or are they similar to session.add()?
-
cache retrieval order
2008-10-31 19:58:28 Ulfius [View]
I notice that you have two methods of retrieving and checking for items from the cache. One is the correct method and one could result in unexpected behavior.
The correct method is the code -
ds = CType(Cache("News"), DataSet)
If ds Is Nothing Then
ds = loadData()
End If
The incorrect method is -
If Cache("News") Is Nothing Then
...
Cache.Insert("News", ds, depends)
Else
ds = CType(Cache("News"), DataSet)
End If
The reason you should do the assigment first, then check for nothing is that it is possible (albeit unlikely) that the cached item could expire inbetween the checking = nothing and the assignment to the variable.
-
Thank you
2008-09-10 03:14:07 Madhu Raykar [View]
Thank-you for such helpful explanation. :)
-
Thank-you
2008-05-09 12:29:41 donkur [View]
Thank-you for such helpful code. :)
-
Set cache to expire at the end of the day
2005-02-16 14:40:51 programmer.new [View]
How do I set the cache to expire at say, 11:59 pm? I would like to do that within the Cache.Insert statement in a C# web app.
Any ideas are welcome 'coz I have hit a wall.
Thanks. -
how to use query strings in asp.net
2007-04-04 04:26:05 browser111 [View]
tell me how to use parameters in output caching in asp.net
-
Set cache to expire at the end of the day
2005-05-10 23:16:58 Weidong.Sun [View]
You can build a caching with a dependence on a text file and creat a task to modify the text file
11:59 pm.
-
Dont want to use Sessions
2005-02-02 01:51:17 sinister [View]
Hi .. i have a problem i am developing a site and i cannot use cookies or sessions and yet i have to track user state ... is caching a good option? does it have any limitations?.. do i have to make a seperate cache for every user?.. need some help here.. ASAP
Regards
-
how to cache a table from the SQL database??
2003-12-20 00:09:30 anonymous2 [View]
hi
i am trying to cache a the contents of a table located in the SQL database usng the .NET framework. how can i go about it?? -
how to cache a table from the SQL database??
2006-06-19 06:58:57 goutam123 [View]
i try it now to solve
-
Excellent
2003-08-07 08:34:47 anonymous2 [View]
Excellent
-
how about caching a web service?
2003-02-10 23:08:05 anonymous2 [View]
This is simple ASP.NET caching???
What about caching strategies in a web service
and a SQL table?
-
anoynymous
2003-01-27 21:46:38 anonymous2 [View]
This is about as good an introduction to asp.net caching as it comes. Thank You, for sharing your knowledge for free. God Bless!














Thanks for then post!!!!! There is no doubt that ASP.NET cache is a good tool for performance of the app. But it is my personal experience that it is good for small web farms only. Once you apply it for larger web farms, you may face some serious scalability issues. So I would suggest reading the limitations of ASP.NET cache (http://www.alachisoft.com/ncache/asp-net-cache.html) for further the understanding.