From bf15479e870cd5a20c7a9901046c0289f1671cc1 Mon Sep 17 00:00:00 2001 From: "aspire-repo-bot[bot]" <268009190+aspire-repo-bot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 00:09:53 +0000 Subject: [PATCH 1/2] docs: document proxyless container endpoint on-demand allocation Documents the on-demand port allocation behavior for dynamic proxyless container endpoints introduced in Aspire 13.5 (microsoft/aspire#17851). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../docs/fundamentals/networking-overview.mdx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx index 8a3533e1b..650447621 100644 --- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx +++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx @@ -259,6 +259,27 @@ await web.withHttpEndpoint({ targetPort: 80, isProxied: false }); +### Resolving proxyless container endpoints before container creation + +Proxyless container endpoints normally defer host port assignment until DCP creates the container. This means that if you reference an endpoint in a `WithEnvironment` callback or similar configuration that runs before the container is fully built, the port may not yet be available, which can cause deadlocks or failures. + +Starting in Aspire 13.5, Aspire supports on-demand port allocation for dynamic proxyless container endpoints. When your AppHost code references a proxyless container endpoint before the container is created — for example, to expose the container's own port number as an environment variable — Aspire commits the `targetPort` as a fallback host port and makes it available immediately. Once the container's ports are finalized, normal DCP-based host port assignment takes over for any subsequent endpoint resolution. + +This lets you write patterns like the following, where a container exposes its own public port in an environment variable: + +```csharp title="AppHost.cs" +var database = builder.AddContainer("database", "image") + .WithEndpoint(name: "tcp", targetPort: 5432, isProxied: false); + +database.WithEnvironment("PUBLIC_PORT", database.GetEndpoint("tcp").Property(EndpointProperty.Port)); +``` + +In this example, `PUBLIC_PORT` is set to the endpoint's port before the container is created. Because the endpoint is proxyless and has a `targetPort` of `5432`, Aspire uses `5432` as the fallback host port so the value is available immediately. + +:::note +If the endpoint is not referenced before container creation, DCP still assigns the host port dynamically. On-demand allocation only activates when a proxyless container endpoint is explicitly resolved before container creation completes. +::: + ## Omit the host port For proxied endpoints, when you omit the host port, Aspire generates a random port for both host and service port. This is useful when you want to avoid port conflicts and don't care about the host or service port. Consider the following code: From aaab7dd51c3699df7b96dd2b50b69185dc1a27d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 22:29:20 +0000 Subject: [PATCH 2/2] docs: update proxyless endpoint port allocation Co-authored-by: danegsta <50252651+danegsta@users.noreply.github.com> --- .../docs/fundamentals/networking-overview.mdx | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx index 650447621..9a5579903 100644 --- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx +++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx @@ -259,13 +259,16 @@ await web.withHttpEndpoint({ targetPort: 80, isProxied: false }); -### Resolving proxyless container endpoints before container creation +### Allocate ports for dynamic proxyless endpoints -Proxyless container endpoints normally defer host port assignment until DCP creates the container. This means that if you reference an endpoint in a `WithEnvironment` callback or similar configuration that runs before the container is fully built, the port may not yet be available, which can cause deadlocks or failures. +Proxyless endpoints can define a `targetPort` without defining a public host `port`. Starting in Aspire 13.5, Aspire allocates a public host port for each dynamic proxyless endpoint before workload resources are created. The allocated port is then available to configuration that resolves endpoint properties, such as `GetEndpoint(...).Property(EndpointProperty.Port)`. -Starting in Aspire 13.5, Aspire supports on-demand port allocation for dynamic proxyless container endpoints. When your AppHost code references a proxyless container endpoint before the container is created — for example, to expose the container's own port number as an environment variable — Aspire commits the `targetPort` as a fallback host port and makes it available immediately. Once the container's ports are finalized, normal DCP-based host port assignment takes over for any subsequent endpoint resolution. +If you set `port`, Aspire uses that value as the public host port. If you omit `port`, Aspire allocates one from the proxyless endpoint port range. The default range is `10000-32767`, and you can override it with the `ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE` environment variable in `start-end` format. -This lets you write patterns like the following, where a container exposes its own public port in an environment variable: +This lets you write patterns like the following, where a container exposes its allocated public port in an environment variable: + + + ```csharp title="AppHost.cs" var database = builder.AddContainer("database", "image") @@ -274,10 +277,30 @@ var database = builder.AddContainer("database", "image") database.WithEnvironment("PUBLIC_PORT", database.GetEndpoint("tcp").Property(EndpointProperty.Port)); ``` -In this example, `PUBLIC_PORT` is set to the endpoint's port before the container is created. Because the endpoint is proxyless and has a `targetPort` of `5432`, Aspire uses `5432` as the fallback host port so the value is available immediately. + + + +```typescript title="apphost.mts" twoslash +import { EndpointProperty, createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const database = await builder.addContainer('database', { + image: 'image', + tag: 'latest', +}); +await database.withEndpoint({ name: 'tcp', targetPort: 5432, isProxied: false }); + +await database.withEnvironment('PUBLIC_PORT', database.getEndpoint('tcp').property(EndpointProperty.Port)); +``` + + + + +In this example, `PUBLIC_PORT` is set to the endpoint's allocated public host port before the container is created. Because the endpoint is proxyless and doesn't specify `port`, Aspire allocates a port from the proxyless endpoint port range. :::note -If the endpoint is not referenced before container creation, DCP still assigns the host port dynamically. On-demand allocation only activates when a proxyless container endpoint is explicitly resolved before container creation completes. +For persistent resources, Aspire persists allocated proxyless endpoint ports in user secrets and reuses them on later AppHost runs. ::: ## Omit the host port