12 KiB
title | author | description | keywords | ms.author | manager | ms.date | ms.topic | ms.assetid | ms.prod | uid |
---|---|---|---|---|---|---|---|---|---|---|
Response caching in ASP.NET Core | rick-anderson | Learn how to use response caching to lower bandwidth and increase performance. | ASP.NET Core,Response caching,HTTP headers | riande | wpickett | 09/20/2017 | article | cb42035a-60b0-472e-a614-cb79f443f654 | asp.net-core | performance/caching/response |
Response caching in ASP.NET Core
By John Luo, Rick Anderson, Steve Smith, and Luke Latham
View or download sample code (how to download)
Response caching reduces the number of requests a client or proxy makes to a web server. Response caching also reduces the amount of work the web server performs to generate a response. Response caching is controlled by headers that specify how you want client, proxy, and middleware to cache responses.
The web server can cache responses when you add Response Caching Middleware.
HTTP-based response caching
The HTTP 1.1 Caching specification describes how Internet caches should behave. The primary HTTP header used for caching is Cache-Control, which is used to specify cache directives. The directives control caching behavior as requests make their way from clients to servers and as reponses make their way from servers back to clients. Requests and responses move through proxy servers, and proxy servers must also conform to the HTTP 1.1 Caching specification.
Common Cache-Control
directives are shown in the following table.
Directive | Action |
---|---|
public | A cache may store the response. |
private | The response must not be stored by a shared cache. A private cache may store and reuse the response. |
max-age | The client won't accept a response whose age is greater than the specified number of seconds. Examples: max-age=60 (60 seconds), max-age=2592000 (1 month) |
no-cache | On requests: A cache must not use a stored response to satisfy the request. Note: The origin server re-generates the response for the client, and the middleware updates the stored response in its cache. On responses: The response must not be used for a subsequent request without validation on the origin server. |
no-store | On requests: A cache must not store the request. On responses: A cache must not store any part of the response. |
Other cache headers that play a role in caching are shown in the following table.
Header | Function |
---|---|
Age | An estimate of the amount of time in seconds since the response was generated or successfully validated at the origin server. |
Expires | The date/time after which the response is considered stale. |
Pragma | Exists for backwards compatibility with HTTP/1.0 caches for setting no-cache behavior. If the Cache-Control header is present, the Pragma header is ignored. |
Vary | Specifies that a cached response must not be sent unless all of the Vary header fields match in both the cached response's original request and the new request. |
HTTP-based caching respects request Cache-Control directives
The HTTP 1.1 Caching specification for the Cache-Control header requires a cache to honor a valid Cache-Control
header sent by the client. A client can make requests with a no-cache
header value and force the server to generate a new response for every request.
Always honoring client Cache-Control
request headers makes sense if you consider the goal of HTTP caching. Under the official specification, caching is meant to reduce the latency and network overhead of satisfying requests across a network of clients, proxies, and servers. It isn't necessarily a way to control the load on an origin server.
There's no current developer control over this caching behavior when using the Response Caching Middleware because the middleware adheres to the official caching specification. Future enhancements to the middleware will permit configuring the middleware to ignore a request's Cache-Control
header when deciding to serve a cached response. This will offer you an opportunity to better control the load on your server when you use the middleware.
Other caching technology in ASP.NET Core
In-memory caching
In-memory caching uses server memory to store cached data. This type of caching is suitable for a single server or multiple servers using sticky sessions. Sticky sessions means that the requests from a client are always routed to the same server for processing.
For more information, see Introduction to in-memory caching in ASP.NET Core.
Distributed Cache
Use a distributed cache to store data in memory when the app is hosted in a cloud or server farm. The cache is shared across the servers that process requests. A client can submit a request that is handled by any server in the group and cached data for the client is available. ASP.NET Core offers SQL Server and Redis distributed caches.
For more information, see Working with a distributed cache.
Cache Tag Helper
You can cache the content from an MVC view or Razor Page with the Cache Tag Helper. The Cache Tag Helper uses in-memory caching to store data.
For more information, see Cache Tag Helper in ASP.NET Core MVC.
Distributed Cache Tag Helper
You can cache the content from an MVC view or Razor Page in distributed cloud or web farm scenarios with the Distributed Cache Tag Helper. The Distributed Cache Tag Helper uses SQL Server or Redis to store data.
For more information, see Distributed Cache Tag Helper.
ResponseCache attribute
The ResponseCacheAttribute
specifies the parameters necessary for setting appropriate headers in response caching. See ResponseCacheAttribute for a description of the parameters.
[!WARNING] Disable caching for content that contains information for authenticated clients. Caching should only be enabled for content that doesn't change based on a user's identity or whether a user is logged in.
VaryByQueryKeys string[]
(requires ASP.NET Core 1.1 and higher): When set, the Response Caching Middleware varies the stored response by the values of the given list of query keys. The Response Caching Middleware must be enabled to set the VaryByQueryKeys
property; otherwise, a runtime exception is thrown. There's no corresponding HTTP header for the VaryByQueryKeys
property. This property is an HTTP feature handled by the Response Caching Middleware. For the middleware to serve a cached response, the query string and query string value must match a previous request. For example, consider the sequence of requests and results shown in the following table.
Request | Result |
---|---|
http://example.com?key1=value1 |
Returned from server |
http://example.com?key1=value1 |
Returned from middleware |
http://example.com?key1=value2 |
Returned from server |
The first request is returned by the server and cached in middleware. The second request is returned by middleware because the query string matches the previous request. The third request is not in the middleware cache because the query string value doesn't match a previous request.
The ResponseCacheAttribute
is used to configure and create (via IFilterFactory
) a ResponseCacheFilter
. The ResponseCacheFilter
performs the work of updating the appropriate HTTP headers and features of the response. The filter:
- Removes any existing headers for
Vary
,Cache-Control
, andPragma
. - Writes out the appropriate headers based on the properties set in the
ResponseCacheAttribute
. - Updates the response caching HTTP feature if
VaryByQueryKeys
is set.
Vary
This header is only written when the VaryByHeader
property is set. It's set to the Vary
property's value. The following sample uses the VaryByHeader
property:
[!code-csharpMain]
You can view the response headers with your browser's network tools. The following image shows the Edge F12 output on the Network tab when the About2
action method is refreshed:
NoStore and Location.None
NoStore
overrides most of the other properties. When this property is set to true
, the Cache-Control
header is set to no-store
. If Location
is set to None
:
Cache-Control
is set tono-store,no-cache
.Pragma
is set tono-cache
.
If NoStore
is false
and Location
is None
, Cache-Control
and Pragma
are set to no-cache
.
You typically set NoStore
to true
on error pages. For example:
[!code-csharpMain]
This results in the following headers:
Cache-Control: no-store,no-cache
Pragma: no-cache
Location and Duration
To enable caching, Duration
must be set to a positive value and Location
must be either Any
(the default) or Client
. In this case, the Cache-Control
header is set to the location value followed by the max-age
of the response.
[!NOTE]
Location
's options ofAny
andClient
translate intoCache-Control
header values ofpublic
andprivate
, respectively. As noted previously, settingLocation
toNone
sets bothCache-Control
andPragma
headers tono-cache
.
Below is an example showing the headers produced by setting Duration
and leaving the default Location
value:
[!code-csharpMain]
This produces the following header:
Cache-Control: public,max-age=60
Cache profiles
Instead of duplicating ResponseCache
settings on many controller action attributes, cache profiles can be configured as options when setting up MVC in the ConfigureServices
method in Startup
. Values found in a referenced cache profile are used as the defaults by the ResponseCache
attribute and are overridden by any properties specified on the attribute.
Setting up a cache profile:
[!code-csharpMain]
Referencing a cache profile:
[!code-csharpMain]
The ResponseCache
attribute can be applied both to actions (methods) and controllers (classes). Method-level attributes override the settings specified in class-level attributes.
In the above example, a class-level attribute specifies a duration of 30 seconds, while a method-level attribute references a cache profile with a duration set to 60 seconds.
The resulting header:
Cache-Control: public,max-age=60