Caching

.

Caching

"Use <Ctrl><F5> to perform a hard reload of a web page without any cached files."


Web page by Kevin Harris of Homer IL

Please contact Kevin Harris of Homer IL concerning this web site

Caching is a strategy to improve performance by storing data which is time-consuming to obtain, or construct, into memory for subsequent retrievals. There are different methods for implementing caching and different places where caching can be employed. The different methods and places each have ramifications on ease of implementation and performance gain. Determining when to cache data, and what data to cache, is an important factor for Internet applications. Highly volatile data may need to be obtained fresh each time. Some data should never be cached for security reasons. Caching is extremely important to the functioning of the modern Internet. Some say the modern high-speed Internet would not be possible without caching.

Caching can be performed on both the client side and the server side. On the client side each browser is responsible for caching data on a per user basis. The different types of browsers do not share cached data with each other and they each employ their own methods for when and how to cache data. Browsers take caching direction from the server by following the cache directives in the response headers. Entire pages, or just components of the page, can be cached. It is common to cache images that are part of a web page. Also only defined areas of a web page can be cached in the Donut caching strategy. ASP.NET contains three methods for server side caching:

  1. Page Level Output Caching - rendered pages are cached. Cached versions can vary by parameter values or dependencies on files or database tables.

  2. Data Source Control Caching - caches data stored in data source controls, typically retrieved from a database.

  3. Application Caching - uses a Cache object accessible within programs. Working with the Caching object is similar to working with User Session objects. However Caching objects were designed to store application scoped network-expensive data such at results from database queries or complex data which was computationally-expensive to obtain.

Common pitfalls with using cached data is using stale (out-of-date) data or assuming an item is in cache when it is not. To avoid stale data, caches are invalidated (i.e. the item is removed from cache). Invalidation can be tied to a specified time or upon a change to some dependency such as the change to a database table. Cache items should always be checked for null before using because .NET may automatically remove cached items. .NET will removed cached items in situations such as when the server is running low on memory. Also changes to the Web.config file can cause the worker processes to recycle losing any cached items.

Page Level Output Caching

Page Level Output Caching stores the end result of a rendered page in cache. Output Caching consists of a default HTTP Module in the ASP.NET pipeline. With Output Caching enabled, the first time the page is requested it is processed through the pipeline in a normal fashion. However on subsequent requests the HTTP module intercepts the request and jumps around the remaining steps in the pipeline (i.e. it skips other HTTP modules, compiling, rendering) and simply returns the HTML created from the first request. So, on subsequent calls, the page is not processed on the server ... no server code in the page is executed ... and the cached rendered HTML from the first request is simply returned to the client. The amount of performance gain by using the cached page depends upon the complexity of the page, but typically 90+ percent increase in performance is realized.

To enable Output Caching in web forms, you specify the OutputCache page directive.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<%@ OutputCache Duration="#ofseconds"
   Location="Any | Client | Downstream | Server | None | 
     ServerAndClient "
   Shared="True | False"
   VaryByControl="controlname"
   VaryByCustom="browser | customstring"
   VaryByHeader="headers"
   VaryByParam="parametername" 
   CacheProfile="cache profile name | ''"
   NoStore="true | false"
   SqlDependency="database/table name pair | CommandNotification"
%>

The "Duration" parameter is the absolution expiration time of the cached pages specified in seconds. The "VaryByParam" parameter specifies how to make versions of the the cached page. If "None" is specified only a single version of the page is stored in cache. Versions of the cached page can be varied by any of the query string values (Get) or fields within the form (Post).

1
<%@ OutputCache Duration="60" VaryByParam="none" %>


Cache Directive Creates One Version of the Page and Stores in Cache for 60 Seconds (Web Forms)

1
<%@ OutputCache Duration="10" VaryByParam="location;count" %>


Cache Directive Creates a Version for Each Combination of the "location" and "count" Form Parameters (Post)


To enable Output Caching in MVC, you specify an Action Filter in the controller.

1
[OutputCache(Duration=60)]


Creates One Version of the Page and Stores in Cache for 60 Seconds (MVC)

OutputCaching Profiles can be set up in the Web.config file and reused for various pages. Caching profiles also allow the caching parameters at run time.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<outputCacheSettings>
   <outputCacheProfiles>
      <add name="ShortTime"
           duration="30"
           varyByParam="none"
           location="Server"/>
      <add name="LongTime"
           duration="86400"
           varyByParam="none"
           location="Server"/>
   </outputCacheProfiles>
</outputCacheSettings>


Cache Profile Set Up in Web.config

1
<%@ OutputCache CacheProfile="LongLived" %>


Using a Cache Profile (Web Forms)

1
[OutputCache(CacheProfile="LongLived"]


Using a Cache Profile (MVC)

Fragment Caching

Some pages contain only portions of a page which should be cached, such as a grid view. Other portions of the page then vary by user, such as having different themes for different users. Or a portion of the page may contain secure information, such as a Login control. You would not want to send a cached page with someone else's theme or Login control. For those situations you can move the Output Caching to the user control level. This technique is called Fragment Caching, which causes portions of the page to be rendered on every request, with other portions of the page pulled from cache.

Custom Cache Providers

Starting with ASP.NET 4 you are able to specify your own OutputCacheProvider in Web.config as a plug-in module. The custom cache module needs to inherit from the OutputCacheProvider module. The primary benefit of a custom cache provider is the ability to cache objects outside of the ASP.NET worker process.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<configuration>
   <system.web>
      <compilation debug="true" targetFramework="4.0"/>
      <caching>
         <outputCache defaultProvider="CustomOutputCache">
            <providers>
               <add name="CacheProviderName" type="CacheProviderCategory"/>
            </providers>
         </outputCache>
      </caching>
   </system.web>
</configuration>


Specifying a Custom Cache Provider in Web.config

Page Output Cache Example

The MVC program fragment below uses Output Caching on an .aspx page. When the page is repeatedly refreshed, the time does not change until 60 seconds has elapsed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using System.Web.Mvc;

namespace MvcApp1.Controllers
{
    public class HomeController : Controller
    {
        [OutputCache(Duration=60, VaryByParam="none")]
        public ActionResult Index()
        {
            return View();
        }

    }
}


OuputCache Action Filter on Action Method in Controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
    
    The current time is: <%= DateTime.Now.ToString("T") %>
    
    </div>
</body>
</html>


View showing the Current Time


Data Source Control Caching

Data source controls were introduced in ASP.NET 2.0. The purpose of data source controls is to provide a consistent representation of data to data-bound controls regardless of the source of the data. Data source controls have no user interface nor do they render any HTML. Data source controls perform data-binding to server controls (e.g. GridView, TreeView, ListView, DetailsView, FormView, Repeater, Chart). The data source controls are named after they type of data with which they interface, and include:

  1. SqlDataSource Control - provides data-bound server control access to data stored in a relational database.
  2. XmlDataSource Control - provides data-bound server control access to XML data.
  3. ObjectDataSource Control - provides data-bound server control access to an application object.
  4. LinqDataSource Control - enables you to use LINQ in order to retrieve and modify data for a data-bound server control.
  5. EntityDataSource Control - provides data-bound server control access to data based on an entity data model.

Data source controls do not have caching enabled by default. Caching is enabled by setting the control's EnableCaching property to true. Cached data is refreshed based on the number of seconds specified in the CacheDuration property.

In ASP.NET, Data Source Controls allo is used in Web Forms to provide data services to data-bound contols (e.g. GridViews).
Caching is not enabledData Source Control Caching

Programmatic Caching

Cache setting can be set and queried in program code by using the Response.Cache property.

1
2
3
4
5
6
7
8
9
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(false);
Response.Cache.VaryByParams["Category"] = true;

if (Response.Cache.VaryByParams["Category"])
{
}


Coding with Response.Cache