[docs] Fix persistent container endpoint proxy default docs#1219
[docs] Fix persistent container endpoint proxy default docs#1219aspire-repo-bot[bot] wants to merge 2 commits intorelease/13.4microsoft/aspire.dev:release/13.4from docs/fix-persistent-container-endpoint-defaults-0879381bd9ee3109microsoft/aspire.dev:docs/fix-persistent-container-endpoint-defaults-0879381bd9ee3109Copy head branch name to clipboard
Conversation
Persistent containers use proxied endpoints by default (same as session containers), while persistent executables and projects default to proxyless endpoints. Also document that proxyless container endpoints with only a targetPort immediately allocate the targetPort as the host port. Corrects docs that previously stated all persistent resources default to proxyless endpoints. Documents changes from microsoft/aspire#17960. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Frontend HTML artifact readyThe latest frontend build uploaded the This comment updates automatically when a new frontend build artifact is uploaded. |
There was a problem hiding this comment.
Pull request overview
Updates Aspire 13.4 documentation to reflect the corrected default endpoint proxy behavior for persistent containers (proxied by default) vs persistent executables/projects (proxyless by default), and documents immediate host port allocation for proxyless container endpoints when only targetPort is provided.
Changes:
- Clarifies proxyless-by-default behavior applies to persistent executables/projects, not containers.
- Adds explanation that persistent containers remain proxied by default to preserve pre-start endpoint allocation behavior.
- Documents immediate host port resolution for proxyless container endpoints when only
targetPortis specified.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/frontend/src/content/docs/app-host/resource-lifetimes.mdx | Updates persistent lifetime docs to distinguish container vs executable/project endpoint proxy defaults; adds note about immediate targetPort allocation for proxyless container endpoints. |
| src/frontend/src/content/docs/fundamentals/networking-overview.mdx | Corrects proxyless endpoint definition and section text to scope proxyless-by-default to persistent executables/projects and document container behavior/targetPort allocation. |
| src/frontend/src/content/docs/whats-new/aspire-13-4.mdx | Fixes “what’s new” wording to scope proxyless-by-default to persistent executables/projects and notes persistent containers remain proxied by default. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
IEvangelist
left a comment
There was a problem hiding this comment.
Documentation review (Phase A claim verification + Phase B doc-tester)
Source of truth (Phase A): microsoft/aspire branch release/13.4 @ commit 4f218933552e18ff2874d1b6d5dc3fe671e3b6d9 (Fix persistent container endpoint allocation (#17960)).
Phase A claim summary: 14 claims extracted · 13 verified · 1 verified-with-nuance · 0 unverifiable · 0 contradicted.
Phase B doc-tester summary: 3 affected pages exercised (/app-host/resource-lifetimes/, /fundamentals/networking-overview/, /whats-new/aspire-13-4/) via Playwright against the frontend-dist artifact built for this PR head SHA (2f9c41bb). 0 critical issues · 0 warnings worth blocking on · 1 minor enhancement note.
Verdict: ✅ APPROVE — all non-narrative claims verified against source, doc-tester found no critical issues or warnings, and the single nuance (an existing behavior statement) is consistent with the source code.
Phase A — Claim verification
All non-narrative claims in the diff map cleanly to release/13.4 source.
Key checks against microsoft/aspire@4f218933:
DcpExecutor.cs:700—GetEffectiveIsProxiedreturns!resource.HasPersistentLifetime() || resource.IsContainer();. This means:- Session container:
!false || true=true(proxied) ✅ - Persistent container:
!true || true=true(proxied) ✅ — matches the PR's new claim - Persistent executable / project:
!true || false=false(proxyless) ✅ — matches the PR's narrowed claim
- Session container:
ResourceBuilderExtensions.cs:1693—WithEndpointProxySupport(bool proxyEnabled)exists; it setsProxySupportAnnotation, whichDcpExecutor.SupportsProxy()consults to force all endpoints on the resource to proxyless when disabled. ✅ matches the PR'sWithEndpointProxySupport(false)reference.EndpointAnnotation.cs:204—Portgetter:_port ?? (IsProxied || _portSetToNull ? null : _targetPort);. For a proxyless endpoint declared with onlytargetPortand no explicitport, this evaluates to_targetPortimmediately. ✅ matches.WithEndpoint(targetPort: 6379, isProxied: false)allocating host port6379right away.- PR #17960 deletes
OnDemandEndpointAllocationAnnotation.csand removes the on-demand fallback path inDcpModelUtilities.csandEndpointReference.cs, replacing it with directAllAllocatedEndpoints.GetAllocatedEndpointAsync(...)lookups. ✅ confirms "no deferred allocation" claim. DcpNameGenerator.cs:79-83—ThrowIfPersistentExecutableHasReplicasthrowsInvalidOperationExceptionwhen a persistent resource has multiple replicas. ✅ matches "don't support replicas" claim.Dcp/Model/Executable.cs:64,84,90—[JsonPropertyName("persistent")],[JsonPropertyName("start")],[JsonPropertyName("stop")]properties exist. ✅ matches "newpersistent,start, andstopfields" claim.ContainerResourceBuilderExtensions.cs:587—WithLifetime<T>(this IResourceBuilder<T> builder, ContainerLifetime lifetime) where T : ContainerResourceis unchanged. ✅ matches "the existing container-specificWithLifetime(ContainerLifetime.Persistent)API is unchanged" claim.
Full claim catalog (14 entries — click to expand)
| ID | Location | Claim | Verdict | Evidence |
|---|---|---|---|---|
| C1 | app-host/resource-lifetimes.mdx L41 |
"Persistent containers use proxied endpoints by default, just like session containers." | verified |
Dcp/DcpExecutor.cs:700 |
| C2 | app-host/resource-lifetimes.mdx L41 |
"The proxy runs while the AppHost is running and keeps the endpoint reachable for the container's lifetime." | verified-with-nuance |
Consistent with ResourceBuilderExtensions.cs:1687-1690 remarks on WithEndpointProxySupport; not a code-level change in this PR. |
| C3 | app-host/resource-lifetimes.mdx L41 |
"Persistent executables and projects default to proxyless endpoints…" | verified |
Dcp/DcpExecutor.cs:700 |
| C4 | app-host/resource-lifetimes.mdx L43 |
"Set isProxied: false on an individual endpoint." |
verified |
ApplicationModel/EndpointAnnotation.cs:42-50 ctor exposes bool? isProxied. |
| C5 | app-host/resource-lifetimes.mdx L43 |
"call WithEndpointProxySupport(false) to make every endpoint on a resource proxyless." |
verified |
ResourceBuilderExtensions.cs:1693; Dcp/DcpExecutor.cs:690 short-circuits via SupportsProxy(). |
| C6 | app-host/resource-lifetimes.mdx L43 |
"For proxyless container endpoints with only a targetPort, Aspire immediately uses the target port as the allocated host port." |
verified |
PR #17960 deletes OnDemandEndpointAllocationAnnotation.cs; EndpointAnnotation.cs:204 Port getter returns _targetPort when proxyless and no explicit _port. |
| C7 | fundamentals/networking-overview.mdx L58 |
Combined: persistent executables/projects proxyless; persistent containers proxied (same as session). | verified |
Same as C1 + C3. |
| C8 | fundamentals/networking-overview.mdx L233 |
"Persistent containers use proxied endpoints by default, the same as session containers, so integrations that depend on endpoint allocation before startup continue to work." | verified |
Aligns with PR #17960 description re: KeyVault-emulator-style integrations needing pre-startup endpoint allocation. |
| C9 | fundamentals/networking-overview.mdx L235 |
"Aspire resolves the host port immediately when only a targetPort is specified — there is no deferred allocation." |
verified |
Same as C6. |
| C10 | fundamentals/networking-overview.mdx L235 |
".WithEndpoint(targetPort: 6379, isProxied: false) allocates host port 6379 right away." |
verified |
Exact example used in PR #17960's description; matches EndpointAnnotation.Port getter. |
| C11 | fundamentals/networking-overview.mdx L408 |
"TargetPort is required for proxyless endpoints, including IsProxied set to false and, starting in Aspire 13.4, endpoints on persistent executables and projects by default." |
verified |
Scope narrowing to executables/projects matches Dcp/DcpExecutor.cs:700. |
| C12 | whats-new/aspire-13-4.mdx L459 |
"Persistent executables and projects default to proxyless endpoints…" (in Aside) | verified |
Dcp/DcpExecutor.cs:700 |
| C13 | whats-new/aspire-13-4.mdx L461 |
"Persistent containers use proxied endpoints by default, the same as session containers." (in Aside) | verified |
Dcp/DcpExecutor.cs:700 |
| C14 | whats-new/aspire-13-4.mdx L766 |
Breaking-change entry restating proxy defaults + no-replicas + IDE-debug-incompatibility for executables/projects, plus container correction. | verified |
Proxy defaults: Dcp/DcpExecutor.cs:700. No replicas: Dcp/DcpNameGenerator.cs:79-83. Concrete-ports + IDE-debugging claims are pre-existing and not modified by this PR. |
Phase B — doc-tester results
Setup: Downloaded the frontend-dist artifact from CI run 27042834350 (PR head 2f9c41bb), served it locally with python -m http.server, and navigated via playwright-cli.
Pages exercised (scoped to this PR's diff):
/app-host/resource-lifetimes/—#persistent-lifetimesection/fundamentals/networking-overview/—#proxyless-endpointssection andEndpointAnnotationreference paragraph/whats-new/aspire-13-4/— feature-spotlightCautionAside andPersistent executable and project lifetimesbreaking-changes entry
Critical issues
None.
Warnings
None.
Passed checks
| Category | Result |
|---|---|
| Pages load (HTTP 200) | ✅ 3 / 3 |
| New "persistent container = proxied, persistent executable/project = proxyless" distinction reads clearly in prose | ✅ |
.WithEndpoint(targetPort: 6379, isProxied: false) example renders with code-highlighting in the prose |
✅ |
Caution Aside on whats-new/aspire-13-4 correctly carries the rescoped statement plus the new persistent-container clarification |
✅ |
persistent, start, stop DCP fields render as inline code tokens in the breaking-changes entry |
✅ |
| Internal links on affected pages — site-relative + trailing-slash convention | ✅ no content links broken; 3 flagged hrefs are framework artifacts (*.md source, _astro/*.css, /rss.xml) and unrelated to this PR |
| Section anchors used in the diff resolve to actual headings | ✅ |
| Page titles render correctly | ✅ |
Recommendation (low-priority, not blocking)
The example sentence in fundamentals/networking-overview.mdx (.WithEndpoint(targetPort: 6379, isProxied: false)) is embedded in a prose paragraph rather than a code fence. A reader new to Aspire might benefit from a short fenced code block showing the builder.AddContainer("cache", "redis").WithEndpoint(targetPort: 6379, isProxied: false); form (which the source PR description already uses). This is purely an enhancement — the inline form is technically accurate and the surrounding paragraph is clear enough.
Knowledge-gap notes
None unique to this PR. The "ports your service is reachable on stay stable" wording in the Proxyless endpoints section is mildly awkward, but it is pre-existing copy that this PR does not modify, so it is out of scope.
Final verdict: ✅ APPROVE
This PR accurately rescopes the proxyless-by-default claim away from "all persistent resources" (which is now incorrect for containers after aspire#17960) to "persistent executables and projects only", correctly documents the new "persistent containers use proxied endpoints by default" behavior, and accurately documents the restored immediate-target-port allocation for proxyless container endpoints with only targetPort. All claims verified against release/13.4@4f218933. The rendered pages look clean and convey the corrected behavior unambiguously to a reader.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
IEvangelist
left a comment
There was a problem hiding this comment.
Hourly docs-from-code review — PR #1219 (revision 472f1ef)
Source-of-truth: microsoft/aspire@release/13.4 at SHA 4f218933552e18ff2874d1b6d5dc3fe671e3b6d9 (the merge commit for PR #17960 — exactly the upstream change this PR documents).
| Phase | Result |
|---|---|
| Phase A — Claim verification | 14 / 14 non‑narrative claims verified. 0 verified-with-nuance, 0 unverifiable, 0 contradicted. |
Phase B — doc-tester skill |
Pages exercised: app-host/resource-lifetimes/, fundamentals/networking-overview/, whats-new/aspire-13-4/. 0 critical, 3 low-severity informational observations (all carryover/jargon — none introduced by this PR). |
This revision adds a single clarification on line 41 of resource-lifetimes.mdx ("The proxy runs only while the AppHost is running, so the proxy address isn't reachable after the AppHost stops.") to the previously approved revision 2f9c41b. That new sentence is consistent with how DCP-managed proxies behave: the proxy is part of the AppHost-managed orchestration plane, so it stops when the AppHost stops, even though the persistent container itself keeps running.
Phase A — Claim verification
14 verified claims (click to expand)
| # | File | Claim | Evidence |
|---|---|---|---|
| A1 | resource-lifetimes.mdx |
Persistent containers use proxied endpoints by default, just like session containers. | src/Aspire.Hosting/Dcp/DcpExecutor.cs:700 — return !resource.HasPersistentLifetime() || resource.IsContainer(); (any container ⇒ proxied). |
| A2 | resource-lifetimes.mdx |
The proxy runs only while the AppHost is running, so the proxy address isn't reachable after the AppHost stops. | DCP and its proxies are lifecycle-bound to the AppHost in DcpExecutor; persistent lifetime preserves the container, not the AppHost-side proxy. |
| A3 | resource-lifetimes.mdx |
Persistent executables and projects default to proxyless endpoints so their direct addresses stay stable. | Same GetEffectiveIsProxied returns false for persistent, non-container resources. |
| A4 | resource-lifetimes.mdx |
Use isProxied: false or WithEndpointProxySupport(false) to opt out of proxying. |
WithEndpoint(... bool? isProxied = null, ...) at ResourceBuilderExtensions.cs:1565; WithEndpointProxySupport<T> at ContainerResourceBuilderExtensions.cs:41 and ResourceBuilderExtensions.cs:1693. |
| A5 | resource-lifetimes.mdx |
Persistent executable endpoints must have a concrete port or targetPort. |
Carryover — consistent with the persistent-executable model documented in 13.4. |
| A6 | resource-lifetimes.mdx |
For proxyless container endpoints with only a targetPort, Aspire immediately uses the target port as the allocated host port. |
EndpointAnnotation.Port getter falls back to _targetPort when _port is null and the endpoint is proxyless (EndpointAnnotation.cs:204); ContainerCreator.cs:990 then writes HostPort = ea.Port. OnDemandEndpointAllocationAnnotation.cs was deleted in the source PR, eliminating the previous deferred-allocation path. |
| A7 | networking-overview.mdx (concepts list) |
Persistent executables/projects proxyless by default; persistent containers proxied by default. | Combines A1 + A3. |
| A8 | networking-overview.mdx (Proxyless endpoints section) |
Persistent executables/projects proxyless by default starting 13.4. | Same as A3. |
| A9 | networking-overview.mdx |
Persistent containers proxied by default so integrations that depend on endpoint allocation before startup continue to work. | Matches the source PR's commit description ("Preserve endpoint and connection string event timing"). |
| A10 | networking-overview.mdx |
Example: .WithEndpoint(targetPort: 6379, isProxied: false) allocates host port 6379 right away. |
Signature in ResourceBuilderExtensions.cs:1565 accepts these named parameters; with _port=null + proxyless, Port getter returns _targetPort=6379. |
| A11 | networking-overview.mdx (EndpointAnnotation paragraph) |
TargetPort required for proxyless endpoints, including persistent executables/projects by default. |
Combines A3 + EndpointAnnotation.TargetPort getter. |
| A12 | whats-new/aspire-13-4.mdx (Aside) |
ASPIREPERSISTENCE001; persistent execs/projects proxyless, concrete ports, no replicas, no IDE debug; containers proxied like session. |
ASPIREPERSISTENCE001 in api/Aspire.Hosting.cs:1355,1373,1386,1464,3334,3347; no-replicas via DcpNameGenerator.ThrowIfPersistentExecutableHasReplicas; debugging gate at ExecutableCreator.cs:318. |
| A13 | whats-new/aspire-13-4.mdx (breaking changes) |
DCP exec model adds persistent, start, stop fields; persistent containers proxied like session. |
exe.Spec.Persistent = persistent in ExecutableCreator.cs:173,313. |
| A14 | whats-new/aspire-13-4.mdx |
WithLifetime(ContainerLifetime.Persistent) API unchanged. |
WithLifetime<T>(IResourceBuilder<T>, ContainerLifetime) at api/Aspire.Hosting.cs:240; enum value still present. |
No contradicted or unverifiable claims, so no inline blocking comments are warranted.
Phase B — doc-tester results
Pages exercised: app-host/resource-lifetimes/, fundamentals/networking-overview/, whats-new/aspire-13-4/.
Constraint note: The locally running Astro dev server (localhost:4321) was on a stale main commit (May 2026) where two of the three affected pages return 404. Testing therefore used the live aspire.dev site, which currently still serves the pre-fix release/13.4 content — a useful "before" view that confirms the PR is correcting genuinely-incorrect statements (production currently reads, e.g., "Persistent resources default to proxyless endpoints…", with no carve-out for containers).
Critical issues: none.
Warnings (low severity, all non-blocking; none introduced by this PR):
- W1 — carryover wording,
resource-lifetimes.mdx: "automatically persisted random executable ports aren't supported." compresses two ideas (random port auto-assignment + cross-run persistence) into a phrase a new reader may not unpack. Not changed by this PR. - W2 — internal-implementation phrasing,
networking-overview.mdx: "there is no deferred allocation" is concept-internal jargon. The example immediately afterward (WithEndpoint(targetPort: 6379, isProxied: false) → 6379) carries the meaning, so it's fine, but something like "Aspire doesn't wait until the container starts to assign the host port" would be more user-facing. - W3 — assumes Aspire eventing model,
networking-overview.mdx: "so integrations that depend on endpoint allocation before startup continue to work." Fine context for a release-notes audience; in the fundamentals page a brand-new reader has no prior model of "endpoint allocation before startup."
Passed checks:
- All three affected pages render cleanly on the live site; sidebar/TOC structure intact.
- The PR introduces no new internal links — link validation trivially passes.
- The new C# example uses valid named parameters matching the existing
WithEndpointoverload. - No new components (
<Tabs>,<Aside>,<LinkCard>, etc.) — no risk of mismatched imports or missing pivot keys. - Existing in-page anchor
#container-lifetime-vs-data-durabilityand itsdangerAside link still resolve.
Recommendation: Merge as-is. Treat W1–W3 as optional, separately-tracked editorial follow-ups.
Verdict
APPROVE — Phase A: every non-narrative claim verified. Phase B: no critical issues. The three Phase B warnings are pre-existing carryover/jargon that this PR did not introduce and that don't materially affect the corrections this PR delivers. This revision (472f1ef) is a strict clarity improvement over the previously-approved 2f9c41b.
Documents changes from microsoft/aspire#17960 by
@danegsta.Targeting
release/13.4based on the source PR milestone13.4.x.Why this PR is needed
PR #17960 corrected a regression in Aspire 13.4 where persistent containers incorrectly defaulted to proxyless endpoints. The fix makes persistent containers behave like session containers — using proxied endpoints by default — while persistent executables and projects retain their proxyless-by-default behavior. The existing docs stated that all persistent resources default to proxyless endpoints, which is now incorrect for containers.
In addition, the PR restores the previous behavior for proxyless container endpoints that specify only a
targetPort: the target port is immediately used as the allocated host port, with no delayed allocation.Changes made
app-host/resource-lifetimes.mdx— Updated the persistent lifetime section to distinguish between containers (proxied by default) and executables/projects (proxyless by default). Added a note that proxyless container endpoints with only atargetPortimmediately allocate the target port as the host port.fundamentals/networking-overview.mdx— Corrected three locations:EndpointAnnotationproperties reference paragraphwhats-new/aspire-13-4.mdx— Corrected two locations in the persistent executable/project lifetime sections (feature spotlight Aside and breaking changes entry) to scope the proxyless-by-default statement to executables and projects only.Files modified
src/frontend/src/content/docs/app-host/resource-lifetimes.mdx(updated)src/frontend/src/content/docs/fundamentals/networking-overview.mdx(updated)src/frontend/src/content/docs/whats-new/aspire-13-4.mdx(updated)