Training
Module
Improve performance with a cache in a .NET Aspire project - Training
In this module, you'll learn about caches in a .NET Aspire cloud-native app and how to use them to optimize the performance of your microservices.
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
By John Luo and Rick Anderson
This article explains how to configure Response Caching Middleware in an ASP.NET Core app. The middleware determines when responses are cacheable, stores responses, and serves responses from cache. For an introduction to HTTP caching and the [ResponseCache]
attribute, see Response Caching.
The Response caching middleware:
To test response caching, use Fiddler, or another tool that can explicitly set request headers. Setting headers explicitly is preferred for testing caching. For more information, see Troubleshooting.
In Program.cs
, add the Response Caching Middleware services AddResponseCaching to the service collection and configure the app to use the middleware with the UseResponseCaching extension method. UseResponseCaching
adds the middleware to the request processing pipeline:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseHttpsRedirection();
// UseCors must be called before UseResponseCaching
//app.UseCors();
app.UseResponseCaching();
Warning
UseCors must be called before UseResponseCaching when using CORS middleware.
The sample app adds headers to control caching on subsequent requests:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseHttpsRedirection();
// UseCors must be called before UseResponseCaching
//app.UseCors();
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next();
});
app.MapGet("/", () => DateTime.Now.Millisecond);
app.Run();
The preceding headers are not written to the response and are overridden when a controller, action, or Razor Page:
Response Caching Middleware only caches server responses that result in a 200 (OK) status code. Any other responses, including error pages, are ignored by the middleware.
Warning
Responses containing content for authenticated clients must be marked as not cacheable to prevent the middleware from storing and serving those responses. See Conditions for caching for details on how the middleware determines if a response is cacheable.
The preceding code typically doesn't return a cached value to a browser. Use Fiddler or another tool that can explicitly set request headers and is preferred for testing caching. For more information, see Troubleshooting in this article.
Response caching options are shown in the following table.
Option | Description |
---|---|
MaximumBodySize | The largest cacheable size for the response body in bytes. The default value is 64 * 1024 * 1024 (64 MB). |
SizeLimit | The size limit for the response cache middleware in bytes. The default value is 100 * 1024 * 1024 (100 MB). |
UseCaseSensitivePaths | Determines if responses are cached on case-sensitive paths. The default value is false . |
The following example configures the middleware to:
/page1
and /Page1
are stored separately.var builder = WebApplication.CreateBuilder(args);
builder.Services.AddResponseCaching(options =>
{
options.MaximumBodySize = 1024;
options.UseCaseSensitivePaths = true;
});
var app = builder.Build();
app.UseHttpsRedirection();
// UseCors must be called before UseResponseCaching
//app.UseCors();
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next(context);
});
app.MapGet("/", () => DateTime.Now.Millisecond);
app.Run();
When using MVC, web API controllers, or Razor Pages page models, the [ResponseCache]
attribute specifies the parameters necessary for setting the appropriate headers for response caching. The only parameter of the [ResponseCache]
attribute that strictly requires the middleware is VaryByQueryKeys, which doesn't correspond to an actual HTTP header. For more information, see Response caching in ASP.NET Core.
When not using the [ResponseCache]
attribute, response caching can be varied with VaryByQueryKeys
. Use the ResponseCachingFeature directly from the HttpContext.Features:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
if (responseCachingFeature != null)
{
responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
Using a single value equal to *
in VaryByQueryKeys
varies the cache by all request query parameters.
The following table provides information on HTTP headers that affect response caching.
Header | Details |
---|---|
Authorization |
The response isn't cached if the header exists. |
Cache-Control |
The middleware only considers caching responses marked with the public cache directive. Control caching with the following parameters:
max-stale , the middleware takes no action.‡ proxy-revalidate has the same effect as must-revalidate .For more information, see RFC 9111: Request Directives. |
Pragma |
A Pragma: no-cache header in the request produces the same effect as Cache-Control: no-cache . This header is overridden by the relevant directives in the Cache-Control header, if present. Considered for backward compatibility with HTTP/1.0. |
Set-Cookie |
The response isn't cached if the header exists. Any middleware in the request processing pipeline that sets one or more cookies prevents the Response Caching Middleware from caching the response (for example, the cookie-based TempData provider). |
Vary |
The Vary header is used to vary the cached response by another header. For example, cache responses by encoding by including the Vary: Accept-Encoding header, which caches responses for requests with headers Accept-Encoding: gzip and Accept-Encoding: text/plain separately. A response with a header value of * is never stored. |
Expires |
A response deemed stale by this header isn't stored or retrieved unless overridden by other Cache-Control headers. |
If-None-Match |
The full response is served from cache if the value isn't * and the ETag of the response doesn't match any of the values provided. Otherwise, a 304 (Not Modified) response is served. |
If-Modified-Since |
If the If-None-Match header isn't present, a full response is served from cache if the cached response date is newer than the value provided. Otherwise, a 304 - Not Modified response is served. |
Date |
When serving from cache, the Date header is set by the middleware if it wasn't provided on the original response. |
Content-Length |
When serving from cache, the Content-Length header is set by the middleware if it wasn't provided on the original response. |
Age |
The Age header sent in the original response is ignored. The middleware computes a new value when serving a cached response. |
The middleware respects the rules of RFC 9111: HTTP Caching (Section 5.2. Cache-Control). The rules require a cache to honor a valid Cache-Control
header sent by the client. Under the specification, a client can make requests with a no-cache
header value and force the server to generate a new response for every request. Currently, there's no developer control over this caching behavior when using the middleware because the middleware adheres to the official caching specification.
For more control over caching behavior, explore other caching features of ASP.NET Core. See the following topics:
The Response Caching Middleware uses IMemoryCache, which has a limited capacity. When the capacity is exceeded, the memory cache is compacted.
If caching behavior isn't as expected, confirm that responses are cacheable and capable of being served from the cache. Examine the request's incoming headers and the response's outgoing headers. Enable logging to help with debugging.
When testing and troubleshooting caching behavior, a browser typically sets request headers that prevent caching. For example, a browser may set the Cache-Control
header to no-cache
or max-age=0
when refreshing a page. Fiddler and other tools can explicitly set request headers and are preferred for testing caching.
Authorization
header must not be present.Cache-Control
header parameters must be valid, and the response must be marked public
and not marked private
.Pragma: no-cache
header must not be present if the Cache-Control
header isn't present, as the Cache-Control
header overrides the Pragma
header when present.Set-Cookie
header must not be present.Vary
header parameters must be valid and not equal to *
.Content-Length
header value (if set) must match the size of the response body.Expires
header and the max-age
and s-maxage
cache directives.no-store
directive must not exist in request or response header fields. See RFC 9111: HTTP Caching (Section 3: Storing Responses in Caches for details.Note
The Antiforgery system for generating secure tokens to prevent Cross-Site Request Forgery (CSRF) attacks sets the Cache-Control
and Pragma
headers to no-cache
so that responses aren't cached. For information on how to disable antiforgery tokens for HTML form elements, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core.
IResponseCachingPolicyProvider
IResponseCachingPolicyProvider
This article explains how to configure Response Caching Middleware in an ASP.NET Core app. The middleware determines when responses are cacheable, stores responses, and serves responses from cache. For an introduction to HTTP caching and the [ResponseCache]
attribute, see Response Caching.
View or download sample code (how to download)
Response Caching Middleware is implicitly available for ASP.NET Core apps via the shared framework.
In Startup.ConfigureServices
, add the Response Caching Middleware to the service collection:
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
services.AddRazorPages();
}
Configure the app to use the middleware with the UseResponseCaching extension method, which adds the middleware to the request processing pipeline in Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
// UseCors must be called before UseResponseCaching
// app.UseCors("myAllowSpecificOrigins");
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Warning
UseCors must be called before UseResponseCaching when using CORS middleware.
The sample app adds headers to control caching on subsequent requests:
// using Microsoft.AspNetCore.Http;
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new string[] { "Accept-Encoding" };
await next();
});
The preceding headers are not written to the response and are overridden when a controller, action, or Razor Page:
Response Caching Middleware only caches server responses that result in a 200 (OK) status code. Any other responses, including error pages, are ignored by the middleware.
Warning
Responses containing content for authenticated clients must be marked as not cacheable to prevent the middleware from storing and serving those responses. See Conditions for caching for details on how the middleware determines if a response is cacheable.
Response caching options are shown in the following table.
Option | Description |
---|---|
MaximumBodySize | The largest cacheable size for the response body in bytes. The default value is 64 * 1024 * 1024 (64 MB). |
SizeLimit | The size limit for the response cache middleware in bytes. The default value is 100 * 1024 * 1024 (100 MB). |
UseCaseSensitivePaths | Determines if responses are cached on case-sensitive paths. The default value is false . |
The following example configures the middleware to:
/page1
and /Page1
are stored separately.services.AddResponseCaching(options =>
{
options.MaximumBodySize = 1024;
options.UseCaseSensitivePaths = true;
});
When using MVC / web API controllers or Razor Pages page models, the [ResponseCache]
attribute specifies the parameters necessary for setting the appropriate headers for response caching. The only parameter of the [ResponseCache]
attribute that strictly requires the middleware is VaryByQueryKeys, which doesn't correspond to an actual HTTP header. For more information, see Response caching in ASP.NET Core.
When not using the [ResponseCache]
attribute, response caching can be varied with VaryByQueryKeys
. Use the ResponseCachingFeature directly from the HttpContext.Features:
var responseCachingFeature = context.HttpContext.Features.Get<IResponseCachingFeature>();
if (responseCachingFeature != null)
{
responseCachingFeature.VaryByQueryKeys = new[] { "MyKey" };
}
Using a single value equal to *
in VaryByQueryKeys
varies the cache by all request query parameters.
The following table provides information on HTTP headers that affect response caching.
Header | Details |
---|---|
Authorization |
The response isn't cached if the header exists. |
Cache-Control |
The middleware only considers caching responses marked with the public cache directive. Control caching with the following parameters:
max-stale , the middleware takes no action.‡ proxy-revalidate has the same effect as must-revalidate .For more information, see RFC 9111: Request Directives. |
Pragma |
A Pragma: no-cache header in the request produces the same effect as Cache-Control: no-cache . This header is overridden by the relevant directives in the Cache-Control header, if present. Considered for backward compatibility with HTTP/1.0. |
Set-Cookie |
The response isn't cached if the header exists. Any middleware in the request processing pipeline that sets one or more cookies prevents the Response Caching Middleware from caching the response (for example, the cookie-based TempData provider). |
Vary |
The Vary header is used to vary the cached response by another header. For example, cache responses by encoding by including the Vary: Accept-Encoding header, which caches responses for requests with headers Accept-Encoding: gzip and Accept-Encoding: text/plain separately. A response with a header value of * is never stored. |
Expires |
A response deemed stale by this header isn't stored or retrieved unless overridden by other Cache-Control headers. |
If-None-Match |
The full response is served from cache if the value isn't * and the ETag of the response doesn't match any of the values provided. Otherwise, a 304 (Not Modified) response is served. |
If-Modified-Since |
If the If-None-Match header isn't present, a full response is served from cache if the cached response date is newer than the value provided. Otherwise, a 304 - Not Modified response is served. |
Date |
When serving from cache, the Date header is set by the middleware if it wasn't provided on the original response. |
Content-Length |
When serving from cache, the Content-Length header is set by the middleware if it wasn't provided on the original response. |
Age |
The Age header sent in the original response is ignored. The middleware computes a new value when serving a cached response. |
The middleware respects the rules of RFC 9111: HTTP Caching (Section 5.2. Cache-Control). The rules require a cache to honor a valid Cache-Control
header sent by the client. Under the specification, a client can make requests with a no-cache
header value and force the server to generate a new response for every request. Currently, there's no developer control over this caching behavior when using the middleware because the middleware adheres to the official caching specification.
For more control over caching behavior, explore other caching features of ASP.NET Core. See the following topics:
If caching behavior isn't as expected, confirm that responses are cacheable and capable of being served from the cache. Examine the request's incoming headers and the response's outgoing headers. Enable logging to help with debugging.
When testing and troubleshooting caching behavior, a browser may set request headers that affect caching in undesirable ways. For example, a browser may set the Cache-Control
header to no-cache
or max-age=0
when refreshing a page. The following tools can explicitly set request headers and are preferred for testing caching:
Startup.Configure
, Response Caching Middleware must be placed before middleware that require caching. For more information, see ASP.NET Core Middleware.Authorization
header must not be present.Cache-Control
header parameters must be valid, and the response must be marked public
and not marked private
.Pragma: no-cache
header must not be present if the Cache-Control
header isn't present, as the Cache-Control
header overrides the Pragma
header when present.Set-Cookie
header must not be present.Vary
header parameters must be valid and not equal to *
.Content-Length
header value (if set) must match the size of the response body.Expires
header and the max-age
and s-maxage
cache directives.no-store
directive must not exist in request or response header fields. See RFC 9111: HTTP Caching (Section 3: Storing Responses in Caches for details.Note
The Antiforgery system for generating secure tokens to prevent Cross-Site Request Forgery (CSRF) attacks sets the Cache-Control
and Pragma
headers to no-cache
so that responses aren't cached. For information on how to disable antiforgery tokens for HTML form elements, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core.
ASP.NET Core feedback
ASP.NET Core is an open source project. Select a link to provide feedback:
Training
Module
Improve performance with a cache in a .NET Aspire project - Training
In this module, you'll learn about caches in a .NET Aspire cloud-native app and how to use them to optimize the performance of your microservices.