From 6f648ecc9e54bbcd54ab2b55b59331bdfa3adce2 Mon Sep 17 00:00:00 2001 From: "Beth-Anne Harvey (AQUENT LLC)" <28070425+GitHubber17@users.noreply.github.com> Date: Thu, 30 Apr 2026 23:05:22 -0700 Subject: [PATCH 1/2] refresh content --- aspnetcore/includes/response-caching-mid.md | 16 +- aspnetcore/performance/caching/distributed.md | 231 +++++++++--------- .../caching/hybrid/includes/overview.md | 28 +-- aspnetcore/performance/caching/memory.md | 159 ++++++------ aspnetcore/performance/caching/output.md | 118 ++++----- aspnetcore/performance/caching/overview.md | 44 ++-- aspnetcore/performance/caching/response.md | 107 ++++---- 7 files changed, 374 insertions(+), 329 deletions(-) diff --git a/aspnetcore/includes/response-caching-mid.md b/aspnetcore/includes/response-caching-mid.md index 21e45d51a0d0..37cc8a8086d6 100644 --- a/aspnetcore/includes/response-caching-mid.md +++ b/aspnetcore/includes/response-caching-mid.md @@ -1,7 +1,13 @@ -The Response caching middleware: +The response caching middleware enables the caching of server responses based on [HTTP Cache-Control headers](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Cache-Control). -* Enables caching server responses based on [HTTP cache headers](https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control). Implements the standard HTTP caching semantics. Caches based on HTTP cache headers like proxies do. -* Is typically not beneficial for UI apps such as Razor Pages because browsers generally set request headers that prevent caching. [Output caching](xref:performance/caching/output), which is available in .NET 7 or later, benefits UI apps. With output caching, configuration decides what should be cached independently of HTTP headers. -* May be beneficial for public GET or HEAD API requests from clients where the [Conditions for caching](xref:performance/caching/middleware#cfc) are met. +* Caching behavior implements standard HTTP caching semantics. -To test response caching, use [Fiddler](https://www.telerik.com/fiddler), or another tool that can explicitly set request headers. Setting headers explicitly is preferred for testing caching. For more information, see [Troubleshooting](xref:performance/caching/middleware#troubleshooting). +* Caching is based on HTTP cache headers similar to the method used by proxies. + +* This form of caching is useful for public GET or HEAD API requests from clients where the [conditions for caching](xref:performance/caching/middleware#cfc) are satisfied. + +* For UI apps like Razor Pages, response caching isn't typically beneficial. Browsers commonly set request headers that prevent caching. + + [Output caching](xref:performance/caching/output) (available in .NET 7 and later) is a better approach for UI apps. In this scenario, the configuration determines what to cache independent of HTTP headers. + +To test response caching, use [Fiddler](https://www.telerik.com/fiddler) or another tool that can explicitly set request headers. Setting headers explicitly is preferred for testing caching. For more information, see [Response caching middleware > Troubleshooting](xref:performance/caching/middleware#troubleshooting). \ No newline at end of file diff --git a/aspnetcore/performance/caching/distributed.md b/aspnetcore/performance/caching/distributed.md index 98c339e1c77c..cb4dd1447f0b 100644 --- a/aspnetcore/performance/caching/distributed.md +++ b/aspnetcore/performance/caching/distributed.md @@ -5,9 +5,11 @@ description: Learn how to use an ASP.NET Core distributed cache to improve app p monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc -ms.date: 01/29/2024 +ms.date: 05/01/2026 uid: performance/caching/distributed ms.sfi.ropc: t + +# customer intent: As an ASP.NET developer, I want to use an ASP.NET Core distributed cache, so I can improve app performance and scalability. --- # Distributed caching in ASP.NET Core @@ -17,7 +19,7 @@ By [Mohsin Nasir](https://github.com/mohsinnasir) and [smandia](https://github.c :::moniker range=">= aspnetcore-8.0" -A distributed cache is a cache shared by multiple app servers, typically maintained as an external service to the app servers that access it. A distributed cache can improve the performance and scalability of an ASP.NET Core app, especially when the app is hosted by a cloud service or a server farm. +A distributed cache is a cache shared by multiple app servers. The cache is typically maintained as an external service for the app servers that access it. A distributed cache can improve the performance and scalability of an ASP.NET Core app, especially when a cloud service or a server farm hosts the app. A distributed cache has several advantages over other caching scenarios where cached data is stored on individual app servers. @@ -27,7 +29,7 @@ When cached data is distributed, the data: * Survives server restarts and app deployments. * Doesn't use local memory. -Distributed cache configuration is implementation specific. This article describes how to configure SQL Server, Redis, or Postgres distributed caches. Third party implementations are also available, such as [NCache](http://www.alachisoft.com/ncache/aspnet-core-idistributedcache-ncache.html) ([NCache on GitHub](https://github.com/Alachisoft/NCache)), Cosmos DB, and Postgres. Regardless of which implementation is selected, the app interacts with the cache using the interface. +Distributed cache configuration is implementation specific. This article describes how to configure SQL Server, Redis, or Postgres distributed caches. Non-Microsoft implementations are also available, such as [NCache](http://www.alachisoft.com/ncache/aspnet-core-idistributedcache-ncache.html) ([NCache on GitHub](https://github.com/Alachisoft/NCache)), Azure Cosmos DB, and Postgres. Regardless of which implementation is selected, the app interacts with the cache by using the interface. [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/performance/caching/distributed/samples/) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) @@ -40,68 +42,66 @@ Add a package reference for the distributed cache provider used: * For a Redis distributed cache, [Microsoft.Extensions.Caching.StackExchangeRedis](https://www.nuget.org/packages/Microsoft.Extensions.Caching.StackExchangeRedis). * For SQL Server, [Microsoft.Extensions.Caching.SqlServer](https://www.nuget.org/packages/Microsoft.Extensions.Caching.SqlServer). * For Postgres, [Microsoft.Extensions.Caching.Postgres](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres). -* For Cosmos DB, [Microsoft.Extensions.Caching.Cosmos](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Cosmos). +* For Azure Cosmos DB, [Microsoft.Extensions.Caching.Cosmos](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Cosmos). * For the NCache distributed cache, [NCache.Microsoft.Extensions.Caching.OpenSource](https://www.nuget.org/packages/NCache.Microsoft.Extensions.Caching.OpenSource). -## IDistributedCache interface +## Use the IDistributedCache interface The interface provides the following methods to manipulate items in the distributed cache implementation: * , : Accepts a string key and retrieves a cached item as a `byte[]` array if found in the cache. -* , : Adds an item (as `byte[]` array) to the cache using a string key. +* , : Adds an item (as `byte[]` array) to the cache by using a string key. * , : Refreshes an item in the cache based on its key, resetting its sliding expiration timeout (if any). * , : Removes a cache item based on its string key. ## Establish distributed caching services -Register an implementation of in `Program.cs`. Framework-provided implementations described in this topic include: +Register an implementation of in the _Program.cs_ file. The following framework-provided implementations are described in this article: * [Distributed Redis cache](#distributed-redis-cache) -* [Distributed Memory Cache](#distributed-memory-cache) +* [Distributed memory Cache](#distributed-memory-cache) * [Distributed SQL Server cache](#distributed-sql-server-cache) * [Distributed Postgres cache](#distributed-postgres-cache) * [Distributed NCache cache](#distributed-ncache-cache) * [Distributed Azure Cosmos DB cache](#distributed-azure-cosmos-db-cache) -### Distributed Redis Cache +### Distributed Redis cache + +The distributed Redis cache delivers the best performance and is recommended for production apps. [Redis](https://redis.io/) is an open source in-memory data store, which is often used as a distributed cache. You can configure an [Azure Cache for Redis](/azure/azure-cache-for-redis/cache-overview) for an Azure-hosted ASP.NET Core app, and use an Azure Cache for Redis for local development. For more information, see [Review cache recommendations](#review-cache-recommendations). + +An app configures the cache implementation with a instance by calling the method. For [output caching](xref:performance/caching/output#cache-storage), use the method. -We recommend production apps use the Distributed Redis Cache because it's the most performant. For more information see [Recommendations](#recommendations). +1. Create an Azure Cache for Redis. -[Redis](https://redis.io/) is an open source in-memory data store, which is often used as a distributed cache. You can configure an [Azure Cache for Redis](/azure/azure-cache-for-redis/cache-overview) for an Azure-hosted ASP.NET Core app, and use an Azure Cache for Redis for local development. +1. Copy the Primary connection string (StackExchange.Redis) to [Configuration](xref:fundamentals/configuration/index). -An app configures the cache implementation using a instance, by calling . For [output caching](xref:performance/caching/output#cache-storage), use `AddStackExchangeRedisOutputCache`. + - **For local development**: Save the connection string with [Secret Manager](xref:security/app-secrets#secret-manager). - 1. Create an Azure Cache for Redis. - 1. Copy the Primary connection string (StackExchange.Redis) to [Configuration](xref:fundamentals/configuration/index). - * Local development: Save the connection string with [Secret Manager](xref:security/app-secrets#secret-manager). - * Azure: Save the connection string in a secure store such as [Azure Key Vault](/azure/key-vault/general/overview) + - **For Azure**: Save the connection string in a secure store such as [Azure Key Vault](/azure/key-vault/general/overview). The following code enables the Azure Cache for Redis: [!code-csharp[](~/performance/caching/distributed/samples/6.x/DistCacheSample/Program.cs?name=snippet_AddStackExchangeRedisCache)] -The preceding code assumes the Primary connection string (StackExchange.Redis) was saved in configuration with the key name `MyRedisConStr`. +The preceding code assumes the Primary connection string (StackExchange.Redis) is saved in configuration with the key name `MyRedisConStr`. For more information, see [Azure Cache for Redis](/azure/azure-cache-for-redis/cache-overview). -See [this GitHub issue](https://github.com/dotnet/AspNetCore.Docs/issues/19542) for a discussion on alternative approaches to a local Redis cache. +For a discussion on alternative approaches to a local Redis cache, see [GitHub /dotnet/aspnetcore issue #19542](https://github.com/dotnet/AspNetCore.Docs/issues/19542). -### Distributed Memory Cache +### Distributed memory cache -The Distributed Memory Cache () is a framework-provided implementation of that stores items in memory. The Distributed Memory Cache isn't an actual distributed cache. Cached items are stored by the app instance on the server where the app is running. +The distributed memory cache () is a framework-provided implementation of that stores items in memory. However, the distributed memory cache isn't an actual distributed cache. The app instance stores the cached items on the server where the app is running. -The Distributed Memory Cache is a useful implementation: +The distributed memory cache is a useful implementation for development and testing scenarios. It's also useful for a single server in a production scenario where memory consumption isn't an issue. Implementing the distributed memory cache abstracts cached data storage. It allows for implementing a true distributed caching solution in the future if multiple nodes or fault tolerance become necessary. -* In development and testing scenarios. -* When a single server is used in production and memory consumption isn't an issue. Implementing the Distributed Memory Cache abstracts cached data storage. It allows for implementing a true distributed caching solution in the future if multiple nodes or fault tolerance become necessary. - -The sample app makes use of the Distributed Memory Cache when the app is run in the `Development` environment in `Program.cs`: +The sample app makes use of the distributed memory cache when the app runs in the `Development` environment in the _Program.cs_ file. [!code-csharp[](~/performance/caching/distributed/samples/6.x/DistCacheSample/Program.cs?name=snippet_AddDistributedMemoryCache)] -### Distributed SQL Server Cache +### Distributed SQL Server cache -The Distributed SQL Server Cache implementation () allows the distributed cache to use a SQL Server database as its backing store. To create a SQL Server cached item table in a SQL Server instance, you can use the `sql-cache` tool. The tool creates a table with the name and schema that you specify. +The distributed SQL Server cache implementation () allows the distributed cache to use a SQL Server database as its backing store. To create a SQL Server cached item table in a SQL Server instance, you can use the `sql-cache` tool. The tool creates a table with the name and schema that you specify. Create a table in SQL Server by running the `sql-cache create` command. Provide the SQL Server instance (`Data Source`), database (`Initial Catalog`), schema (for example, `dbo`), and table name (for example, `TestCache`): @@ -109,7 +109,7 @@ Create a table in SQL Server by running the `sql-cache create` command. Provide dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache ``` -A message is logged to indicate that the tool was successful: +When the tool succeeds, a message is logged: ```console Table and index were created successfully. @@ -117,110 +117,117 @@ Table and index were created successfully. The table created by the `sql-cache` tool has the following schema: -![SqlServer Cache Table](~/performance/caching/distributed/_static/SqlServerCacheTable.png) +:::image type="content" source="~/performance/caching/distributed/_static/SqlServerCacheTable.png" alt-text="Screenshot that shows the schema of a SQL Server cache table created with the 'sql-cache create' command."::: > [!NOTE] -> An app should manipulate cache values using an instance of , not a . +> An app should manipulate cache values by using an instance of , not an instance of . -The sample app implements in a non-`Development` environment in `Program.cs`: +The sample app implements the class in a nondevelopment (`Development`) environment in the _Program.cs_ file: [!code-csharp[](~/performance/caching/distributed/samples/6.x/DistCacheSample/Program.cs?name=snippet_AddDistributedSqlServerCache)] > [!NOTE] -> A (and optionally, and ) are typically stored outside of source control (for example, stored by the [Secret Manager](xref:security/app-secrets) or in `appsettings.json`/`appsettings.{Environment}.json` files). The connection string may contain credentials that should be kept out of source control systems. +> Properties like (and optionally, and ) are typically stored outside of source control. For example, the [Secret Manager](xref:security/app-secrets) or the _appsettings.json_ or _appsettings.{Environment}.json_ file might store the properties. The connection string can contain credentials that should be kept out of source control systems. + +For more information, see [SQL Database on Azure](/azure/sql-database/). -### Distributed Postgres Cache +### Distributed Postgres cache -[Azure Database for PostgreSQL](/azure/postgresql) can be used as a distributed cache backing store via the `IDistributedCache` interface. Azure Database for PostgreSQL is a fully managed, AI-ready Database-as-a-Service (DBaaS) offering built on the open-source PostgreSQL engine, designed to support mission-critical workloads with predictable performance, robust security, high availability, and seamless scalability. +[Azure Database for PostgreSQL](/azure/postgresql) can be used as a distributed cache backing store via the `IDistributedCache` interface. Azure Database for PostgreSQL is a fully managed, AI-ready Database-as-a-Service (DBaaS) offering built on the open-source PostgreSQL engine. The design supports mission-critical workloads with predictable performance, robust security, high availability, and seamless scalability. After installing the [Microsoft.Extensions.Caching.Postgres](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres) NuGet package, configure your distributed cache as follows: -1. Register the Service +1. Register the Service. -```csharp -using Microsoft.Extensions.DependencyInjection; + ```csharp + using Microsoft.Extensions.DependencyInjection; -var builder = WebApplication.CreateBuilder(args); + var builder = WebApplication.CreateBuilder(args); -// Register Postgres distributed cache -builder.Services.AddDistributedPostgresCache(options => { - options.ConnectionString = builder.Configuration.GetConnectionString("PostgresCache"); - options.SchemaName = builder.Configuration.GetValue("PostgresCache:SchemaName", "public"); - options.TableName = builder.Configuration.GetValue("PostgresCache:TableName", "cache"); - options.CreateIfNotExists = builder.Configuration.GetValue("PostgresCache:CreateIfNotExists", true); - options.UseWAL = builder.Configuration.GetValue("PostgresCache:UseWAL", false); + // Register the Postgres distributed cache. + builder.Services.AddDistributedPostgresCache(options => { + options.ConnectionString = builder.Configuration.GetConnectionString("PostgresCache"); + options.SchemaName = builder.Configuration.GetValue("PostgresCache:SchemaName", "public"); + options.TableName = builder.Configuration.GetValue("PostgresCache:TableName", "cache"); + options.CreateIfNotExists = builder.Configuration.GetValue("PostgresCache:CreateIfNotExists", true); + options.UseWAL = builder.Configuration.GetValue("PostgresCache:UseWAL", false); - // Optional: Configure expiration settings + // Optional: Configure expiration settings. - var expirationInterval = builder.Configuration.GetValue("PostgresCache:ExpiredItemsDeletionInterval"); - if (!string.IsNullOrEmpty(expirationInterval) && TimeSpan.TryParse(expirationInterval, out var interval)) { - options.ExpiredItemsDeletionInterval = interval; - } + var expirationInterval = builder.Configuration.GetValue("PostgresCache:ExpiredItemsDeletionInterval"); + if (!string.IsNullOrEmpty(expirationInterval) && TimeSpan.TryParse(expirationInterval, out var interval)) { + options.ExpiredItemsDeletionInterval = interval; + } - var slidingExpiration = builder.Configuration.GetValue("PostgresCache:DefaultSlidingExpiration"); - if (!string.IsNullOrEmpty(slidingExpiration) && TimeSpan.TryParse(slidingExpiration, out var sliding)) { - options.DefaultSlidingExpiration = sliding; - } -}); + var slidingExpiration = builder.Configuration.GetValue("PostgresCache:DefaultSlidingExpiration"); + if (!string.IsNullOrEmpty(slidingExpiration) && TimeSpan.TryParse(slidingExpiration, out var sliding)) { + options.DefaultSlidingExpiration = sliding; + } + }); -var app = builder.Build(); -``` + var app = builder.Build(); + ``` -2. Use the Cache +1. Use the cache. -```csharp -public class MyService { - private readonly IDistributedCache _cache; + ```csharp + public class MyService { + private readonly IDistributedCache _cache; - public MyService(IDistributedCache cache) { - _cache = cache; - } + public MyService(IDistributedCache cache) { + _cache = cache; + } - public async Task GetDataAsync(string key) { - var cachedData = await _cache.GetStringAsync(key); + public async Task GetDataAsync(string key) { + var cachedData = await _cache.GetStringAsync(key); - if (cachedData == null) { - // Fetch data from source - var data = await FetchDataFromSource(); + if (cachedData == null) { + + // Fetch the data from source. + var data = await FetchDataFromSource(); - // Cache the data with options - var options = new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30), - SlidingExpiration = TimeSpan.FromMinutes(5) - }; + // Cache the data with options. + var options = new DistributedCacheEntryOptions { + AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30), + SlidingExpiration = TimeSpan.FromMinutes(5) + }; - await _cache.SetStringAsync(key, data, options); - return data; - } + await _cache.SetStringAsync(key, data, options); + return data; + } - return cachedData; - } -} -``` + return cachedData; + } + } + ``` -### Distributed NCache Cache +### Distributed NCache cache [NCache](https://github.com/Alachisoft/NCache) is an open source in-memory distributed cache developed natively in .NET. NCache works both locally and configured as a distributed cache cluster for an ASP.NET Core app running in Azure or on other hosting platforms. -To install and configure NCache on your local machine, see [Getting Started Guide for Windows & Linux](https://www.alachisoft.com/resources/docs/ncache/getting-started-guide-windows/). +To install and configure NCache on your local machine, see the [Getting Started Guide](https://www.alachisoft.com/resources/docs/ncache/getting-started/). To configure NCache: -1. Install [NCache open source NuGet](https://www.nuget.org/packages/Alachisoft.NCache.OpenSource.SDK/). -1. Configure the cache cluster in [client.ncconf](https://www.alachisoft.com/resources/docs/ncache/admin-guide/client-config.html). -1. Add the following code to `Program.cs`: +1. Install the [NCache SDK NuGet package](https://www.nuget.org/packages/Alachisoft.NCache.OpenSource.SDK/), which supports NCache Opensource for .NET Framework and .NET Core apps. + +1. Configure the cache cluster in the [client configuration](https://www.alachisoft.com/resources/docs/ncache/admin-guide/client-config.html) (the _client.ncconf_ file). + +1. Add the following code to the _Program.cs_ file: [!code-csharp[](~/performance/caching/distributed/samples/6.x/DistCacheSample/Program.cs?name=snippet_AddNCache_Cache)] -### Distributed Azure Cosmos DB Cache +### Distributed Azure Cosmos DB cache -[Azure Cosmos DB](/azure/cosmos-db/introduction) can be used in ASP.NET Core as a session state provider by using the `IDistributedCache` interface. Azure Cosmos DB is a fully managed NoSQL and relational database for modern app development that offers high availability, scalability, and low-latency access to data for mission-critical applications. +[Azure Cosmos DB](/azure/cosmos-db/overview) can be configured in ASP.NET Core as a session state provider by using the `IDistributedCache` interface. Azure Cosmos DB is a fully managed NoSQL and relational database for modern app development that offers high availability, scalability, and low-latency access to data for mission-critical applications. -After installing the [Microsoft.Extensions.Caching.Cosmos](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Cosmos) NuGet package, configure an Azure Cosmos DB distributed cache as follows: +After you install the [Microsoft.Extensions.Caching.Cosmos](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Cosmos) NuGet package, configure an Azure Cosmos DB distributed cache. You can use an existing Azure Cosmos DB client or create a new one, as described in the following sections. + +For more information, see the [Microsoft Caching Extension using Azure Cosmos DB](https://github.com/Azure/Microsoft.Extensions.Caching.Cosmos/blob/master/README.md), the GitHub repository README file for the NuGet package. #### Reuse an existing client -The easiest way to configure distributed cache is by reusing an existing Azure Cosmos DB client. In this case, the `CosmosClient` instance won't be disposed when the provider is disposed. +The easiest way to configure a distributed cache is by reusing an existing Azure Cosmos DB client. In this case, the `CosmosClient` instance isn't disposed when the provider is disposed. ```csharp services.AddCosmosCache((CosmosCacheOptions cacheOptions) => @@ -234,7 +241,7 @@ services.AddCosmosCache((CosmosCacheOptions cacheOptions) => #### Create a new client -Alternatively, instantiate a new client. In this case, the `CosmosClient` instance will get disposed when the provider is disposed. +Alternatively, instantiate a new client. In this case, the `CosmosClient` instance is disposed when the provider is disposed. ```csharp services.AddCosmosCache((CosmosCacheOptions cacheOptions) => @@ -250,25 +257,26 @@ services.AddCosmosCache((CosmosCacheOptions cacheOptions) => To use the interface, request an instance of in the app. The instance is provided by [dependency injection (DI)](xref:fundamentals/dependency-injection). -When the sample app starts, is injected into `Program.cs`. The current time is cached using (for more information, see [Generic Host: IHostApplicationLifetime](xref:fundamentals/host/generic-host#ihostapplicationlifetime)): +When the sample app starts, the instance is injected into the _Program.cs_ file. The current time is cached by using the interface. (For more information, see [.NET Generic Host: IHostApplicationLifetime](xref:fundamentals/host/generic-host#ihostapplicationlifetime).) [!code-csharp[](~/performance/caching/distributed/samples/6.x/DistCacheSample/Program.cs?name=snippet_Configure)] -The sample app injects into the `IndexModel` for use by the Index page. +The sample app injects the instance into the `IndexModel` object for use by the Index page. -Each time the Index page is loaded, the cache is checked for the cached time in `OnGetAsync`. If the cached time hasn't expired, the time is displayed. If 20 seconds have elapsed since the last time the cached time was accessed (the last time this page was loaded), the page displays *Cached Time Expired*. +Each time the Index page loads, the cache is checked for the cached time by using the `OnGetAsync` method. If the cached time isn't expired, the time is displayed. If 20 seconds elapsed since the last time the cached time was accessed (the last time this page loaded), the page displays the message, _Cached Time Expired_. -Immediately update the cached time to the current time by selecting the **Reset Cached Time** button. The button triggers the `OnPostResetCachedTime` handler method. +Immediately update the cached time to the current time by selecting the **Reset Cached Time** option. This action triggers the `OnPostResetCachedTime` handler method. [!code-csharp[](~/performance/caching/distributed/samples/6.x/DistCacheSample/Pages/Index.cshtml.cs?name=snippet_IndexModel&highlight=7,14-20,25-29)] -> There's ***no*** need to use a Singleton or Scoped lifetime for instances with the built-in implementations. +> [!NOTE] +> You don't need to use a Singleton or Scoped lifetime for instances with a built-in implementation. > -> You can also create an instance wherever you might need one instead of using DI, but creating an instance in code can make your code harder to test and violates the [Explicit Dependencies Principle](/dotnet/standard/modern-web-apps-azure-architecture/architectural-principles#explicit-dependencies). +> You can also create an instance wherever you might need one instead of using DI. However, creating an instance in code can make your code harder to test and violates the [Explicit Dependencies Principle](/dotnet/architecture/modern-web-apps-azure/architectural-principles#explicit-dependencies). -## Recommendations +## Review cache recommendations -When deciding which implementation of is best for your app, consider the following: +When deciding which implementation of the interface is best for your app, consider the following points: * Existing infrastructure * Performance requirements @@ -279,22 +287,15 @@ Caching solutions usually rely on in-memory storage to provide fast retrieval of For most apps, a Redis cache provides higher throughput and lower latency than a SQL Server cache. However, benchmarking is recommended to determine the performance characteristics of caching strategies. -When SQL Server is used as a distributed cache backing store, use of the same database for the cache and the app's ordinary data storage and retrieval can negatively impact the performance of both. We recommend using a dedicated SQL Server instance for the distributed cache backing store. - -## Additional resources - -* [Redis Cache on Azure](/azure/azure-cache-for-redis/) -* [SQL Database on Azure](/azure/sql-database/) -* [Azure Database for PostgreSQL](/azure/postgresql/) -* [ASP.NET Core IDistributedCache Provider for NCache in Web Farms](http://www.alachisoft.com/ncache/aspnet-core-idistributedcache-ncache.html) ([NCache on GitHub](https://github.com/Alachisoft/NCache)) -* [Repository README file for Microsoft.Extensions.Caching.Cosmos](https://github.com/Azure/Microsoft.Extensions.Caching.Cosmos/blob/master/README.md) -* -* -* -* -* -* -* +If SQL Server is the distributed cache backing store, and the cache and app data storage/retrieval use the same database, performance can be reduced. The recommended approach is to use a dedicated SQL Server instance for the distributed cache backing store. + +## Related content + +* [Cache in-memory in ASP.NET Core](xref:performance/caching/memory) +* [Detect changes with change tokens in ASP.NET Core](xref:fundamentals/change-tokens) +* [Response caching in ASP.NET Core](xref:performance/caching/response) +* [Response caching middleware in ASP.NET Core](xref:performance/caching/middleware) +* [Host ASP.NET Core in a web farm](xref:host-and-deploy/web-farm) :::moniker-end diff --git a/aspnetcore/performance/caching/hybrid/includes/overview.md b/aspnetcore/performance/caching/hybrid/includes/overview.md index f9dd02e6ca0c..2251f9e68669 100644 --- a/aspnetcore/performance/caching/hybrid/includes/overview.md +++ b/aspnetcore/performance/caching/hybrid/includes/overview.md @@ -1,8 +1,8 @@ -The API bridges some gaps in the and APIs. `HybridCache` is an abstract class with a default implementation that handles most aspects of saving to cache and retrieving from cache. +The API bridges gaps in the and APIs. `HybridCache` is an abstract class with a default implementation that handles most aspects of saving to cache and retrieving from cache. -### Features +### Features of HybridCache -`HybridCache` has the following features that the other APIs don't have: +`HybridCache` provides the following features that aren't available with other APIs: * A unified API for both in-process and out-of-process caching. @@ -11,13 +11,13 @@ simple API for adding new caching code. If the app has an `IDistributedCache` im * Stampede protection. - *Cache stampede* happens when a frequently used cache entry is revoked, and too many requests try to repopulate the same cache entry at the same time. `HybridCache` combines concurrent operations, ensuring that all requests for a given response wait for the first request to populate the cache. + *Cache stampede* happens when a frequently used cache entry is revoked, and too many requests try to repopulate the same cache entry at the same time. `HybridCache` combines concurrent operations, which ensures that all requests for a given response wait for the first request to populate the cache. * Configurable serialization. - Serialization is configured as part of registering the service, with support for type-specific and generalized serializers via the `WithSerializer` and `WithSerializerFactory` methods, chained from the `AddHybridCache` call. By default, the service handles `string` and `byte[]` internally, and uses `System.Text.Json` for everything else. It can be configured for other types of serializers, such as protobuf or XML. + Serialization is configured as part of registering the service, with support for type-specific and generalized serializers via the `WithSerializer` and `WithSerializerFactory` methods, chained from the `AddHybridCache` call. By default, the service handles `string` and `byte[]` types internally, and uses the `System.Text.Json` namespace for everything else. `HybridCache` can be configured for other types of serializers, such as protobuf or XML. -To see the relative simplicity of the `HybridCache` API, compare code that uses it to code that uses `IDistributedCache`. Here's an example of what using `IDistributedCache` looks like: +To see the relative simplicity of the `HybridCache` API, compare code that uses it to code that uses the `IDistributedCache` interface. Here's an example of a configuration with the `IDistributedCache` interface: ```csharp public class SomeService(IDistributedCache cache) @@ -52,9 +52,9 @@ public class SomeService(IDistributedCache cache) } ``` -That's a lot of work to get right each time, including things like serialization. And in the "cache miss" scenario, you could end up with multiple concurrent threads, all getting a cache miss, all fetching the underlying data, all serializing it, and all sending that data to the cache. +The code demonstrates a significant amount of work to get right each time, including things like serialization. Also in the "cache miss" scenario, you might end up with multiple concurrent threads. These threads might all receive a cache miss, all fetch the underlying data, all serialize it, and all send the data to the cache. -Here's equivalent code using `HybridCache`: +Here's equivalent code that uses the `HybridCache` API: ```csharp public class SomeService(HybridCache cache) @@ -71,16 +71,16 @@ public class SomeService(HybridCache cache) } ``` -The code is simpler and the library provides stampede protection and other features that `IDistributedCache` doesn't. +The code is simpler, and the library provides stampede protection and other features not available with the `IDistributedCache` interface. ### Compatibility -The `HybridCache` library supports older .NET runtimes, down to .NET Framework 4.7.2 and .NET Standard 2.0. +The `HybridCache` library supports older .NET runtimes, including .NET Framework 4.7.2 and .NET Standard 2.0. -### Additional resources +### More information For more information, see the following resources: -* -* [Hybrid Cache API proposal (`dotnet/aspnetcore` #54647)](https://github.com/dotnet/aspnetcore/issues/54647) -* [`HybridCache` source code](https://source.dot.net/#Microsoft.Extensions.Caching.Abstractions/Hybrid/HybridCache.cs,8c0fe94693d1ac8d) +* [HybridCache library in ASP.NET Core](xref:performance/caching/hybrid) +* [Hybrid Cache API proposal (GitHub dotnet/aspnetcore issue #54647)](https://github.com/dotnet/aspnetcore/issues/54647) +* [HybridCache source code](https://source.dot.net/#Microsoft.Extensions.Caching.Abstractions/Hybrid/HybridCache.cs,8c0fe94693d1ac8d) diff --git a/aspnetcore/performance/caching/memory.md b/aspnetcore/performance/caching/memory.md index b313ac15e9c8..b8d44067601a 100644 --- a/aspnetcore/performance/caching/memory.md +++ b/aspnetcore/performance/caching/memory.md @@ -5,10 +5,12 @@ description: Learn how to cache data in memory in ASP.NET Core. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc -ms.date: 11/07/2023 +ms.date: 05/01/2026 content_well_notification: AI-contribution uid: performance/caching/memory ai-usage: ai-assisted + +# customer intent: As an ASP.NET developer, I want to use in-memory caching in ASP.NET Core, so I can improve the performance and scalability of my app. --- # Cache in-memory in ASP.NET Core @@ -18,64 +20,74 @@ By [Rick Anderson](https://twitter.com/RickAndMSFT), [John Luo](https://github.c Caching can significantly improve the performance and scalability of an app by reducing the work required to generate content. Caching works best with data that changes infrequently **and** is expensive to generate. Caching makes a copy of data that can be returned much faster than from the source. Apps should be written and tested to **never** depend on cached data. -ASP.NET Core supports several different caches. The simplest cache is based on the . `IMemoryCache` represents a cache stored in the memory of the web server. Apps running on a server farm (multiple servers) should ensure sessions are sticky when using the in-memory cache. Sticky sessions ensure that requests from a client all go to the same server. For example, Azure Web apps use [Application Request Routing](/iis/extensions/planning-for-arr/application-request-routing-version-2-overview) (ARR) to route all requests to the same server. +ASP.NET Core supports several different caches. The simplest cache is based on the interface. `IMemoryCache` represents a cache stored in the memory of the web server. Apps running on a server farm (multiple servers) should ensure sessions are sticky when using the in-memory cache. Sticky sessions ensure that requests from a client all go to the same server. For example, an Azure web app uses [Microsoft Application Request Routing (ARR)](/iis/extensions/planning-for-arr/application-request-routing-version-2-overview) to route all requests to the same server. -Non-sticky sessions in a web farm require a [distributed cache](xref:performance/caching/distributed) to avoid cache consistency problems. For some apps, a distributed cache can support higher scale-out than an in-memory cache. Using a distributed cache offloads the cache memory to an external process. +Nonsticky sessions in a web farm require a [distributed cache](xref:performance/caching/distributed) to avoid cache consistency problems. For some apps, a distributed cache can support higher scale-out than an in-memory cache. Using a distributed cache offloads the cache memory to an external process. The in-memory cache can store any object. The distributed cache interface is limited to `byte[]`. The in-memory and distributed cache store cache items as key-value pairs. -## System.Runtime.Caching/MemoryCache +## Use System.Runtime.Caching/MemoryCache / ([NuGet package](https://www.nuget.org/packages/System.Runtime.Caching/)) can be used with: -* .NET Standard 2.0 or later. -* Any [.NET implementation](/dotnet/standard/net-standard#net-implementation-support) that targets .NET Standard 2.0 or later. For example, ASP.NET Core 3.1 or later. -* .NET Framework 4.5 or later. +* .NET Standard 2.0 or later +* Any [.NET implementation](/dotnet/standard/net-standard#net-implementation-support) that targets .NET Standard 2.0 or later (such as ASP.NET Core 3.1 or later) +* .NET Framework 4.5 or later -[Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/`IMemoryCache` (described in this article) is recommended over `System.Runtime.Caching`/`MemoryCache` because it's better integrated into ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](xref:fundamentals/dependency-injection). +[Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/`IMemoryCache` (described in this article) is recommended over `System.Runtime.Caching`/`MemoryCache` because it offers better integration with ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](xref:fundamentals/dependency-injection). Use `System.Runtime.Caching`/`MemoryCache` as a compatibility bridge when porting code from ASP.NET 4.x to ASP.NET Core. -## Cache guidelines +## Review guidelines for in-memory caching + +The following guidelines apply to in-memory caching: + +* Code should always have a fallback option to fetch data and **not** depend on the availability of a cached value. + +* The cache uses memory, which is a scarce resource. Limit cache growth: + + * **Don't** insert external input into the cache. As an example, using arbitrary user-provided input as a cache key isn't recommended because the input might consume an unpredictable amount of memory. -* Code should always have a fallback option to fetch data and **not** depend on a cached value being available. -* The cache uses a scarce resource, memory. Limit cache growth: - * Do **not** insert external input into the cache. As an example, using arbitrary user-provided input as a cache key is not recommended since the input might consume an unpredictable amount of memory. * Use expirations to limit cache growth. - * [Use SetSize, Size, and SizeLimit to limit cache size](#use-setsize-size-and-sizelimit-to-limit-cache-size). The ASP.NET Core runtime does **not** limit cache size based on memory pressure. It's up to the developer to limit cache size. -## Use IMemoryCache + * [Use SetSize, Size, and SizeLimit to limit cache size](#use-setsize-size-and-sizelimit-to-limit-cache-size). The ASP.NET Core runtime **doesn't** limit cache size based on memory pressure. The developer is responsible for limiting the cache size. + +## Create an instance of IMemoryCache + +In-memory caching is a *service* that an app references by using [dependency injection](xref:fundamentals/dependency-injection). > [!WARNING] -> Using a *shared* memory cache from [Dependency Injection](xref:fundamentals/dependency-injection) and calling `SetSize`, `Size`, or `SizeLimit` to limit cache size can cause the app to fail. When a size limit is set on a cache, all entries must specify a size when being added. This can lead to issues since developers may not have full control on what uses the shared cache. -> When using `SetSize`, `Size`, or `SizeLimit` to limit cache, create a cache singleton for caching. For more information and an example, see [Use SetSize, Size, and SizeLimit to limit cache size](#use-setsize-size-and-sizelimit-to-limit-cache-size). -> A shared cache is one shared by other frameworks or libraries. +> If the same cache is used by multiple frameworks or libraries, it's a _shared_ cache. If you use a shared memory cache from [dependency injection](xref:fundamentals/dependency-injection) and also use `SetSize`, `Size`, and `SizeLimit` to limit the cache size, the app can fail. +> +> When a size limit is set on a cache, all entries must specify a size when they're added. This approach can lead to issues because developers might not have full control over what uses the shared cache. +> +> To limit the cache size with the `SetSize` method, the `Size` property, or the `SizeLimit` property, create a cache singleton for caching. For more information and an example, see [Use SetSize, Size, and SizeLimit to limit cache size](#use-setsize-size-and-sizelimit-to-limit-cache-size). -In-memory caching is a *service* that's referenced from an app using [Dependency Injection](xref:fundamentals/dependency-injection). Request the `IMemoryCache` instance in the constructor: +Request the `IMemoryCache` instance in the constructor: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Pages/Index.cshtml.cs" id="snippet_ClassConstructor" highlight="5"::: -The following code uses to check if a time is in the cache. If a time isn't cached, a new entry is created and added to the cache with : +The following code uses the method to check if a time is in the cache. If a time isn't cached, a new entry is created and added to the cache with the method: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Pages/Index.cshtml.cs" id="snippet_OnGet" highlight="5,9-12"::: -In the preceding code, the cache entry is configured with a sliding expiration of three seconds. If the cache entry isn't accessed for more than three seconds, it gets evicted from the cache. Each time the cache entry is accessed, it remains in the cache for a further 3 seconds. The `CacheKeys` class is part of the download sample. +In the preceding code, the cache entry is configured with a sliding expiration of 3 seconds. If the cache entry isn't accessed for more than 3 seconds, the entry is evicted from the cache. Each time the cache entry is accessed, it remains in the cache for a further 3 seconds. The `CacheKeys` class is part of the download sample. The current time and the cached time are displayed: :::code language="cshtml" source="memory/samples/6.x/CachingMemorySample/Pages/Index.cshtml" id="snippet_CacheCurrentDateTime"::: -The following code uses the `Set` extension method to cache data for a relative time without `MemoryCacheEntryOptions`: +The following code uses the `Set` extension method to cache data for a relative time without : :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGetCacheRelative"::: -In the preceding code, the cache entry is configured with a relative expiration of one day. The cache entry gets evicted from the cache after one day, even if it's accessed within this timeout period. +In the preceding code, the cache entry is configured with a relative expiration of one day. The cache entry is evicted from the cache after one day, even if the entry is accessed during the timeout period. -The following code uses and to cache data. +The following code uses the and methods to cache data. :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGetCacheGetOrCreate"::: -The following code calls to fetch the cached time: +The following code calls the method to fetch the cached time: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGetCacheGet"::: @@ -83,107 +95,116 @@ The following code gets or creates a cached item with absolute expiration: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGetCacheGetOrCreateAbsolute" highlight="5"::: -A cached item set with only a sliding expiration is at risk of never expiring. If the cached item is repeatedly accessed within the sliding expiration interval, the item never expires. Combine a sliding expiration with an absolute expiration to guarantee the item expires. The absolute expiration sets an upper bound on how long the item can be cached while still allowing the item to expire earlier if it isn't requested within the sliding expiration interval. If either the sliding expiration interval *or* the absolute expiration time pass, the item is evicted from the cache. +A cached item set with only a sliding expiration is at risk of never expiring. If the cached item is repeatedly accessed within the sliding expiration interval, the item never expires. Combining a sliding expiration with an absolute expiration guarantees the item expires. The absolute expiration sets an upper bound on how long the item can be cached. It still allows the item to expire earlier, if the item isn't requested within the sliding expiration interval. If either the sliding expiration interval *or* the absolute expiration time passes, the item is evicted from the cache. The following code gets or creates a cached item with both sliding *and* absolute expiration: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGetCacheGetOrCreateSlidingAbsolute" highlight="5-6"::: -The preceding code guarantees the data won't be cached longer than the absolute time. +The preceding code guarantees the data isn't cached longer than the absolute time. , , and are extension methods in the class. These methods extend the capability of . -## `MemoryCacheEntryOptions` +## Create MemoryCacheEntryOptions for an entry -The following example: +The following example demonstrates how to create for an entry. The code completes the following tasks: * Sets the cache priority to . -* Sets a that gets called after the entry is evicted from the cache. The callback is run on a different thread from the code that removes the item from the cache. + +* Sets a to call after the entry is evicted from the cache. The callback runs on a different thread from the code that removes the item from the cache. :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_MemoryCacheEntryOptions" highlight="4-5"::: -## Use SetSize, Size, and SizeLimit to limit cache size +## Limit cache size with SetSize, Size, and SizeLimit -A `MemoryCache` instance may optionally specify and enforce a size limit. The cache size limit doesn't have a defined unit of measure because the cache has no mechanism to measure the size of entries. If the cache size limit is set, all entries must specify size. The ASP.NET Core runtime doesn't limit cache size based on memory pressure. It's up to the developer to limit cache size. The size specified is in units the developer chooses. +A `MemoryCache` instance can optionally specify and enforce a size limit. The cache size limit doesn't have a defined unit of measure because the cache has no mechanism to measure the size of entries. If the cache size limit is set, all entries must specify size. The ASP.NET Core runtime doesn't limit cache size based on memory pressure. It's up to the developer to limit cache size. The size specified is in units the developer chooses. For example: -* If the web app was primarily caching strings, each cache entry size could be the string length. -* The app could specify the size of all entries as 1, and the size limit is the count of entries. +* If the web app primarily caches strings, each cache entry size might be the string length. +* The app can specify the size of all entries as 1, and the size limit is the count of entries. -If isn't set, the cache grows without bound. The ASP.NET Core runtime doesn't trim the cache when system memory is low. Apps must be architected to: +If the property isn't set, the cache grows without bound. The ASP.NET Core runtime doesn't trim the cache when system memory is low. Apps must be architected to: * Limit cache growth. -* Call or when available memory is limited. +* Call the or method when available memory is limited. -The following code creates a unitless fixed size accessible by [dependency injection](xref:fundamentals/dependency-injection): +The following code creates a unitless fixed-size instance that's accessible by [dependency injection](xref:fundamentals/dependency-injection): :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/MyMemoryCache.cs" id="snippet_Class"::: -`SizeLimit` doesn't have units. Cached entries must specify size in whatever units they consider most appropriate if the cache size limit has been set. All users of a cache instance should use the same unit system. An entry won't be cached if the sum of the cached entry sizes exceeds the value specified by `SizeLimit`. If no cache size limit is set, the cache size set on the entry is ignored. +The `SizeLimit` property doesn't have units. Cached entries must specify size in whatever units they consider most appropriate when the cache size limit is set. All users of a cache instance should use the same unit system. An entry isn't cached if the sum of the cached entry sizes exceeds the value specified by `SizeLimit`. If no cache size limit is set, the cache size set on the entry is ignored. -The following code registers `MyMemoryCache` with the [dependency injection](xref:fundamentals/dependency-injection) container: +The following code registers the `MyMemoryCache` instance with the [dependency injection](xref:fundamentals/dependency-injection) container: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Program.cs" id="snippet_AddSingletonMyMemoryCache" highlight="4"::: -`MyMemoryCache` is created as an independent memory cache for components that are aware of this size limited cache and know how to set cache entry size appropriately. +`MyMemoryCache` is created as an independent memory cache for components that are aware of this size-limited cache and know how to set cache entry size appropriately. -The size of the cache entry can be set using the extension method or the property: +The size of the cache entry can be set by using the extension method or the property: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/MyMemoryCache.cshtml.cs" id="snippet_OnGetCacheSizeSetSize" highlight="4,6"::: -In the preceding code, the two highlighted lines achieve the same result of setting the size of the cache entry. `SetSize` is provided for convenience when chaining calls onto `new MemoryCacheOptions()`. +In the preceding code, the two highlighted lines achieve the same result of setting the size of the cache entry. The `SetSize` method is provided for convenience when chaining calls onto `new MemoryCacheOptions()`. -### MemoryCache.Compact +### Remove cache items with MemoryCache.Compact -`MemoryCache.Compact` attempts to remove the specified percentage of the cache in the following order: +The `MemoryCache.Compact` method attempts to remove the specified percentage of the cache in the following order: -* All expired items. -* Items by priority. Lowest priority items are removed first. -* Least recently used objects. -* Items with the earliest absolute expiration. -* Items with the earliest sliding expiration. +* All expired items +* Items by priority, where lowest priority items are removed first +* Least recently used objects +* Items with the earliest absolute expiration +* Items with the earliest sliding expiration -Pinned items with priority are [never removed](https://github.com/dotnet/runtime/blob/release/6.0/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs#L415-L430). The following code removes a cache item and calls `Compact` to remove 25% of cached entries: +Pinned items with priority are [never removed](https://github.com/dotnet/runtime/blob/release/6.0/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs#L415-L430). The following code removes a cache item and calls the `Compact` method to remove 25% of cached entries: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/MyMemoryCache.cshtml.cs" id="snippet_OnGetCacheCompact"::: For more information, see the [Compact source on GitHub](https://github.com/dotnet/runtime/blob/release/6.0/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs#L382-L393). -## Cache dependencies +## Evict a cache entry with expired dependencies -The following sample shows how to expire a cache entry if a dependent entry expires. A is added to the cached item. When `Cancel` is called on the `CancellationTokenSource`, both cache entries are evicted: +The following sample shows how to expire a cache entry if a dependent entry expires. A is added to the cached item. When the `Cancel` method is called on the `CancellationTokenSource` object, both cache entries are evicted: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_CacheDependencies" highlight="16,24"::: -Using a allows multiple cache entries to be evicted as a group. With the `using` pattern in the code above, cache entries created inside the `using` scope inherit triggers and expiration settings. +When you use a object, you can evict multiple cache entries as a group. With the `using` pattern in the preceding code, cache entries created inside the `using` scope inherit triggers and expiration settings. -## Additional notes +## Review notes about in-memory caching + +The following notes apply to in-memory caching: -* Expiration doesn't happen in the background. There's no timer that actively scans the cache for expired items. Any activity on the cache (`Get`, `TryGetValue`, `Set`, `Remove`) can trigger a background scan for expired items. A timer on the `CancellationTokenSource` () also removes the entry and triggers a scan for expired items. The following example uses for the registered token. When this token fires, it removes the entry immediately and fires the eviction callbacks: +* Expiration doesn't happen in the background. + + There's no timer that actively scans the cache for expired items. Any activity on the cache (via `Get`, `TryGetValue`, `Set`, or `Remove`) can trigger a background scan for expired items. A timer set on the `CancellationTokenSource` object (by using the method) also removes the entry and triggers a scan for expired items. + + The following example uses the overloaded constructor for the registered token. When this token fires, it removes the entry immediately and fires the eviction callbacks: :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGeCacheExpirationToken"::: -* When using a callback to repopulate a cache item: - * Multiple requests can find the cached key value empty because the callback hasn't completed. - * This can result in several threads repopulating the cached item. -* When one cache entry is used to create another, the child copies the parent entry's expiration tokens and time-based expiration settings. The child isn't expired by manual removal or updating of the parent entry. -* Use to set the callbacks that will be fired after the cache entry is evicted from the cache. -* For most apps, `IMemoryCache` is enabled. For example, calling `AddMvc`, `AddControllersWithViews`, `AddRazorPages`, `AddMvcCore().AddRazorViewEngine`, and many other `Add{Service}` methods in `Program.cs`, enables `IMemoryCache`. For apps that don't call one of the preceding `Add{Service}` methods, it may be necessary to call in `Program.cs`. +* When you use a callback to repopulate a cache item: -## Background cache update + * Multiple requests might discover the cached key value is empty because the callback isn't finished. + * This approach can result in several threads repopulating the cached item. -Use a [background service](xref:fundamentals/host/hosted-services) such as to update the cache. The background service can recompute the entries and then assign them to the cache only when they’re ready. +* When one cache entry (the parent) creates another entry (the child), the child copies the parent entry's expiration tokens and time-based expiration settings. The child doesn't expire by manual removal or updating of the parent entry. -## Additional resources +* Use the property to specify which callbacks should fire after a cache entry is evicted from the cache. + +* For most apps, `IMemoryCache` is enabled. For example, calling `AddMvc`, `AddControllersWithViews`, `AddRazorPages`, `AddMvcCore().AddRazorViewEngine`, and many other `Add{Service}` methods in the _Program.cs_ file enables `IMemoryCache`. + + For apps that don't call one of the mentioned `Add{Service}` methods, you might need to call the method in the _Program.cs_ file. + +## Use a background cache update + +Use a [background service](xref:fundamentals/host/hosted-services) such as the interface to update the cache. The background service can recompute the entries and assign them to the cache only after they're ready. + +## Related content * [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/performance/caching/memory/samples/) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) -* -* -* -* -* -* +* [Detect changes with change tokens in ASP.NET Core](xref:fundamentals/change-tokens) +* [Response caching in ASP.NET Core](xref:performance/caching/response) :::moniker-end diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index 0aacbfee0f5a..b1b78ef1e6b7 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -5,8 +5,10 @@ description: Learn how to configure and use output caching middleware in ASP.NET monikerRange: '>= aspnetcore-7.0' ms.author: tdykstra ms.custom: mvc -ms.date: 06/20/2024 +ms.date: 05/01/2026 uid: performance/caching/output + +# customer intent: As an ASP.NET developer, I want to configure output caching middleware in ASP.NET Core, so I can use output caching in my apps. --- # Output caching middleware in ASP.NET Core @@ -18,34 +20,34 @@ By [Tom Dykstra](https://github.com/tdykstra) This article explains how to configure output caching middleware in an ASP.NET Core app. For an introduction to output caching, see [Output caching](xref:performance/caching/overview#output-caching). -The output caching middleware can be used in all types of ASP.NET Core apps: Minimal API, Web API with controllers, MVC, and Razor Pages. Code examples are provided for Minimal APIs and controller-based APIs. The controller-based API examples show how to use attributes to configure caching. These attributes can also be used in MVC and Razor Pages apps. +The output caching middleware can be used in all types of ASP.NET Core apps: [Minimal APIs](xref:fundamentals/minimal-apis), [Web API with controllers](xref:web-api/index), [MVC](xref:mvc/overview), and [Razor Pages](xref:razor-pages/index). Code examples are provided for Minimal APIs and controller-based APIs. The controller-based API examples show how to use attributes to configure caching. These attributes can also be used in MVC and Razor Pages apps. -The code examples refer to a [Gravatar class](https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/performance/caching/output/samples/7.x/Gravatar.cs) that generates an image and provides a "generated at" date and time. The class is defined and used only in [the sample app](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/performance/caching/output/samples/7.x). Its purpose is to make it easy to see when cached output is being used. For more information, see [How to download a sample](xref:fundamentals/index#how-to-download-a-sample) and [Preprocessor directives in sample code](xref:index#preprocessor-directives-in-sample-code). +The code examples refer to a [Gravatar class](https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/performance/caching/output/samples/7.x/Gravatar.cs) that generates an image and provides a "generated at" date and time. The class is defined and used only in [the sample app](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/performance/caching/output/samples/7.x). Its purpose is to make it easy to see when cached output is being used. For more information, see [How to download a sample](xref:fundamentals/index#how-to-download-a-sample) and [Preprocessor directives](/dotnet/csharp/fundamentals/program-structure/preprocessor-directives). ## Add the middleware to the app -Add the output caching middleware to the service collection by calling . +Add the output caching middleware to the service collection by calling the method. -Add the middleware to the request processing pipeline by calling . +Add the middleware to the request processing pipeline by calling the method. For example: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies4" highlight="1"::: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="snippet_use" highlight="5"::: -Calling `AddOutputCache`and `UseOutputCache` doesn't start caching behavior, it makes caching available. To make the app cache responses, caching must be configured as shown in the following sections. +Calling the `AddOutputCache`and `UseOutputCache` methods doesn't start caching behavior, it makes caching available. To make the app cache responses, caching must be configured as described in the following sections. > [!NOTE] -> * In apps that use [CORS middleware](xref:security/cors), `UseOutputCache` must be called after . -> * In Razor Pages apps and apps with controllers, `UseOutputCache` must be called after `UseRouting`. +> * In apps that use [Cross-Origin Requests (CORS) middleware](xref:security/cors), the `UseOutputCache` method must be called after the method. +> * In Razor Pages apps and apps with controllers, the `UseOutputCache` method must be called after the `UseRouting` method. ## Configure one endpoint or page -For Minimal API apps, configure an endpoint to do caching by calling [`CacheOutput`](xref:Microsoft.Extensions.DependencyInjection.OutputCacheConventionBuilderExtensions.CacheOutput%2A), or by applying the [`[OutputCache]`](xref:Microsoft.AspNetCore.OutputCaching.OutputCacheAttribute) attribute, as shown in the following examples: +For Minimal API apps, configure an endpoint to do caching by calling the [CacheOutput](xref:Microsoft.Extensions.DependencyInjection.OutputCacheConventionBuilderExtensions.CacheOutput%2A) method, or by applying the [[OutputCache](xref:Microsoft.AspNetCore.OutputCaching.OutputCacheAttribute)] attribute, as shown in the following examples: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="oneendpoint"::: -For apps with controllers, apply the `[OutputCache]` attribute to the action method as shown here: +For apps with controllers, apply the `[OutputCache]` attribute to the action method as shown in the following code: :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Controllers/CachedController.cs" id="snippet_oneendpoint"::: @@ -53,9 +55,9 @@ For Razor Pages apps, apply the attribute to the Razor page class. ## Configure multiple endpoints or pages -Create *policies* when calling `AddOutputCache` to specify caching configuration that applies to multiple endpoints. A policy can be selected for specific endpoints, while a base policy provides default caching configuration for a collection of endpoints. +Create *policies* when calling the `AddOutputCache` method to specify caching configuration that applies to multiple endpoints. A policy can be selected for specific endpoints, while a base policy provides default caching configuration for a collection of endpoints. -The following highlighted code configures caching for all of the app's endpoints, with expiration time of 10 seconds. If an expiration time isn't specified, it defaults to one minute. +The following highlighted code configures caching for all of the app's endpoints, with an expiration time of 10 seconds. If an expiration time isn't specified, it defaults to one minute. :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies1" highlight="3-4"::: @@ -63,7 +65,7 @@ The following highlighted code creates two policies, each specifying a different :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies1" highlight="5-8"::: -You can select a policy for an endpoint when calling the `CacheOutput` method or using the `[OutputCache]` attribute. +You can select a policy for an endpoint when calling the `CacheOutput` method or by using the `[OutputCache]` attribute. In a Minimal API app, the following code configures one endpoint with a 20-second expiration and one with a 30-second expiration: @@ -73,9 +75,9 @@ For apps with controllers, apply the `[OutputCache]` attribute to the action met :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Controllers/Expire20Controller.cs" id="snippet_selectpolicy"::: - For Razor Pages apps, apply the attribute to the Razor page class. +For Razor Pages apps, apply the attribute to the Razor page class. -## Default output caching policy +## Work with the default output caching policy By default, output caching follows these rules: @@ -90,7 +92,7 @@ The following code applies all of the default caching rules to all of an app's e ### Override the default policy -The following code shows how to override the default rules. The highlighted lines in the following custom policy code enable caching for HTTP POST methods and HTTP 301 responses: +The following code shows how to override the default policy rules. The highlighted lines in the following custom policy code enable caching for HTTP POST methods and HTTP 301 responses: :::code language="csharp" source="~/performance/caching/output/samples/7.x/MyCustomPolicy.cs" highlight="50,68"::: @@ -98,7 +100,7 @@ To use this custom policy, create a named policy: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies3b"::: -And select the named policy for an endpoint. The following code selects the custom policy for an endpoint in a Minimal API app: +And, select the named policy for an endpoint. The following code selects the custom policy for an endpoint in a Minimal API app: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="post"::: @@ -106,11 +108,11 @@ The following code does the same for a controller action: :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Controllers/PostController.cs" id="snippet_post"::: -### Alternative default policy override +### Use an alternative default policy override -Alternatively, use Dependency Injection (DI) to initialize an instance, with the following changes to the custom policy class: +Alternatively, use Dependency Injection (DI) to initialize an instance with the following changes to the custom policy class: -* A public constructor instead of a private constructor. +* Use a public constructor instead of a private constructor. * Eliminate the `Instance` property in the custom policy class. For example: @@ -123,7 +125,7 @@ The remainder of the class is the same as shown previously. Add the custom polic The preceding code uses DI to create the instance of the custom policy class. Any public arguments in the constructor are resolved. -When using a custom policy as a base policy, don't call `OutputCache()` (with no arguments) or use the `[OutputCache]` attribute on any endpoint that the base policy should apply to. Calling `OutputCache()` or using the attribute adds the default policy to the endpoint. +When using a custom policy as a base policy, don't call the `OutputCache()` method (with no arguments) or use the `[OutputCache]` attribute on any endpoint that the base policy should apply to. Calling the `OutputCache()` method or using the attribute adds the default policy to the endpoint. ## Specify the cache key @@ -141,35 +143,37 @@ The following code does the same for a controller action: Here are some of the options for controlling the cache key: -* - Specify one or more query string names to add to the cache key. -* - Specify one or more HTTP headers to add to the cache key. -* - Specify a value to add to the cache key. The following example uses a value that indicates whether the current server time in seconds is odd or even. A new response is generated only when the number of seconds goes from odd to even or even to odd. +* The method specifies one or more query string names to add to the cache key. +* The method specifies one or more HTTP headers to add to the cache key. +* The method provides a value to add to the cache key. The following example uses a value that indicates whether the current server time in seconds is odd or even. A new response is generated only when the number of seconds changes from an odd to even value, or vice versa. :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Program.cs" id="policies2" highlight="10-14"::: -Use to specify that the path part of the key is case sensitive. The default is case insensitive. +Use the property to specify that the path part of the key is case sensitive. The default is case insensitive. For more options, see the class. -## Cache revalidation +## Enable cache revalidation + +Cache revalidation means the server can return a _304 Not Modified_ HTTP status code instead of the full response body. This status code informs the client that the response to the request is unchanged from what the client previously received. -Cache revalidation means the server can return a `304 Not Modified` HTTP status code instead of the full response body. This status code informs the client that the response to the request is unchanged from what the client previously received. +The following code illustrates the use of an [ETag](https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag) header to enable cache revalidation. If the client sends an [If-None-Match](https://developer.mozilla.org/docs/Web/HTTP/Headers/If-None-Match) header with the value for the `ETag` from an earlier response, and the cache entry is fresh, the server returns the [304 Not Modified](https://developer.mozilla.org/docs/Web/HTTP/Status/304) code instead of the full response. -The following code illustrates the use of an [`Etag`](https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag) header to enable cache revalidation. If the client sends an [`If-None-Match`](https://developer.mozilla.org/docs/Web/HTTP/Headers/If-None-Match) header with the etag value of an earlier response, and the cache entry is fresh, the server returns [304 Not Modified](https://developer.mozilla.org/docs/Web/HTTP/Status/304) instead of the full response. Here's how to set the etag value in a policy, in a Minimal API app: +The following code sets the `ETag` value in a policy in a Minimal API app: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="etag"::: -And here's how to set the etag value in a controller-based API: +The following code does the same for a controller-based API: :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Controllers/EtagController.cs" id="snippet_etag"::: -Another way to do cache revalidation is to check the date of the cache entry creation compared to the date requested by the client. When the request header `If-Modified-Since` is provided, output caching returns 304 if the cached entry is older and isn't expired. +Another way to do cache revalidation is to check the date of the cache entry creation compared to the date requested by the client. When the request header `If-Modified-Since` is provided, output caching returns the 304 code if the cached entry is older and isn't expired. Cache revalidation is automatic in response to these headers sent from the client. No special configuration is required on the server to enable this behavior, aside from enabling output caching. ## Use tags to evict cache entries -You can use tags to identify a group of endpoints and evict all cache entries for the group. For example, the following Minimal API code creates a pair of endpoints whose URLs begin with "blog", and tags them "tag-blog": +You can use tags to identify a group of endpoints and evict all cache entries for the group. For example, the following Minimal API code creates a pair of endpoints whose URLs begin with the text `blog` and applies the `tag-blog` tag: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="tagendpoint"::: @@ -177,11 +181,11 @@ The following code shows how to assign tags to an endpoint in a controller-based :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Controllers/TagEndpointController.cs" id="snippet_tagendpoint"::: -An alternative way to assign tags for endpoints with routes that begin with `blog` is to define a base policy that applies to all endpoints with that route. The following code shows how to do that: +An alternative way to assign tags for endpoints with routes that begin with `blog` is to define a base policy that applies to all endpoints with that route. The following code demonstrates this approach: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies2" highlight="3-5"::: -Another alternative for Minimal API apps is to call `MapGroup`: +Another alternative for Minimal API apps is to call the [MapGroup(/dotnet/api/microsoft.aspnetcore.builder.endpointroutebuilderextensions.mapgroup) method: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="taggroup"::: @@ -189,23 +193,23 @@ In the preceding tag assignment examples, both endpoints are identified by the ` :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="evictbytag"::: -With this code, an HTTP POST request sent to `https://localhost:/purge/tag-blog` evicts cache entries for these endpoints. +With this code, an HTTP POST request sent to the `https://localhost:/purge/tag-blog` URL evicts cache entries for these endpoints. -You might want a way to evict all cache entries for all endpoints. To do that, create a base policy for all endpoints as the following code does: +You might want a way to evict all cache entries for all endpoints. You can create a base policy for all endpoints as demonstrated in the following code: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies2" highlight="6"::: -This base policy enables you to use the "tag-all" tag to evict everything in cache. +This base policy enables you to use the `tag-all` tag to evict everything in cache. ## Disable resource locking -By default, resource locking is enabled to mitigate the risk of [cache stampede and thundering herd](https://en.wikipedia.org/wiki/Thundering_herd_problem). For more information, see [Output Caching](xref:performance/caching/overview#output-caching). +By default, resource locking is enabled to mitigate the risk of [cache stampede and thundering herd](https://wikipedia.org/wiki/Thundering_herd_problem). For more information, see [Output Caching](xref:performance/caching/overview#output-caching). -To disable resource locking, call [SetLocking(false)](xref:Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.SetLocking%2A) while creating a policy, as shown in the following example: +To disable resource locking, call the [SetLocking(false)](xref:Microsoft.AspNetCore.OutputCaching.OutputCachePolicyBuilder.SetLocking%2A) method while creating a policy, as shown in the following example: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies2" highlight="9"::: -The following example selects the no-locking policy for an endpoint in a Minimal API app: +The next example selects the no-locking policy for an endpoint in a Minimal API app: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="selectnolock"::: @@ -213,42 +217,46 @@ In a controller-based API, use the attribute to select the policy: :::code language="csharp" source="~/performance/caching/output/samples/9.x/OCControllers/Controllers/NoLockController.cs" id="snippet_selectnolock"::: -## Limits +## Configure limits -The following properties of let you configure limits that apply to all endpoints: +The following properties of the class let you configure limits that apply to all endpoints: -* - Maximum size of cache storage. When this limit is reached, no new responses are cached until older entries are evicted. Default value is 100 MB. -* - If the response body exceeds this limit, it isn't cached. Default value is 64 MB. -* - The expiration time duration that applies when not specified by a policy. Default value is 60 seconds. +* The property sets the maximum size for the cache storage. When the limit is reached, no new responses are cached until older entries are evicted. The default value is 100 MB. +* The property sets the maximum size for the response body. If the response body exceeds the limit, it isn't cached. The default value is 64 MB. +* The property sets the maximum duration a response is cached, when a time isn't specified in a policy. The default value is 60 seconds. -## Cache storage +## Explore cache storage options - is used for storage. By default it's used with . Cached responses are stored in-process, so each server has a separate cache that is lost whenever the server process is restarted. +The interface is used for storage. By default, it's used with the class. Cached responses are stored in-process, so each server has a separate cache that is lost whenever the server process restarts. -### Redis cache +### Alternative: Redis cache An alternative is to use [Redis](https://redis.io/) cache. Redis cache provides consistency between server nodes via a shared cache that outlives individual server processes. To use Redis for output caching: * Install the [Microsoft.AspNetCore.OutputCaching.StackExchangeRedis](https://www.nuget.org/packages/Microsoft.AspNetCore.OutputCaching.StackExchangeRedis) NuGet package. -* Call `builder.Services.AddStackExchangeRedisOutputCache` (not `AddStackExchangeRedisCache`), and provide a connection string that points to a Redis server. + +* Call the `builder.Services.AddStackExchangeRedisOutputCache` method (not the `AddStackExchangeRedisCache` method), and provide a connection string that points to a Redis server. For example: :::code language="csharp" source="~/performance/caching/output/samples/8.x/Program.cs" id="redis" highlight="1-6"::: - * [`options.Configuration`](xref:Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions.Configuration) - A connection string to an on-premises Redis server or to a hosted offering such as [Azure Cache for Redis](/azure/azure-cache-for-redis/). For example, `.redis.cache.windows.net:6380,password=,pw,ssl=True,abortConnect=False` for Azure cache for Redis. - * [`options.InstanceName`](xref:Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions.InstanceName) - Optional, specifies a logical partition for the cache. + * The [options.Configuration](xref:Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions.Configuration) property is a connection string to an on-premises Redis server or to a hosted offering such as [Azure Cache for Redis](/azure/azure-cache-for-redis/). For example, `.redis.cache.windows.net:6380,password=,pw,ssl=True,abortConnect=False` for Azure Cache for Redis. + + * (Optional) The [options.InstanceName](xref:Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions.InstanceName) property specifies a logical partition for the cache. The configuration options are identical to the [Redis-based distributed caching options](xref:performance/caching/distributed#distributed-redis-cache). -### `IDistributedCache` not recommended +### Not recommended: IDistributedCache + +The interface isn't recommended for use with output caching. This interface doesn't provide atomic features, which are required for tagging. -We don't recommend for use with output caching. `IDistributedCache` doesn't have atomic features, which are required for tagging. We recommend that you use the built-in support for Redis or create custom implementations by using direct dependencies on the underlying storage mechanism. +The recommended approach is to use the built-in support for Redis or create a custom implementation by using direct dependencies on the underlying storage mechanism. -## See also +## Related content -* -* +* [Overview of caching in ASP.NET Core](xref:performance/caching/overview) +* [ASP.NET Core Middleware](xref:fundamentals/middleware/index) * * diff --git a/aspnetcore/performance/caching/overview.md b/aspnetcore/performance/caching/overview.md index 3b03544470e1..35e647c13487 100644 --- a/aspnetcore/performance/caching/overview.md +++ b/aspnetcore/performance/caching/overview.md @@ -1,11 +1,13 @@ --- title: Overview of caching in ASP.NET Core author: tdykstra -description: Overview of caching in ASP.NET Core +description: Explore caching in ASP.NET Core, including in-memory, distributed, hybrid, response, and output caching. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra -ms.date: 11/07/2022 +ms.date: 05/01/2026 uid: performance/caching/overview + +# customer intent: As an ASP.NET developer, I want to explore caching options in ASP.NET Core, so I can use various types of caching in my apps. --- # Overview of caching in ASP.NET Core @@ -13,19 +15,21 @@ uid: performance/caching/overview By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Tom Dykstra](https://twitter.com/tdykstra) +This article provides an overview of caching in ASP.NET Core with an introduction to in-memory, distributed, hybrid, response, and output caching. + :::moniker range=">= aspnetcore-9.0" ## 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 session affinity. Session affinity is also known as *sticky sessions*. Session affinity means that the requests from a client are always routed to the same server for processing. +In-memory caching uses server memory to store cached data. This type of caching is suitable for a single server or multiple servers that use session affinity. Session affinity is also known as *sticky sessions*. Session affinity means that the requests from a client are always routed to the same server for processing. -For more information, see and [Troubleshoot Azure Application Gateway session affinity issues](/azure/application-gateway/how-to-troubleshoot-application-gateway-session-affinity-issues). +For more information, see [Cache in-memory in ASP.NET Core](xref:performance/caching/memory) and [Troubleshoot Azure Application Gateway session affinity issues](/azure/application-gateway/how-to-troubleshoot-application-gateway-session-affinity-issues). -## Distributed Cache +## Distributed cache -Use a distributed cache to store data 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's handled by any server in the group if cached data for the client is available. ASP.NET Core works with SQL Server, [Redis](https://www.nuget.org/packages/Microsoft.Extensions.Caching.StackExchangeRedis), [Postgres](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres), and [NCache](https://www.nuget.org/packages/Alachisoft.NCache.OpenSource.SDK/) distributed caches. +Use a distributed cache to store data 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 gets handled by any server in the group when cached data for the client is available. ASP.NET Core works with SQL Server, [Redis](https://www.nuget.org/packages/Microsoft.Extensions.Caching.StackExchangeRedis), [Postgres](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Postgres), and [NCache](https://www.nuget.org/packages/Alachisoft.NCache.OpenSource.SDK/) distributed caches. -For more information, see . +For more information, see [Distributed caching in ASP.NET Core](xref:performance/caching/distributed). ## HybridCache @@ -35,17 +39,15 @@ For more information, see . [!INCLUDE[](~/includes/response-caching-mid.md)] -For more information, see . - - +For more information, see [Response caching in ASP.NET Core](xref:performance/caching/response). ## Output caching The output caching middleware enables caching of HTTP responses. Output caching differs from [response caching](#response-caching) in the following ways: -* The caching behavior is configurable on the server. +* Caching behavior is configurable on the server. - Response caching behavior is defined by HTTP headers. For example, when you visit a website with Chrome or Edge, the browser automatically sends a `Cache-control: max-age=0` header. This header effectively disables response caching, since the server follows the directions provided by the client. A new response is returned for every request, even if the server has a fresh cached response. With output caching the client doesn't override the caching behavior that you configure on the server. + Response caching behavior is defined with HTTP headers. For example, when you browse a website with Chrome or Microsoft Edge, the browser automatically sends a `Cache-control: max-age=0` header. This header effectively disables response caching because the server follows the directions provided by the client. A new response is returned for every request, even if the server has a fresh cached response. With output caching, the client doesn't override the caching behavior that you configure on the server. * The cache storage medium is extensible. @@ -53,7 +55,7 @@ The output caching middleware enables caching of HTTP responses. Output caching * You can programmatically invalidate selected cache entries. - Response caching's dependence on HTTP headers leaves you with few options for invalidating cache entries. + Response caching is dependent on HTTP headers, which leaves you with few options for invalidating cache entries. * Resource locking mitigates the risk of cache stampede and thundering herd. @@ -61,23 +63,31 @@ The output caching middleware enables caching of HTTP responses. Output caching * Cache revalidation minimizes bandwidth usage. - *Cache revalidation* means the server can return a `304 Not Modified` HTTP status code instead of a cached response body. This status code informs the client that the response to the request is unchanged from what was previously received. Response caching doesn't do cache revalidation. + *Cache revalidation* means the server can return a _304 Not Modified_ HTTP status code instead of a cached response body. This status code informs the client that the response to the request is unchanged from what was previously received. Response caching doesn't do cache revalidation. -For more information, see . +For more information, see [Output caching middleware in ASP.NET Core](xref:performance/caching/output). ## Cache Tag Helper 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 . +For more information, see [Cache Tag Helper in ASP.NET Core MVC](xref:mvc/views/tag-helpers/builtin-th/cache-tag-helper). ## Distributed Cache Tag Helper 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, [Redis](https://www.nuget.org/packages/Microsoft.Extensions.Caching.StackExchangeRedis), or [NCache](https://www.nuget.org/packages/Alachisoft.NCache.OpenSource.SDK/) to store data. -For more information, see . +For more information, see [Distributed Cache Tag Helper in ASP.NET Core](xref:mvc/views/tag-helpers/builtin-th/distributed-cache-tag-helper). :::moniker-end [!INCLUDE[](~/performance/caching/overview/includes/overview7-8.md)] [!INCLUDE[](~/performance/caching/overview/includes/overview6.md)] + +## Related content + +* [Cache in-memory in ASP.NET Core](xref:performance/caching/memory) +* [Distributed caching in ASP.NET Core](xref:performance/caching/distributed) +* [HybridCache library in ASP.NET Core](xref:performance/caching/hybrid) +* [Response caching middleware in ASP.NET Core](xref:performance/caching/middleware) +* [Output caching middleware in ASP.NET Core](xref:performance/caching/output) \ No newline at end of file diff --git a/aspnetcore/performance/caching/response.md b/aspnetcore/performance/caching/response.md index 7892d3faca7a..95778494aca2 100644 --- a/aspnetcore/performance/caching/response.md +++ b/aspnetcore/performance/caching/response.md @@ -4,8 +4,10 @@ author: tdykstra description: Learn how to use response caching to lower bandwidth requirements and increase performance of ASP.NET Core apps. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra -ms.date: 1/11/2022 +ms.date: 05/01/2026 uid: performance/caching/response + +# customer intent: As an ASP.NET developer, I want to use response caching in ASP.NET Core, so I can reduce bandwidth requirements and increase performance of my apps. --- # Response caching in ASP.NET Core @@ -13,27 +15,27 @@ By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Kirk Larkin](https://tw :::moniker range=">= aspnetcore-6.0" -[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/performance/caching/response/samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) - 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 set in headers. -The [ResponseCache attribute](#responsecache-attribute) sets response caching headers. Clients and intermediate proxies should honor the headers for caching responses under [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111). +The [ResponseCache attribute](#responsecache-attribute) sets response caching headers. Clients and intermediate proxies should honor the headers for caching responses under the [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111) specification. For server-side caching that follows the HTTP 1.1 Caching specification, use [Response Caching Middleware](xref:performance/caching/middleware). The middleware can use the properties to influence server-side caching behavior. [!INCLUDE[](~/includes/response-caching-mid.md)] +[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/performance/caching/response/samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) + ## HTTP-based response caching -[RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111) describes how Internet caches should behave. The primary HTTP header used for caching is [Cache-Control](https://www.rfc-editor.org/rfc/rfc9111#field.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 responses 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. +The [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111) specification describes how internet caches should behave. The primary HTTP header used for caching is [Cache-Control](https://www.rfc-editor.org/rfc/rfc9111#field.cache-control), which is used to specify cache directives. The directives control caching behavior as requests make their way from clients to servers and responses 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](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.public) | A cache may store the response. | -| [private](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.private) | The response must not be stored by a shared cache. A private cache may store and reuse the response. | -| [max-age](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.max-age) | The client doesn'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) | +| [public](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.public) | A cache can store the response. | +| [private](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.private) | A shared cache must not store the response. A private cache can store and reuse the response. | +| [max-age](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.max-age) | The client doesn't accept a response whose age is greater than the specified number of seconds. Examples: `max-age=60` (60 seconds), `max-age=2592000` (one month) | | [no-cache](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.no-cache) | **On requests**: A cache must not use a stored response to satisfy the request. The origin server regenerates 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](https://www.rfc-editor.org/rfc/rfc9111#cache-response-directive.no-store) | **On requests**: A cache must not store the request.

**On responses**: A cache must not store any part of the response. | @@ -41,27 +43,27 @@ Other cache headers that play a role in caching are shown in the following table | Header | Function | | --------------------------------------------------------------- | -------- | -| [Age](https://www.rfc-editor.org/rfc/rfc9111#field.age) | An estimate of the amount of time in seconds since the response was generated or successfully validated at the origin server. | -| [Expires](https://www.rfc-editor.org/rfc/rfc9111#field.expires) | The time after which the response is considered stale. | -| [Pragma](https://www.rfc-editor.org/rfc/rfc9111#field.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. | +| [Age](https://www.rfc-editor.org/rfc/rfc9111#field.age) | Provides an estimate of the amount of time in seconds since the response was generated or successfully validated at the origin server. | +| [Expires](https://www.rfc-editor.org/rfc/rfc9111#field.expires) | Specified the time after which the response is considered stale. | +| [Pragma](https://www.rfc-editor.org/rfc/rfc9111#field.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](https://www.rfc-editor.org/rfc/rfc9110#field.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 -[RFC 9111: HTTP Caching (Section 5.2. Cache-Control)](https://www.rfc-editor.org/rfc/rfc9111#field.cache-control) 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. +The [RFC 9111: HTTP Caching (Section 5.2. Cache-Control)](https://www.rfc-editor.org/rfc/rfc9111#field.cache-control) specification 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. +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. The approach isn't necessarily a way to control the load on an origin server. -There's no developer control over this caching behavior when using the [Response Caching Middleware](xref:performance/caching/middleware) because the middleware adheres to the official caching specification. Support for *output caching* to better control server load was added in .NET 7. For more information, see [Output caching](xref:performance/caching/overview#output-caching). +There's no developer control over this caching behavior when using the [Response Caching Middleware](xref:performance/caching/middleware) because the middleware adheres to the official caching specification. .NET 7 and later includes support for *output caching* to better control server load. For more information, see [Output caching](xref:performance/caching/overview#output-caching). ## ResponseCache attribute -The specifies the parameters necessary for setting appropriate headers in response caching. +The class specifies the parameters necessary for setting appropriate headers in response caching. > [!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 signed in. - varies the stored response by the values of the given list of query keys. When a single value of `*` is provided, the middleware varies responses by all request query string parameters. +The property varies the stored response by the values of the given list of query keys. When a single value of the wildcard asterisk (`*`) is provided, the middleware varies responses by all request query string parameters. [Response Caching Middleware](xref:performance/caching/middleware) must be enabled to set the property. Otherwise, a runtime exception is thrown. There isn't a corresponding HTTP header for the property. The property is an HTTP feature handled by 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: @@ -71,17 +73,17 @@ The specifies the paramet | `http://example.com?key1=value1` | Middleware | | `http://example.com?key1=NewValue` | 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 isn't in the middleware cache because the query string value doesn't match a previous request. +The server returns the first request and the middleware caches the request. The middleware returns the second request because the query string matches the previous (first) request. The third request isn't in the middleware cache because the query string value doesn't match a previous request. -The is used to configure and create (via ) a `Microsoft.AspNetCore.Mvc.Internal.ResponseCacheFilter`. The `ResponseCacheFilter` performs the work of updating the appropriate HTTP headers and features of the response. The filter: +The class is used to configure and create (via the interface) a `Microsoft.AspNetCore.Mvc.Internal.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`, and `Pragma`. * Writes out the appropriate headers based on the properties set in the . -* Updates the response caching HTTP feature if is set. +* Updates the response caching HTTP feature if the property is set. -### Vary +### Vary header -This header is only written when the property is set. The property set to the `Vary` property's value. The following sample uses the property: +This header is only written when the property is set. The property is set to the `Vary` property's value. The following sample uses the property: [!code-csharp[](response/samples/6.x/WebRC/Controllers/TimeController.cs?name=snippet)] @@ -92,33 +94,33 @@ Cache-Control: public,max-age=30 Vary: User-Agent ``` -The preceding code requires adding the Response Caching Middleware services to the service collection and configures the app to use the middleware with the extension method. +The preceding code requires adding the Response Caching Middleware services method to the service collection. The code configures the app to use the middleware with the extension method. [!code-csharp[](response/samples/6.x/WebRC/Program.cs?name=snippet&highlight=4,13)] -### `NoStore` and `Location.None` +### NoStore and Location.None properties - overrides most of the other properties. When this property is set to `true`, the `Cache-Control` header is set to `no-store`. If is set to `None`: +The property overrides most of the other properties. When this property is set to `true`, the `Cache-Control` header is set to `no-store`. If the property is set to `None`: -* `Cache-Control` is set to `no-store,no-cache`. -* `Pragma` is set to `no-cache`. +* The `Cache-Control` header is set to `no-store,no-cache`. +* The `Pragma` header is set to `no-cache`. -If is `false` and is `None`, `Cache-Control`, and `Pragma` are set to `no-cache`. +If the property is set to `false` and the property is set to `None`, the `Cache-Control` and `Pragma` headers are set to `no-cache`. - is typically set to `true` for error pages. The following produces response headers that instruct the client not to store the response. +The property is typically set to `true` for error pages. The following code produces response headers that instruct the client not to store the response. [!code-csharp[](response/samples/6.x/WebRC/Controllers/TimeController.cs?name=snippet2)] The preceding code includes the following headers in the response: -``` +```text Cache-Control: no-store,no-cache Pragma: no-cache ``` -To apply the to all of the app's MVC controller or Razor Pages page responses, add it with an [MVC filter](xref:mvc/controllers/filters) or [Razor Pages filter](xref:razor-pages/filter). +To apply the to all of the app's MVC controller or Razor Pages page responses, add the attribute with an [MVC filter](xref:mvc/controllers/filters) or [Razor Pages filter](xref:razor-pages/filter). -In an MVC app: +In an MVC app, add the following code: ```csharp builder.Services.AddControllersWithViews().AddMvcOptions(options => @@ -130,21 +132,21 @@ builder.Services.AddControllersWithViews().AddMvcOptions(options => })); ``` -For an approach that applies to Razor Pages apps, see [Adding `ResponseCacheAttribute` to MVC global filter list does not apply to Razor Pages (dotnet/aspnetcore #18890)](https://github.com/dotnet/aspnetcore/issues/18890#issuecomment-584290537). The example provided in the issue comment was written for apps targeting ASP.NET Core prior to the release of [Minimal APIs](xref:fundamentals/minimal-apis) at 6.0. For 6.0 or later apps, change the service registration in the example to `builder.Services.AddSingleton...` for `Program.cs`. +For an approach that applies to Razor Pages apps, see [GitHub dotnet/aspnetcore issue #18890)](https://github.com/dotnet/aspnetcore/issues/18890#issuecomment-584290537) - _Adding ResponseCacheAttribute to MVC global filter list does not apply to Razor Pages_. The comment example in the issue applies to ASP.NET Core apps that predate the release of [Minimal APIs](xref:fundamentals/minimal-apis) (ASP.NET Core version 6.0). For apps that target version 6.0 and later, change the service registration used in the example to `builder.Services.AddSingleton...` in the _Program.cs_ file. -### Location and Duration +### Location and Duration properties -To enable caching, must be set to a positive value and must be either `Any` (the default) or `Client`. The framework sets the `Cache-Control` header to the location value followed by the `max-age` of the response. +To enable caching, the property must be set to a positive value and must be either `Any` (the default) or `Client`. The framework sets the `Cache-Control` header to the location value followed by the `max-age` of the response. -'s options of `Any` and `Client` translate into `Cache-Control` header values of `public` and `private`, respectively. As noted in the [NoStore and Location.None](#nostore-and-locationnone) section, setting to `None` sets both `Cache-Control` and `Pragma` headers to `no-cache`. +The property options of `Any` and `Client` translate into `Cache-Control` header values of `public` and `private`, respectively. As noted in the [NoStore and Location.None](#nostore-and-locationnone-properties) section, setting the property to `None` sets both the `Cache-Control` and `Pragma` headers to `no-cache`. -`Location.Any` (`Cache-Control` set to `public`) indicates that the *client or any intermediate proxy* may cache the value, including [Response Caching Middleware](xref:performance/caching/middleware). +The `Location.Any` (`Cache-Control` set to `public`) property setting indicates that the *client or any intermediate proxy* can cache the value, including [Response Caching Middleware](xref:performance/caching/middleware). -`Location.Client` (`Cache-Control` set to `private`) indicates that *only the client* may cache the value. No intermediate cache should cache the value, including [Response Caching Middleware](xref:performance/caching/middleware). +The `Location.Client` (`Cache-Control` set to `private`) property setting indicates that *only the client* can cache the value. No intermediate cache should cache the value, including [Response Caching Middleware](xref:performance/caching/middleware). -Cache control headers provide guidance to clients and intermediary proxies when and how to cache responses. There's no guarantee that clients and proxies will honor [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111). [Response Caching Middleware](xref:performance/caching/middleware) always follows the caching rules laid out by the specification. +Cache control headers provide guidance to clients and intermediary proxies about when and how to cache responses. There's no guarantee that clients and proxies the honor [RFC 9111: HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111) specification. [Response Caching Middleware](xref:performance/caching/middleware) always follows the caching rules laid out by the specification. -The following example shows the headers produced by setting and leaving the default value: +The following example shows the headers produced by setting the property and leaving the default property value: [!code-csharp[](response/samples/6.x/WebRC/Controllers/TimeController.cs?name=snippet3)] @@ -156,9 +158,9 @@ Cache-Control: public,max-age=10 ### Cache profiles -Instead of duplicating response cache settings on many controller action attributes, cache profiles can be configured as options when setting up MVC/Razor Pages. Values found in a referenced cache profile are used as the defaults by the and are overridden by any properties specified on the attribute. +Instead of duplicating response cache settings on many controller action attributes, cache profiles can be configured as options when setting up MVC pages or Razor Pages. Values found in a referenced cache profile are used as the defaults by the . Any properties specified on the attribute override the referenced cache profile values. -The following example shows a 30 second cache profile: +The following example shows a 30-second cache profile: [!code-csharp[](response/samples/6.x/WebRC/Program.cs?name=snippet2&highlight=5-13,22)] @@ -172,26 +174,22 @@ The resulting header response by the `Default30` cache profile includes: Cache-Control: public,max-age=30 ``` -The [`[ResponseCache]`](xref:Microsoft.AspNetCore.Mvc.ResponseCacheAttribute) attribute can be applied to: +You can apply the [[ResponseCache](xref:Microsoft.AspNetCore.Mvc.ResponseCacheAttribute)] attribute to Razor Pages, MVC controllers, and MVC action methods. -* Razor Pages: Attributes can't be applied to handler methods. Browsers used with UI apps prevent response caching. -* MVC controllers. -* MVC action methods: Method-level attributes override the settings specified in class-level attributes. +In Razor Pages, you can't apply attributes to handler methods because browsers used with UI apps prevent response caching. In an MVC action method, the method-level attributes override the settings specified in class-level attributes. The following code applies the `[ResponseCache]` attribute at the controller level and method level: [!code-csharp[](response/samples/6.x/WebRC/Controllers/TimeController.cs?name=snippet4&highlight=2,17)] -## Additional resources +## Related content + +* [Storing Responses in Caches - RFC 9111: HTTP Caching (Section 3)](https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-in-caches) +* [Cache-Control - RFC 9111: HTTP Caching (Section 5.2)](https://www.rfc-editor.org/rfc/rfc9111.html#field.cache-control) +* [Cache in-memory in ASP.NET Core](xref:performance/caching/memory) +* [Distributed caching in ASP.NET Core](xref:performance/caching/distributed) +* [Response caching middleware in ASP.NET Core](xref:performance/caching/middleware) -* [Storing Responses in Caches](https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-in-caches) -* [Cache-Control](https://www.rfc-editor.org/rfc/rfc9111.html#field.cache-control) -* -* -* -* -* -* :::moniker-end :::moniker range="< aspnetcore-6.0" @@ -391,4 +389,5 @@ Cache-Control: public,max-age=30 * * * + :::moniker-end From 8de2c298924d3785e2838cdc953da16e75c0f7b9 Mon Sep 17 00:00:00 2001 From: "Beth-Anne Harvey (AQUENT LLC)" <28070425+GitHubber17@users.noreply.github.com> Date: Thu, 30 Apr 2026 23:21:04 -0700 Subject: [PATCH 2/2] edits --- aspnetcore/performance/caching/memory.md | 4 ++-- aspnetcore/performance/caching/output.md | 7 +++---- aspnetcore/performance/caching/response.md | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/aspnetcore/performance/caching/memory.md b/aspnetcore/performance/caching/memory.md index b8d44067601a..201daf07bf34 100644 --- a/aspnetcore/performance/caching/memory.md +++ b/aspnetcore/performance/caching/memory.md @@ -77,7 +77,7 @@ The current time and the cached time are displayed: :::code language="cshtml" source="memory/samples/6.x/CachingMemorySample/Pages/Index.cshtml" id="snippet_CacheCurrentDateTime"::: -The following code uses the `Set` extension method to cache data for a relative time without : +The following code uses the `Set` extension method to cache data for a relative time without : :::code language="csharp" source="memory/samples/6.x/CachingMemorySample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGetCacheRelative"::: @@ -107,7 +107,7 @@ The preceding code guarantees the data isn't cached longer than the absolute tim ## Create MemoryCacheEntryOptions for an entry -The following example demonstrates how to create for an entry. The code completes the following tasks: +The following example demonstrates how to create for an entry. The code completes the following tasks: * Sets the cache priority to . diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index b1b78ef1e6b7..e464671a675d 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -26,13 +26,12 @@ The code examples refer to a [Gravatar class](https://github.com/dotnet/AspNetCo ## Add the middleware to the app -Add the output caching middleware to the service collection by calling the method. +Add the output caching middleware to the service collection by calling the method. For example: -Add the middleware to the request processing pipeline by calling the method. +:::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies4" highlight="1"::: -For example: +Add the middleware to the request processing pipeline by calling the method. For example: -:::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="policies4" highlight="1"::: :::code language="csharp" source="~/performance/caching/output/samples/7.x/Program.cs" id="snippet_use" highlight="5"::: Calling the `AddOutputCache`and `UseOutputCache` methods doesn't start caching behavior, it makes caching available. To make the app cache responses, caching must be configured as described in the following sections. diff --git a/aspnetcore/performance/caching/response.md b/aspnetcore/performance/caching/response.md index 95778494aca2..883456a268d1 100644 --- a/aspnetcore/performance/caching/response.md +++ b/aspnetcore/performance/caching/response.md @@ -152,7 +152,7 @@ The following example shows the headers produced by setting the