From 3ef88bfcbdbe12be396b78312859897260d48032 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Mon, 1 Aug 2022 16:19:14 -0700 Subject: [PATCH 1/9] draft --- aspnetcore/includes/response-caching-mid.md | 4 +- aspnetcore/performance/caching/output.md | 153 ++++++++++++++++++ .../caching/output/samples/7.x/Gravatar.cs | 17 ++ .../output/samples/7.x/OCMinimal.csproj | 14 ++ .../caching/output/samples/7.x/Program.cs | 126 +++++++++++++++ .../samples/7.x/appsettings.Development.json | 8 + .../output/samples/7.x/appsettings.json | 9 ++ aspnetcore/performance/caching/overview.md | 28 +++- 8 files changed, 355 insertions(+), 4 deletions(-) create mode 100644 aspnetcore/performance/caching/output.md create mode 100644 aspnetcore/performance/caching/output/samples/7.x/Gravatar.cs create mode 100644 aspnetcore/performance/caching/output/samples/7.x/OCMinimal.csproj create mode 100644 aspnetcore/performance/caching/output/samples/7.x/Program.cs create mode 100644 aspnetcore/performance/caching/output/samples/7.x/appsettings.Development.json create mode 100644 aspnetcore/performance/caching/output/samples/7.x/appsettings.json diff --git a/aspnetcore/includes/response-caching-mid.md b/aspnetcore/includes/response-caching-mid.md index 56c1d9234cef..43bd7e43268d 100644 --- a/aspnetcore/includes/response-caching-mid.md +++ b/aspnetcore/includes/response-caching-mid.md @@ -1,7 +1,7 @@ The Response caching middleware: * 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 is being considered for the next version of ASP.NET Core, which will benefit UI apps. With output caching, configuration decides what should be cached independently of HTTP headers. For more information, see [this GitHub issue](https://github.com/dotnet/aspnetcore/issues/27387). +* 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-caching-middleware), which is available in ASP.NET Core 7 Preview, 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. -Use [Fiddler](https://www.telerik.com/fiddler), [Postman](https://www.getpostman.com/), 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) \ No newline at end of file +To test response caching, use [Fiddler](https://www.telerik.com/fiddler), [Postman](https://www.getpostman.com/), 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). diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md new file mode 100644 index 000000000000..5b0fcce7fedf --- /dev/null +++ b/aspnetcore/performance/caching/output.md @@ -0,0 +1,153 @@ +--- +title: Output caching middleware in ASP.NET Core +author: tdykstra +description: Learn how to configure and use output caching middleware in ASP.NET Core. +monikerRange: '>= aspnetcore-7.0' +ms.author: riande +ms.custom: mvc +ms.date: 08/12/2022 +uid: performance/caching/output +--- +# Output caching middleware in ASP.NET Core + +By [Tom Dykstra](https://github.com/tdykstra) + +:::moniker range=">= aspnetcore-7.0" + +This article explains how to configure [output caching middleware](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs) 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 supports use in all types of ASP.NET Core apps: Minimal API, Web API with controllers, MVC, and Razor Pages. The sample app is a Minimal API, but every caching feature it illustrates is also supported in the other app types. + +## Add the middleware to the app + +Add the output caching middleware to the service collection by calling . + +Add the middleware to the request processing pipeline by calling . + +> [!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`. +> * Calling `AddOutputCache`and `UseOutputCache` doesn't start caching behavior. It makes caching available, but the actual caching behavior must be configured as shown in the following sections. + +## Configure one endpoint or page + +For minimal API apps, configure an endpoint to do caching by calling `CacheOutput()` or by applying the `[OutputCache]` attribute, as shown in the following examples: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="oneendpointl"::: + +For apps with controllers, apply the `[OutputCache]` attribute to the action method. For Razor Pages apps, apply the attribute to the Razor page class. + +## Configure multiple endpoints or pages + +Create *policies* when calling `AddOutputCaching` 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 you don't explicitly configure an expiration time, it's 1 minute. + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="2"::: + +The following highlighted code creates two policies, each specifying a different expiration time. Selected endpoints can use the 20 second expiration, and others can use the 30 second expiration. + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="3-4"::: + +You can select a policy for an endpoint when calling the `CacheOutput` method or using the `[OutputCache]` attribute: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="selectpolicies"::: + +For apps with controllers, apply the `[OutputCache]` attribute to the action method. For Razor Pages apps, apply the attribute to the Razor page class. + +## Default output caching policy + +By default, output caching follows these rules + +* Only HTTP 200 responses are cached. +* Only HTTP GET or HEAD requests are cached. +* Responses that set cookies aren't cached. +* Responses to authenticated requests aren't cached. + +The following code applies all of the default caching rules to all of an app's endpoints: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="[policies3]"::: + +The following code removes these defaults while applying caching to all of an app's endpoints: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="[policies4]"::: + + +You can override these defaults. + +## Specify the cache key + +By default, every part of the URL is included as the key to a cache entry -- that is, the scheme, host, port, path, and query string. However, you might want to explicitly control the cache key. For example, suppose you have an endpoint that returns a unique response for each unique value of the `culture` query string. Variation in other parts of the URL, such as other query strings, shouldn't result in different cache entries. You can specify such rules in a policy, as shown in the following highlighted code: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies" highlight="5"::: + +You can then select the `VaryByQuery` policy for an endpoint: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="selectquery"::: + +Here are the options for controlling the cache key: + +* `VaryByQuery` - Specify one or more query string names to act as the cache key. +* `VaryByHeader` - Specify one or more HTTP headers to act as the cache key. +* `VaryByValue` - Specify a value to act as 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. + + :::code language="csharp" source="output/samples/7.x/Program.cs" id="varybyvalue"::: + +## 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. + +The following code illustrates the use of an `Etag` header to enable cache revalidation. If the client sends an `If-None-Match` header with the etag value of an earlier response, and the cache entry is fresh, the server returns 304 instead of the full response: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="etag"::: + +If the client sends an `If-None-Match` header with the etag value and the cache entry isn't expired, the server returns 304 instead of the full response. + +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. + +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 code creates a pair of endpoints whose URLs begin with "blog", and tags them "tag-blog": + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="tagendpoint"::: + +An alternative way to assign tags for the same pair of endpoints is to define a base policy that applies to endpoints that begin with `blog`: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies2" highlight="3-5"::: + +Another alternative is to call `MapGroup`: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="taggroup"::: + +In the preceding tag assignment examples, both endpoints are identified by the `tag-blog` tag. You can then evict the cache entries for those endpoints with a single statement that references that tag: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="evictbytag"::: + +With this code, an HTTP POST request sent to `https://localhost:/purge/tag-blog` will evict 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: + +:::code language="csharp" source="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. + +## Disable resource locking + +By default, resource locking is enabled to mitigate the risk of [cache stampede and thundering herd](xref:performance/caching/overview#output-caching). + +To disable resource locking, set `AllowLocking` to `false`, as shown in the following example: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies2" highlight="8"::: + +:::code language="csharp" source="output/samples/7.x/Program.cs" id="selectnolock"::: + +## See also + +* +* +* +* + +:::moniker-end diff --git a/aspnetcore/performance/caching/output/samples/7.x/Gravatar.cs b/aspnetcore/performance/caching/output/samples/7.x/Gravatar.cs new file mode 100644 index 000000000000..08eccafbb9e6 --- /dev/null +++ b/aspnetcore/performance/caching/output/samples/7.x/Gravatar.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +public static class Gravatar +{ + public static async Task WriteGravatar(HttpContext context) + { + const string type = "monsterid"; // identicon, monsterid, wavatar + const int size = 200; + var hash = Guid.NewGuid().ToString("n"); + + context.Response.StatusCode = 200; + context.Response.ContentType = "text/html"; + await context.Response.WriteAsync($""); + await context.Response.WriteAsync($"
Generated at {DateTime.Now:hh:mm:ss.ff}
"); + } +} diff --git a/aspnetcore/performance/caching/output/samples/7.x/OCMinimal.csproj b/aspnetcore/performance/caching/output/samples/7.x/OCMinimal.csproj new file mode 100644 index 000000000000..c48bd6004bf7 --- /dev/null +++ b/aspnetcore/performance/caching/output/samples/7.x/OCMinimal.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/aspnetcore/performance/caching/output/samples/7.x/Program.cs b/aspnetcore/performance/caching/output/samples/7.x/Program.cs new file mode 100644 index 000000000000..f1fa4c8f07f0 --- /dev/null +++ b/aspnetcore/performance/caching/output/samples/7.x/Program.cs @@ -0,0 +1,126 @@ +#define Version4 +using Microsoft.AspNetCore.OutputCaching; +using System.Globalization; + +namespace OCMinimal; +public class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + builder.Services.AddAuthorization(); + +#if Version1 + // + builder.Services.AddOutputCache(options => + { + options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromSeconds(10))); + options.AddPolicy("Expire20", builder => builder.Expire(TimeSpan.FromSeconds(20))); + options.AddPolicy("Expire30", builder => builder.Expire(TimeSpan.FromSeconds(30))); + }); + // +#endif +#if Version2 + // + builder.Services.AddOutputCache(options => + { + options.AddBasePolicy(builder => builder + .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog")) + .Tag("tag-blog")); + options.AddBasePolicy(builder => builder.Tag("tag-all")); + options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture")); + options.AddPolicy("NoCache", builder => builder.NoCache()); + options.AddPolicy("NoLock", builder => builder.SetLocking(false)); + }); + // +#endif +#if Version3 + // + builder.Services.AddOutputCache(options => + { + options.AddBasePolicy(builder => builder.Cache()); + }); + // +#endif +#if Version4 + // + builder.Services.AddOutputCache(); + // +#endif + var app = builder.Build(); + + // Configure the HTTP request pipeline. + app.UseHttpsRedirection(); + app.UseOutputCache(); + app.UseAuthorization(); + + app.MapGet("/", Gravatar.WriteGravatar); + + // + app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput(); + app.MapGet("/attribute", [OutputCache] (context) => Gravatar.WriteGravatar(context)); + // + + // + app.MapGet("/20", Gravatar.WriteGravatar).CacheOutput("Expire20"); + app.MapGet("/30", [OutputCache(PolicyName = "Expire30")] (context) => Gravatar.WriteGravatar(context)); + // + + // + app.MapGet("/query", Gravatar.WriteGravatar).CacheOutput("Query"); + // + + // + app.MapGet("/varybyvalue", Gravatar.WriteGravatar) + .CacheOutput(c => c.VaryByValue((context) => + new KeyValuePair( + "time", (DateTime.Now.Second % 2) + .ToString(CultureInfo.InvariantCulture)))); + // + + // + app.MapGet("/etag", async (context) => + { + var etag = $"\"{Guid.NewGuid():n}\""; + context.Response.Headers.ETag = etag; + await Gravatar.WriteGravatar(context); + + }).CacheOutput(); + // + + + // + app.MapGet("/blog", Gravatar.WriteGravatar) + .CacheOutput(builder => builder.Tag("tag-blog")); ; + app.MapGet("/blog/post/{id}", Gravatar.WriteGravatar) + .CacheOutput(builder => builder.Tag("tag-blog")); ; + // + + // + var blog = app.MapGroup("blog") + .CacheOutput(builder => builder.Tag("tag-blog")); + blog.MapGet("/", Gravatar.WriteGravatar); + blog.MapGet("/post/{id}", Gravatar.WriteGravatar); + // + + // + blog.MapGet("/post/{id}", Gravatar.WriteGravatar) + .CacheOutput(x => x.Tag("tag-blog", "tag-blog-post-id")); + // + + // + app.MapPost("/purge/{tag}", async (IOutputCacheStore cache, string tag) => + { + await cache.EvictByTagAsync(tag, default); + }); + // + + // + app.MapGet("/nolock", Gravatar.WriteGravatar).CacheOutput("NoLock"); + // + + app.Run(); + } +} diff --git a/aspnetcore/performance/caching/output/samples/7.x/appsettings.Development.json b/aspnetcore/performance/caching/output/samples/7.x/appsettings.Development.json new file mode 100644 index 000000000000..0c208ae9181e --- /dev/null +++ b/aspnetcore/performance/caching/output/samples/7.x/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/aspnetcore/performance/caching/output/samples/7.x/appsettings.json b/aspnetcore/performance/caching/output/samples/7.x/appsettings.json new file mode 100644 index 000000000000..10f68b8c8b4f --- /dev/null +++ b/aspnetcore/performance/caching/output/samples/7.x/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/aspnetcore/performance/caching/overview.md b/aspnetcore/performance/caching/overview.md index 5cd571a0f7ec..6aa885ac1f2b 100644 --- a/aspnetcore/performance/caching/overview.md +++ b/aspnetcore/performance/caching/overview.md @@ -4,7 +4,7 @@ author: rick-anderson description: Overview of caching in ASP.NET Core monikerRange: '>= aspnetcore-3.1' ms.author: riande -ms.date: 1/11/2022 +ms.date: 08/12/2022 uid: performance/caching/overview --- # Overview of caching in ASP.NET Core @@ -37,4 +37,28 @@ For more information, see Date: Wed, 26 Oct 2022 15:35:28 -0700 Subject: [PATCH 2/9] add to toc --- aspnetcore/toc.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 7fcd3334f06f..72837880a6e7 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -1490,6 +1490,8 @@ items: uid: performance/caching/memory - name: Distributed caching uid: performance/caching/distributed + - name: Output caching + uid: performance/caching/output - name: Response caching uid: performance/caching/response - name: Response caching middleware From 92921b747013a41b112e44fb834f8e0286f26ad9 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 26 Oct 2022 15:40:36 -0700 Subject: [PATCH 3/9] fix link --- aspnetcore/includes/response-caching-mid.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/includes/response-caching-mid.md b/aspnetcore/includes/response-caching-mid.md index 43bd7e43268d..9d4165b380bc 100644 --- a/aspnetcore/includes/response-caching-mid.md +++ b/aspnetcore/includes/response-caching-mid.md @@ -1,7 +1,7 @@ The Response caching middleware: * 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-caching-middleware), which is available in ASP.NET Core 7 Preview, benefits UI apps. With output caching, configuration decides what should be cached independently of HTTP headers. +* 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 ASP.NET Core 7.0, 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. To test response caching, use [Fiddler](https://www.telerik.com/fiddler), [Postman](https://www.getpostman.com/), 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). From a621df8651bab3705b42e3a5bac59f4b87d0318b Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 26 Oct 2022 15:45:47 -0700 Subject: [PATCH 4/9] remove link --- aspnetcore/performance/caching/output.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index 5b0fcce7fedf..449d476d34d2 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -5,7 +5,7 @@ description: Learn how to configure and use output caching middleware in ASP.NET monikerRange: '>= aspnetcore-7.0' ms.author: riande ms.custom: mvc -ms.date: 08/12/2022 +ms.date: 10/26/2022 uid: performance/caching/output --- # Output caching middleware in ASP.NET Core @@ -14,7 +14,7 @@ By [Tom Dykstra](https://github.com/tdykstra) :::moniker range=">= aspnetcore-7.0" -This article explains how to configure [output caching middleware](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs) in an ASP.NET Core app. For an introduction to output caching, see [Output caching](xref:performance/caching/overview#output-caching). +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 supports use in all types of ASP.NET Core apps: Minimal API, Web API with controllers, MVC, and Razor Pages. The sample app is a Minimal API, but every caching feature it illustrates is also supported in the other app types. From 2be68ad8ad7d98dcd2c0971bcb98ff88334352b6 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Wed, 26 Oct 2022 16:24:54 -0700 Subject: [PATCH 5/9] fix snippet links --- aspnetcore/performance/caching/output.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index 449d476d34d2..34aa2ca6349c 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -20,9 +20,9 @@ The output caching middleware supports use in all types of ASP.NET Core apps: Mi ## 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 . -Add the middleware to the request processing pipeline by calling . +Add the middleware to the request processing pipeline by calling . > [!NOTE] > * In apps that use [CORS middleware](xref:security/cors), `UseOutputCache` must be called after . @@ -33,7 +33,7 @@ Add the middleware to the request processing pipeline by calling Date: Wed, 26 Oct 2022 17:13:52 -0700 Subject: [PATCH 6/9] proofread updates --- aspnetcore/performance/caching/output.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index 34aa2ca6349c..443db6684d5b 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -41,13 +41,13 @@ For apps with controllers, apply the `[OutputCache]` attribute to the action met Create *policies* when calling `AddOutputCaching` 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 you don't explicitly configure an expiration time, it's 1 minute. +The following highlighted code configures caching for all of the app's endpoints, with expiration time of 10 seconds. If you don't explicitly configure an expiration time, it's one minute. -:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="2"::: +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="3"::: The following highlighted code creates two policies, each specifying a different expiration time. Selected endpoints can use the 20 second expiration, and others can use the 30 second expiration. -:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="3-4"::: +:::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="4-5"::: You can select a policy for an endpoint when calling the `CacheOutput` method or using the `[OutputCache]` attribute: @@ -85,14 +85,16 @@ You can then select the `VaryByQuery` policy for an endpoint: :::code language="csharp" source="output/samples/7.x/Program.cs" id="selectquery"::: -Here are the options for controlling the cache key: +Here are some of the options for controlling the cache key: -* `VaryByQuery` - Specify one or more query string names to act as the cache key. -* `VaryByHeader` - Specify one or more HTTP headers to act as the cache key. -* `VaryByValue` - Specify a value to act as 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. +* - Specify one or more query string names to act as the cache key. +* - Specify one or more HTTP headers to act as the cache key. +* - Specify a value to act as 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. :::code language="csharp" source="output/samples/7.x/Program.cs" id="varybyvalue"::: +For more options, see the class. + ## 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. @@ -101,8 +103,6 @@ The following code illustrates the use of an `Etag` header to enable cache reval :::code language="csharp" source="output/samples/7.x/Program.cs" id="etag"::: -If the client sends an `If-None-Match` header with the etag value and the cache entry isn't expired, the server returns 304 instead of the full response. - 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. 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. From 676fcb6605012aa5fd9fec11beae5007cd05de16 Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Thu, 27 Oct 2022 17:20:53 -0700 Subject: [PATCH 7/9] Apply suggestions from code review Co-authored-by: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com> --- aspnetcore/includes/response-caching-mid.md | 2 +- aspnetcore/performance/caching/output.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/aspnetcore/includes/response-caching-mid.md b/aspnetcore/includes/response-caching-mid.md index 9d4165b380bc..3ba86a24eee0 100644 --- a/aspnetcore/includes/response-caching-mid.md +++ b/aspnetcore/includes/response-caching-mid.md @@ -1,7 +1,7 @@ The Response caching middleware: * 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 ASP.NET Core 7.0, benefits UI apps. With output caching, configuration decides what should be cached independently of HTTP headers. +* 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 ASP.NET Core 7.0 and 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. To test response caching, use [Fiddler](https://www.telerik.com/fiddler), [Postman](https://www.getpostman.com/), 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). diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index 443db6684d5b..5883fd77a076 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -27,11 +27,11 @@ Add the middleware to the request processing pipeline by calling [!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`. -> * Calling `AddOutputCache`and `UseOutputCache` doesn't start caching behavior. It makes caching available, but the actual caching behavior must be configured as shown in the following sections. +> * Calling `AddOutputCache`and `UseOutputCache` doesn't start caching behavior, it makes caching available. Caching response data must be configured as shown in the following sections. ## Configure one endpoint or page -For minimal API apps, configure an endpoint to do caching by calling `CacheOutput()` or by applying the `[OutputCache]` attribute, as shown in the following examples: +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: :::code language="csharp" source="output/samples/7.x/Program.cs" id="oneendpoint"::: @@ -41,7 +41,7 @@ For apps with controllers, apply the `[OutputCache]` attribute to the action met Create *policies* when calling `AddOutputCaching` 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 you don't explicitly configure an expiration time, it's one minute. +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. :::code language="csharp" source="output/samples/7.x/Program.cs" id="policies1" highlight="3"::: @@ -57,7 +57,7 @@ For apps with controllers, apply the `[OutputCache]` attribute to the action met ## Default output caching policy -By default, output caching follows these rules +By default, output caching follows these rules: * Only HTTP 200 responses are cached. * Only HTTP GET or HEAD requests are cached. @@ -77,7 +77,7 @@ You can override these defaults. ## Specify the cache key -By default, every part of the URL is included as the key to a cache entry -- that is, the scheme, host, port, path, and query string. However, you might want to explicitly control the cache key. For example, suppose you have an endpoint that returns a unique response for each unique value of the `culture` query string. Variation in other parts of the URL, such as other query strings, shouldn't result in different cache entries. You can specify such rules in a policy, as shown in the following highlighted code: +By default, every part of the URL is included as the key to a cache entry, that is, the scheme, host, port, path, and query string. However, you might want to explicitly control the cache key. For example, suppose you have an endpoint that returns a unique response for each unique value of the `culture` query string. Variation in other parts of the URL, such as other query strings, shouldn't result in different cache entries. You can specify such rules in a policy, as shown in the following highlighted code: :::code language="csharp" source="output/samples/7.x/Program.cs" id="policies2" highlight="7"::: @@ -99,7 +99,7 @@ For more options, see the Date: Tue, 1 Nov 2022 13:57:59 -0700 Subject: [PATCH 8/9] Apply suggestions from code review --- aspnetcore/performance/caching/output.md | 10 +++++----- aspnetcore/performance/caching/overview.md | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/aspnetcore/performance/caching/output.md b/aspnetcore/performance/caching/output.md index 5883fd77a076..d1e794740168 100644 --- a/aspnetcore/performance/caching/output.md +++ b/aspnetcore/performance/caching/output.md @@ -16,7 +16,7 @@ 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 supports use in all types of ASP.NET Core apps: Minimal API, Web API with controllers, MVC, and Razor Pages. The sample app is a Minimal API, but every caching feature it illustrates is also supported in the other app types. +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. The sample app is a Minimal API, but every caching feature it illustrates is also supported in the other app types. ## Add the middleware to the app @@ -77,7 +77,7 @@ You can override these defaults. ## Specify the cache key -By default, every part of the URL is included as the key to a cache entry, that is, the scheme, host, port, path, and query string. However, you might want to explicitly control the cache key. For example, suppose you have an endpoint that returns a unique response for each unique value of the `culture` query string. Variation in other parts of the URL, such as other query strings, shouldn't result in different cache entries. You can specify such rules in a policy, as shown in the following highlighted code: +By default, every part of the URL is included as the key to a cache entry, that is, the scheme, host, port, path, and query string. However, you might want to explicitly control the cache key. For example, suppose you have an endpoint that returns a unique response only for each unique value of the `culture` query string. Variation in other parts of the URL, such as other query strings, shouldn't result in different cache entries. You can specify such rules in a policy, as shown in the following highlighted code: :::code language="csharp" source="output/samples/7.x/Program.cs" id="policies2" highlight="7"::: @@ -87,9 +87,9 @@ You can then select the `VaryByQuery` policy for an endpoint: Here are some of the options for controlling the cache key: -* - Specify one or more query string names to act as the cache key. -* - Specify one or more HTTP headers to act as the cache key. -* - Specify a value to act as 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. +* - 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. :::code language="csharp" source="output/samples/7.x/Program.cs" id="varybyvalue"::: diff --git a/aspnetcore/performance/caching/overview.md b/aspnetcore/performance/caching/overview.md index 6aa885ac1f2b..b49150afd107 100644 --- a/aspnetcore/performance/caching/overview.md +++ b/aspnetcore/performance/caching/overview.md @@ -43,14 +43,13 @@ For more information, see Date: Tue, 1 Nov 2022 14:07:02 -0700 Subject: [PATCH 9/9] fix list spacing --- aspnetcore/performance/caching/overview.md | 1 + 1 file changed, 1 insertion(+) diff --git a/aspnetcore/performance/caching/overview.md b/aspnetcore/performance/caching/overview.md index b49150afd107..7cb32e629d69 100644 --- a/aspnetcore/performance/caching/overview.md +++ b/aspnetcore/performance/caching/overview.md @@ -50,6 +50,7 @@ The output caching middleware enables caching of HTTP responses. Output caching * The cache storage medium is extensible. Memory is used by default. Response caching is limited to memory. + * You can programmatically invalidate selected cache entries. Response caching's dependence on HTTP headers leaves you with few options for invalidating cache entries.