You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The behavior change is already captured in the breaking-changes docset (breaking-changes/11/response-compression-always-vary.md). The gap is in the evergreen how-to: performance/response-compression.md has an "Add the Vary header" section whose text still says the middleware adds Vary "when the response is compressed" — the exact condition that changed. A reader on the how-to page gets the pre-.NET-11 story with no pointer to the new always-emit behavior. Close that with a version-scoped note plus a cross-link.
This is a behavior change on an existing middleware with no new API, so the element below names the prior behavior explicitly.
✅ Coverage status summary
Legend: ✅ already documented · ✏️ update needed · 🟣 could not determine
#
Feature element from What's New
Status
Where
1
The behavior change itself — a dedicated breaking-change article explaining that Vary: Accept-Encoding is now always appended
The how-to's "Add the Vary header" section still describes the old, compression-conditional behavior ("automatically when the response is compressed") and doesn't mention the .NET 11 always-emit change
Prior behavior (element 2's contrast): Vary: Accept-Encoding was added only when the middleware actually compressed the body
✏️
Same insertion — the note must state the old condition so the change is legible
4
Motivation: correct cache keys for shared caches/CDNs so a compressed variant isn't served to a client that didn't request that encoding
✏️
Same insertion (one sentence of rationale)
🔢 Version applicability
Applies to:CURRENT-ONLY Target moniker:>= aspnetcore-11.0 Earlier versions affected: None — the always-emit behavior ships in .NET 11 (PR dotnet/aspnetcore#55092, issue dotnet/aspnetcore#48008). The existing 6.0-scoped paragraph stays correct for 6.0–10.0.
Article
monikerRange
Moniker state
performance/response-compression.md
(no front-matter monikerRange; article is fully zoned inline)
State D — the insertion point is inside a :::moniker range=">= aspnetcore-6.0" zone spanning L227–L269. Adding an 11.0-only note requires the four-directive split: close >= aspnetcore-6.0, open >= aspnetcore-11.0, add the note, close it, reopen >= aspnetcore-6.0. The pre-existing 6.0 paragraph is left intact because it's accurate for 6.0–10.0.
The insertion point is not inside any # [Tab](#tab/...) group, so no tab-nesting hazard applies.
📋 Coverage gap summary
A developer configuring response compression reads performance/response-compression.md, reaches "Add the Vary header," and is told the middleware adds Vary "automatically when the response is compressed." In .NET 11 that's no longer the whole story: the middleware appends Vary: Accept-Encoding to every response it processes (when compression is enabled), including responses whose body it doesn't compress. A reader troubleshooting unexpected Vary headers on uncompressed responses — or reasoning about CDN cache variants — finds nothing here explaining it. The breaking-changes article has the full story, but nobody on the how-to page is sent there.
Feature announced in What's New:
The response compression middleware now appends Vary: Accept-Encoding to every response that passes through it, including responses for which it didn't compress the body. This gives downstream caches more correct cache keys.
Product source confirms the behavior: in ResponseCompressionBody.cs (ShouldCompressResponseCommon, L204–L227), the Vary: Accept-Encoding header is appended based on whether the response is a candidate for compression (a compressible content type), decoupled from whether a matching provider was actually selected for the request's Accept-Encoding. That's why the header now appears even when no encoding is applied.
Target article uids:(none — performance/response-compression.md has no uid in front matter; link by relative path)
📝 Proposed changes
✏️ 1. Update — response-compression.md, add a >= aspnetcore-11.0 note in "Add the Vary header" (State D split)
Applies to:>= aspnetcore-11.0 Location:Lines 251–255 — after the existing Vary paragraph (L253) and before the [!INCLUDE...] (L255), inside the >= aspnetcore-6.0 zone (L227–L269).
Before (lines 251–255):
## Add the Vary header
When responses are compressed based on the [Accept-Encoding request header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Accept-Encoding), there can be uncompressed and multiple compressed versions of the response. To instruct client and proxy caches that multiple versions exist and should be stored, the `Vary` header is added with an `Accept-Encoding` value. The response middleware [adds the 'Vary' header](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs#L198-L241) in the _ResponseCompressionBody.cs_ file automatically when the response is compressed.
[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)]
After:
## Add the Vary header
When responses are compressed based on the [Accept-Encoding request header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Accept-Encoding), there can be uncompressed and multiple compressed versions of the response. To instruct client and proxy caches that multiple versions exist and should be stored, the `Vary` header is added with an `Accept-Encoding` value. The response middleware [adds the 'Vary' header](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/ResponseCompression/src/ResponseCompressionBody.cs#L198-L241) in the _ResponseCompressionBody.cs_ file automatically when the response is compressed.
:::moniker-end
:::moniker range=">= aspnetcore-11.0"
> [!NOTE]> In .NET 11 and later, the response compression middleware adds `Vary: Accept-Encoding` even to responses whose body it doesn't compress—for example, when the content type isn't configured for compression, or the client didn't request a supported encoding. In earlier versions the header was added only when the response was actually compressed. The broader behavior gives shared caches and CDNs a correct cache key so a stored compressed response isn't served to a client that didn't request that encoding. If the response already lists `Accept-Encoding` in its `Vary` header, the middleware doesn't add a duplicate. For details and mitigation, see [Response compression always emits Vary: Accept-Encoding](../breaking-changes/11/response-compression-always-vary.md).:::moniker-end
:::moniker range=">= aspnetcore-6.0"
[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)]
Rationale: The existing paragraph is accurate for 6.0–10.0, so it stays under the >= aspnetcore-6.0 zone unchanged. The .NET 11 clarification is scoped to >= aspnetcore-11.0 via a four-directive split and cross-links the breaking-change article for mitigation guidance, avoiding duplication.
✅ 2. Update — TOC
No TOC change required. Both articles already exist in the TOC; the edit adds a note to one.
✅ Action plan
Confirm element 1 (breaking-change article) — already published and accurate.
Apply change 1 as a State D four-directive split; verify the >= aspnetcore-6.0 zone that opened at L227 still closes exactly once at L269 after the edit (net-zero balance).
Confirm the relative link ../breaking-changes/11/response-compression-always-vary.md resolves (neither article has a uid, so xref isn't available).
Build and confirm the moniker zones render and the note appears only under 11.0.
⚠️ Review considerations
Don't rewrite the 6.0 paragraph. It's tempting to "fix" the "when the response is compressed" wording in place, but that sentence is correct for 6.0–10.0. Correcting it globally would misstate older versions. The moniker-scoped note is the right tool.
State D balance. This is one clean split and no other issue in this .NET 11 coverage sweep edits this file, so the combined balance is simply the file's existing balance plus 0. (Contrast v11 update: OpenAPI 3.2.0 support (Microsoft.OpenApi 3.x breaking change) #37706, where three independent splits in customize-openapi.md had to compose and must be applied bottom-up.)
Product link uses the pinned SHA; the existing in-article link points at main#L198-L241 (unpinned) — left as-is since it's pre-existing content, but this issue's evidence link is pinned to 1fcd...#L204-L227.
Target repository:
dotnet/AspNetCore.DocsAnalyzed at commit:
4986136881f2bbf1879f10106467769df5a49932Product source verified at:
dotnet/aspnetcore@1fcd7ef305697a1888f3ede076010350ae9f4f8dSource release note: Response compression always emits Vary: Accept-Encoding
🎯 Goal
The behavior change is already captured in the breaking-changes docset (
breaking-changes/11/response-compression-always-vary.md). The gap is in the evergreen how-to:performance/response-compression.mdhas an "Add the Vary header" section whose text still says the middleware addsVary"when the response is compressed" — the exact condition that changed. A reader on the how-to page gets the pre-.NET-11 story with no pointer to the new always-emit behavior. Close that with a version-scoped note plus a cross-link.This is a behavior change on an existing middleware with no new API, so the element below names the prior behavior explicitly.
✅ Coverage status summary
Legend: ✅ already documented · ✏️ update needed · 🟣 could not determine
Vary: Accept-Encodingis now always appendedbreaking-changes/11/response-compression-always-vary.mdperformance/response-compression.mdL251–L255Vary: Accept-Encodingwas added only when the middleware actually compressed the body🔢 Version applicability
Applies to:
CURRENT-ONLYTarget moniker:
>= aspnetcore-11.0Earlier versions affected: None — the always-emit behavior ships in .NET 11 (PR dotnet/aspnetcore#55092, issue dotnet/aspnetcore#48008). The existing 6.0-scoped paragraph stays correct for 6.0–10.0.
monikerRangeperformance/response-compression.mdmonikerRange; article is fully zoned inline):::moniker range=">= aspnetcore-6.0"zone spanning L227–L269. Adding an 11.0-only note requires the four-directive split: close>= aspnetcore-6.0, open>= aspnetcore-11.0, add the note, close it, reopen>= aspnetcore-6.0. The pre-existing 6.0 paragraph is left intact because it's accurate for 6.0–10.0.The insertion point is not inside any
# [Tab](#tab/...)group, so no tab-nesting hazard applies.📋 Coverage gap summary
A developer configuring response compression reads
performance/response-compression.md, reaches "Add the Vary header," and is told the middleware addsVary"automatically when the response is compressed." In .NET 11 that's no longer the whole story: the middleware appendsVary: Accept-Encodingto every response it processes (when compression is enabled), including responses whose body it doesn't compress. A reader troubleshooting unexpectedVaryheaders on uncompressed responses — or reasoning about CDN cache variants — finds nothing here explaining it. The breaking-changes article has the full story, but nobody on the how-to page is sent there.Feature announced in What's New:
Product source confirms the behavior: in
ResponseCompressionBody.cs(ShouldCompressResponseCommon, L204–L227), theVary: Accept-Encodingheader is appended based on whether the response is a candidate for compression (a compressible content type), decoupled from whether a matching provider was actually selected for the request'sAccept-Encoding. That's why the header now appears even when no encoding is applied.Breaking change: Yes — documented at
breaking-changes/11/response-compression-always-vary.md. The how-to note should cross-link it rather than restate the mitigation.📁 Affected files
performance/response-compression.mdTarget article uids: (none —
performance/response-compression.mdhas nouidin front matter; link by relative path)📝 Proposed changes
✏️ 1. Update —
response-compression.md, add a>= aspnetcore-11.0note in "Add the Vary header" (State D split)Applies to:
>= aspnetcore-11.0Location: Lines 251–255 — after the existing Vary paragraph (L253) and before the
[!INCLUDE...](L255), inside the>= aspnetcore-6.0zone (L227–L269).Before (lines 251–255):
After:
Rationale: The existing paragraph is accurate for 6.0–10.0, so it stays under the
>= aspnetcore-6.0zone unchanged. The .NET 11 clarification is scoped to>= aspnetcore-11.0via a four-directive split and cross-links the breaking-change article for mitigation guidance, avoiding duplication.✅ 2. Update — TOC
No TOC change required. Both articles already exist in the TOC; the edit adds a note to one.
✅ Action plan
>= aspnetcore-6.0zone that opened at L227 still closes exactly once at L269 after the edit (net-zero balance).../breaking-changes/11/response-compression-always-vary.mdresolves (neither article has auid, so xref isn't available).customize-openapi.mdhad to compose and must be applied bottom-up.)main#L198-L241(unpinned) — left as-is since it's pre-existing content, but this issue's evidence link is pinned to1fcd...#L204-L227.🔗 References
breaking-changes/11/response-compression-always-vary.mdperformance/response-compression.mdL251–L255src/Middleware/ResponseCompression/src/ResponseCompressionBody.csL204–L227 —Varyappended based on compression candidacy.