Caching Web Pages

In this lesson, we will learn how to control response caching.

Responses returned by Web servers can be cached in various places during their path to their target client applications. They can be cached in various Internet intermediary nodes, and in the browser cache itself.

HTTP standard headers control the way a response must be cached and when it can be cached. ASP.NET Core supports Web response caching through the ResponseCacheAttribute action filter that manipulates the HTTP headers that affect response caching. It also allows response caching on the Web server itself.

In the sections below, we will describe the HTTP caching headers, how to use the ResponseCacheAttribute action filter, and how to cache responses on the server.

HTTP cache headers

The main HTTP header that affects response caching is Cache-Control which can assume several commas separated values. The table below describes all allowed values:

Cache-Control value Effect Example
public The response is not specific for a single user so, it can be stored in the browser and on all intermediary nodes. public
private The response is specific for a single user so, it can be stored in the browser and in intermediary nodes that serve that specific user (usually just in the browser). private
max-age The number of seconds the cache is considered valid. When this time expires the cached response is not accepted by the client and validation is asked to the server, which, in turn, can respond that the cached content is still valid or can provide a fresher response. public, max-age=80
no-cache The response can be cached but must be validated by the original server before being used. Therefore, a request to the server is issued anyway, to ask it if the cache is expired. no-cache
no-store Response must not be cached. no-store

It is worth mentioning when max-age expires with no-cache, cache records continue to be stored. However, the server must confirm they are still valid. So the request must be transmitted to the server. Usually, the server answers with a new response that overrides all cached results.

Usually, servers also issue the Pragma: no-cache header together with Cache-Control: no-cache for retro compatibility with old specifications. However, the Pragma header is now obsolete.

It is also possible to specify an absolute date+time after which the cache is no more valid with the Expires header, as shown below:

Expires: Wed, 10 Mar 2021 07:28:00 GMT

The Vary header is also important. It contains a comma-separated list of HTTP headers. A different cache entry is created for each combination of the listed header values, as shown below:

Vary: accept-encoding, accept-language

It is worth pointing out that GET ASP.NET Core requests with different routes or query string parameters are cached in different entries since their URLs are different. Therefore, the cache must be refreshed only when a response to the same parameters changes.

Moreover, by default, ASP.NET Core only allows caching for GET requests, as it assumes that the response to other verbs depends on the body content. Thus we should only worry about GET requests caching.

The ResponseCacheAttribute action filter

The ResponseCacheAttribute action filter can be used to configure all cache-related headers of an action method response. It can be applied both to the controller and to each action method. The action method configuration overrides the controller configuration.

It has a Location property where ResponseCacheLocation.Any, and ResponseCacheLocation.Client values map respectively to the public and private Cache-Control values.

The Duration property maps to the max-age Cache-Control value.

The Vary property maps directly to the Vary header value.

Finally, when the NoStore property is set, the no-store value is added to the Cache-Control header. While, when the Location property is set to ResponseCacheLocation.None the no-cache value is added to the Cache-Control header.

The example below allows caching of 3 minutes on both the browser and any intermediate node:

Get hands-on with 1200+ tech skills courses.