From fcfd361f841cb8de8b50315d81907344e60c6030 Mon Sep 17 00:00:00 2001 From: "aspire-repo-bot[bot]" <268009190+aspire-repo-bot[bot]@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:55:08 +0000 Subject: [PATCH 01/12] docs: document dashboard startup telemetry Document the aspire/dashboard/startup product telemetry event added in microsoft/aspire#20846: startup result, duration, launch context, and failure error type. Add the Dashboard:LaunchContext configuration option to the dashboard configuration reference. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/content/docs/dashboard/configuration.mdx | 1 + .../microsoft-collected-dashboard-telemetry.mdx | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/frontend/src/content/docs/dashboard/configuration.mdx b/src/frontend/src/content/docs/dashboard/configuration.mdx index ce52bc5db..0439b93b6 100644 --- a/src/frontend/src/content/docs/dashboard/configuration.mdx +++ b/src/frontend/src/content/docs/dashboard/configuration.mdx @@ -317,6 +317,7 @@ Telemetry limits have different scopes depending upon the telemetry type: | Option | Description | |--------|-------------| | `Dashboard:ApplicationName`
Default: `Aspire` | The logical application name used to partition persisted data and to scope authentication and antiforgery cookie names. The AppHost supplies its application name automatically. Set it with the `ASPIRE_DASHBOARD_APPLICATION_NAME` environment variable. Configure a distinct name for dashboards whose cookies should be kept separate; see [Cookie scoping by application name](/dashboard/security-considerations/#cookie-scoping-by-application-name). | +| `Dashboard:LaunchContext`
Default: `null` | The launch context reported in dashboard startup telemetry, such as `apphost`, `cli`, or `container`. Set it with the `DASHBOARD__LAUNCHCONTEXT` environment variable. The AppHost and the `aspire dashboard run` CLI command set this automatically; container deployments can set `container` explicitly. Values are matched case-insensitively, and missing or unrecognized values are reported as `unknown`. See [Microsoft-collected dashboard telemetry](/dashboard/microsoft-collected-dashboard-telemetry/). | | `Dashboard:UI:DisableResourceGraph`
Default: `false` | Disables displaying the resource graph UI in the dashboard. | | `Dashboard:UI:DisableImport`
Default: `false` | Disables the telemetry import UI in the dashboard. | | `Dashboard:UI:DisableAgentHelp`
Default: `false` | Disables the **AI Agents** button in the dashboard header. When `false`, a button is shown in the header that opens a dialog with instructions for using AI coding agents with the dashboard. | diff --git a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx index 57bbcf6c5..9083d803b 100644 --- a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx +++ b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx @@ -45,6 +45,19 @@ Alternatively, you can opt-out of telemetry collection by disabling telemetry co When dashboard usage telemetry is enabled, there's a disclosure statement at the bottom of the settings panel, informing you that telemetry is enabled. This disclosure statement appears when usage telemetry is enabled. +## Startup telemetry + +Separately from the IDE-scoped usage telemetry described above, the dashboard always records an `aspire/dashboard/startup` event when it starts, regardless of how it's launched (AppHost, the `aspire dashboard run` CLI command, standalone, or a deployed container). This event records: + +- The startup result (success or failure). +- The elapsed startup duration, in milliseconds. +- The launch context: `apphost`, `cli`, `container`, or `unknown`. +- For failed startups, an error type: `invalid_config` for options validation failures, `address_in_use` for address conflicts, `canceled` for token-driven startup cancellation, or the exception type for other failures. + +The launch context is read from the `Dashboard:LaunchContext` configuration option (`DASHBOARD__LAUNCHCONTEXT` environment variable). The AppHost and the `aspire dashboard run` CLI command set this automatically; container deployments can set it explicitly to `container`. Values are matched case-insensitively, and missing or unrecognized values are reported as `unknown`. See [dashboard configuration](/dashboard/configuration/#other). + +Startup telemetry is sent using the same Azure Monitor reporting path, and the same `ASPIRE_DASHBOARD_TELEMETRY_OPTOUT` opt-out described above, as other dashboard usage and error telemetry. + ## Data points Aspire dashboard usage telemetry doesn't collect personal data, such as, IP addresses or use browser fingerprinting. It doesn't scan your code and doesn't extract source code, authorship, or deployment configuration. The data is sent securely to Microsoft using Azure Monitor through existing telemetry APIs in Visual Studio and Visual Studio Code. From ce6d2424abb1414a581837605d8c793cfc869fb2 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 12 Oct 2026 08:21:19 -0500 Subject: [PATCH 02/12] docs: migrate standalone dashboard image references (#1679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Update active dashboard image references to the published canonical Aspire repositories. The previous draft/publication warnings are resolved: all exact image tags consumed by this PR returned HTTP 200 on October 12, 2026. The PR is ready for review and conflict-free; an explicit user-directed merge hold remains in effect. - Audit all 2,475 tracked files, including 611 documentation pages and every available localization, plus generated data, runnable examples, configuration, scripts, and workflows. All active tagged references now use canonical names; legacy names remain only in migration explanations. Historical release pages and the hosting-integration image catalog are unchanged. - Use `mcr.microsoft.com/aspire/dashboard:latest` in all standalone Docker examples, including the newly added persistence examples. Preserve container names, ports, authentication, telemetry limits, CORS, volumes, and persistence settings. - Keep the English Compose examples on the intentional floating `mcr.microsoft.com/aspire/nightly/dashboard:latest` selection, with an explicit publisher-output caveat. Align both Japanese generated-output examples with the current publisher's version-line selection, `mcr.microsoft.com/aspire/nightly/dashboard:13.6`, rather than introducing a new manual translation. - Preserve the upstream sample's nightly `13.6` pin in its command and explanation, in both generated README fields. Retain current-main screenshots and metadata; no other sample fields change semantically. After the source change merged, normal-main generation verified that the entire 29-sample catalog is semantically identical to this committed data. - Explain repository mappings, tag availability, immutable digests, and Aspire 13 servicing compatibility. Do not silently upgrade a version-constrained example when its old tag is unavailable in the new repository. - Merge canonical `main` (`1a61517655b4fd7811ef63fb5913f6fb623d9d6a`) while preserving the original PR commits. Resolve the generated catalog conflict through the existing updater and extend regression coverage to persistence commands, all active documentation locales, and arbitrary valid Docker image tags. ### Feedback addressed Both actionable inline findings were fixed in `728e2b88638808155fe10d8f9b0e5f078aa71635`, replied to, and resolved after pushing to the existing upstream head: - Match Docker tag grammar rather than three hard-coded tags. Regression fixtures cover versions, architecture/preview tags, underscores, mixed case, 128-character tags, end-of-input, and tag-plus-digest references in both legacy channels. Historical release-page exclusions remain intact. - Align both Japanese Compose output examples to canonical nightly `13.6`; retain the English guide's explicit floating-nightly explanation. Browser clipboard verification confirms the final language-specific selections. A fully paginated feedback refresh returned two resolved threads, no further thread/comment pages, and zero unresolved findings. No additional actionable general comments were present. ### Dependencies and merge gates - Publisher prerequisite [dotnet/dotnet-docker#7337](https://github.com/dotnet/dotnet-docker/pull/7337) merged on September 15, 2026. Publisher manifests use `aspire/dashboard` on `main` (`f731d8c7f1049741a025a3ed8c034f6921c8af5e`) and `aspire/nightly/dashboard` on `nightly` (`f1f5cc1b0a02f0dd4538d013cca20a89d4ada83e`); actual publication is independently confirmed below. - Source synchronization is fulfilled: [microsoft/aspire-samples#1952](https://github.com/microsoft/aspire-samples/pull/1952) merged as `9e83d52d2f0e8be2c5cc61e87e2a3d9b010f1fc3`. This catalog was initially generated from corrected head `d9ee93a5ef275919aa81956794ad34285a262199` with the supported `SAMPLES_BRANCH` override; running the existing generator against normal `main` after the merge produced semantically identical data for all 29 samples. No needless follow-up catalog edit was made. - Companion [microsoft/aspire#20177](https://github.com/microsoft/aspire/pull/20177) is coordinated separately. At current product `main` (`b1d4824f1249ea4297b818a3f67c48f0cdb5a3ef`), `src/Shared/DashboardImage.cs` and the Docker publisher select the canonical nightly name and resolve a build override or the running product's major/minor tag. This documentation does not claim that manual image edits rewrite installed tooling's output. - **Do not merge, enable auto-merge, or enqueue while the user-directed incident hold is active.** GitHub auto-merge is disabled and the PR has no queue entry. - A valid human approval of the final work and green required/relevant exact-head CI are mandatory after the hold is lifted. `mitchdenny` approved the preceding head `e55de41c1d28522ef5f40aa22a53f19134e36017`; GitHub retains that approval after the feedback push, so a summary `APPROVED` state must not be mistaken for review of the current head. No self-approval or bypass was performed. ### Exact published image decisions | Use | Image | Manifest verification | | --- | --- | --- | | Standalone guides | `mcr.microsoft.com/aspire/dashboard:latest` | HTTP 200; `sha256:613f297a274958abd85e7b71664f51fb42b0ddeb697ebd4c159677774433345b` | | Explicitly illustrative English Compose examples | `mcr.microsoft.com/aspire/nightly/dashboard:latest` | HTTP 200; `sha256:03a6f96028282634e3e957fb0b146e83fcc88e98f34aa3d689a38cd8ac31e5e7` | | Japanese publisher-output examples and upstream sample | `mcr.microsoft.com/aspire/nightly/dashboard:13.6` | HTTP 200; `sha256:03a6f96028282634e3e957fb0b146e83fcc88e98f34aa3d689a38cd8ac31e5e7` | Both canonical tag lists contain `13`, `13.6`, and `latest`, but earlier minors such as `13.0` are absent. Exact canonical `13.0`–`13.3` requests returned 404 while their legacy counterparts returned 200. A repository rename is not a reason to change an intentionally pinned version or switch release channels. ## Third-party links and affiliations None. Added catalog links point to Microsoft's own Microsoft Container Registry. ## Validation Validated/pushed head: `728e2b88638808155fe10d8f9b0e5f078aa71635`. - `pnpm --dir .\src\frontend exec vitest run --config vitest.config.ts tests/unit/dashboard-image-references.vitest.test.ts tests/unit/dashboard-agent-commands.vitest.test.ts tests/unit/update-samples.vitest.test.ts`: **69 passed** after the feedback fixes. Earlier extended coverage reproduced three stale persistence/sample-reference failures before correction. - `pnpm --dir .\src\frontend exec eslint tests\unit\dashboard-image-references.vitest.test.ts --max-warnings 0`: **passed**. - `$env:SAMPLES_BRANCH = 'd9ee93a5ef275919aa81956794ad34285a262199'; pnpm --dir .\src\frontend update:samples`: **passed**, all 29 samples fetched; only the standalone-dashboard README fields changed semantically versus the base. Its `readmeRaw` exactly matches the pinned source bytes. Post-merge execution of the same `update-samples.ts` with `SAMPLES_BRANCH=main` in a temporary output directory: **passed**, all 29 generated sample objects matched the committed catalog; temporary assets were removed. - `git diff upstream/main HEAD --check`: **passed**. Final PR diff: nine intended files, 215 insertions and 20 deletions. Existing PR history and the latest base ancestry are preserved. - `pnpm dev --host 127.0.0.1 --port 4389` with telemetry disabled: **started successfully**. Playwright CLI verified all seven affected documentation routes, Bash/PowerShell standalone/configuration/CORS/persistence variants, C#/TypeScript deployment variants, migration anchors, both image catalogs, and `/reference/samples/standalone-dashboard/`. Final Japanese and sample clipboard checks passed. The owned browser/scratch artifacts and preview server were cleaned up; port 4389 has no listener. - `docker manifest inspect mcr.microsoft.com/aspire/dashboard:latest`, `docker manifest inspect mcr.microsoft.com/aspire/nightly/dashboard:latest`, and `docker manifest inspect mcr.microsoft.com/aspire/nightly/dashboard:13.6`: **passed**, each advertises Linux AMD64 and ARM64. Exact registry manifests were **HTTP 200** with the digests above. - Container execution/login/OTLP/persistence runtime checks were **blocked by the unavailable local Docker Desktop Linux engine**, not claimed as passed. Four copied Compose examples also exposed pre-existing `environment must be a mapping` schema failures; a byte comparison verified their unchanged content against canonical main apart from dashboard image references. Those unrelated baseline defects were not altered. - No full local build was run. Current-head [CI](https://github.com/microsoft/aspire.dev/actions/runs/38249739333) has passed frontend Build, frontend lint/unit validation, release-sync, and change detection; [CodeQL](https://github.com/microsoft/aspire.dev/actions/runs/38249739086), forbidden words, and CLA are green. E2E/downstream gates must finish before merge. Previous-head checks are not reused. --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../content/docs/dashboard/configuration.mdx | 4 +- .../enable-browser-telemetry/index.mdx | 8 +- .../src/content/docs/dashboard/index.mdx | 4 +- .../src/content/docs/dashboard/standalone.mdx | 36 +++- .../docs/get-started/deploy-first-app.mdx | 8 +- .../docs/ja/get-started/deploy-first-app.mdx | 4 +- .../content/docs/whats-new/upgrade-aspire.mdx | 8 + src/frontend/src/data/samples.json | 6 +- .../dashboard-image-references.vitest.test.ts | 157 ++++++++++++++++++ 9 files changed, 215 insertions(+), 20 deletions(-) create mode 100644 src/frontend/tests/unit/dashboard-image-references.vitest.test.ts diff --git a/src/frontend/src/content/docs/dashboard/configuration.mdx b/src/frontend/src/content/docs/dashboard/configuration.mdx index ce52bc5db..b20124ca4 100644 --- a/src/frontend/src/content/docs/dashboard/configuration.mdx +++ b/src/frontend/src/content/docs/dashboard/configuration.mdx @@ -85,7 +85,7 @@ docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire- -e DASHBOARD__TELEMETRYLIMITS__MAXLOGCOUNT='1000' \ -e DASHBOARD__TELEMETRYLIMITS__MAXTRACECOUNT='1000' \ -e DASHBOARD__TELEMETRYLIMITS__MAXMETRICSCOUNT='1000' \ - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -96,7 +96,7 @@ docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire- -e DASHBOARD__TELEMETRYLIMITS__MAXLOGCOUNT='1000' ` -e DASHBOARD__TELEMETRYLIMITS__MAXTRACECOUNT='1000' ` -e DASHBOARD__TELEMETRYLIMITS__MAXMETRICSCOUNT='1000' ` - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` diff --git a/src/frontend/src/content/docs/dashboard/enable-browser-telemetry/index.mdx b/src/frontend/src/content/docs/dashboard/enable-browser-telemetry/index.mdx index b131c2e55..e897fd9d5 100644 --- a/src/frontend/src/content/docs/dashboard/enable-browser-telemetry/index.mdx +++ b/src/frontend/src/content/docs/dashboard/enable-browser-telemetry/index.mdx @@ -97,7 +97,7 @@ docker run --rm -it -d \ -p 4317:18889 \ -p 4318:18890 \ --name aspire-dashboard \ - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -109,7 +109,7 @@ docker run --rm -it -d ` -p 4317:18889 ` -p 4318:18890 ` --name aspire-dashboard ` - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -135,7 +135,7 @@ docker run --rm -it -d \ -p 4318:18890 \ -e DASHBOARD__OTLP__CORS__ALLOWEDORIGINS=https://localhost:8080 \ --name aspire-dashboard \ - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -148,7 +148,7 @@ docker run --rm -it -d ` -p 4318:18890 ` -e DASHBOARD__OTLP__CORS__ALLOWEDORIGINS=https://localhost:8080 ` --name aspire-dashboard ` - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` diff --git a/src/frontend/src/content/docs/dashboard/index.mdx b/src/frontend/src/content/docs/dashboard/index.mdx index 776647d21..98e117f2b 100644 --- a/src/frontend/src/content/docs/dashboard/index.mdx +++ b/src/frontend/src/content/docs/dashboard/index.mdx @@ -95,7 +95,7 @@ Or run the same standalone dashboard from its container image: ```bash docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire-dashboard \ - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -103,7 +103,7 @@ docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire- ```powershell docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire-dashboard ` - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` diff --git a/src/frontend/src/content/docs/dashboard/standalone.mdx b/src/frontend/src/content/docs/dashboard/standalone.mdx index 5c91ea115..9cb162d46 100644 --- a/src/frontend/src/content/docs/dashboard/standalone.mdx +++ b/src/frontend/src/content/docs/dashboard/standalone.mdx @@ -65,7 +65,7 @@ The dashboard also ships as a standalone container image. Use this option when a ```bash docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire-dashboard \ - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -73,7 +73,7 @@ docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire- ```powershell docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire-dashboard ` - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -81,12 +81,38 @@ docker run --rm -it -p 18888:18888 -p 4317:18889 -p 4318:18890 -d --name aspire- The preceding Docker command: -- Starts a container from the `mcr.microsoft.com/dotnet/aspire-dashboard:latest` image. +- Starts a container from the `mcr.microsoft.com/aspire/dashboard:latest` image. - The container exposes three ports: - Mapping the dashboard's port `18888` to the host's port `18888`. Port `18888` has the dashboard UI. Navigate to `http://localhost:18888` in the browser to view the dashboard. - Mapping the dashboard's OTLP/gRPC port `18889` to the host's port `4317`. Port `4317` receives OpenTelemetry data from apps using [OTLP/gRPC](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc). - Mapping the dashboard's OTLP/HTTP port `18890` to the host's port `4318`. Port `4318` receives OpenTelemetry data from apps using [OTLP/HTTP](https://opentelemetry.io/docs/specs/otlp/#otlphttp). +### Container image repositories and migration + +The dashboard images are published to Microsoft Container Registry (MCR) under the `aspire` product family: + +| Channel | Repository | Use | +| --- | --- | --- | +| Stable | `mcr.microsoft.com/aspire/dashboard` | Released dashboard images; recommended for standalone use. | +| Nightly | `mcr.microsoft.com/aspire/nightly/dashboard` | Preview builds for testing upcoming changes. | + +Use the [stable image catalog](https://mcr.microsoft.com/en-us/product/aspire/dashboard/tags) or [nightly image catalog](https://mcr.microsoft.com/en-us/product/aspire/nightly/dashboard/tags) to check available tags. Nightly builds aren't a substitute for stable releases. + +If you manage a dashboard container yourself, update the image repository in your Docker commands, Compose files, Kubernetes manifests, and image-mirroring or allowlist configuration: + +| Previous repository | New repository | +| --- | --- | +| `mcr.microsoft.com/dotnet/aspire-dashboard` | `mcr.microsoft.com/aspire/dashboard` | +| `mcr.microsoft.com/dotnet/nightly/aspire-dashboard` | `mcr.microsoft.com/aspire/nightly/dashboard` | + +Preserve your stable or nightly channel and verify that your chosen tag exists in the new repository before changing it. The migration doesn't guarantee that all historical tags are available at the new names. If a version-specific tag isn't available in the new repository, keep the legacy reference rather than silently upgrading the dashboard. The `latest` tag follows the latest image in its repository; choose a published version tag to stay on a version line, or a digest when you need an immutable image reference. + +:::note[Aspire 13 compatibility] +Aspire 13 images continue to be published to the legacy repositories for servicing and security updates. This compatibility covers the published fixed, minor, major, and architecture-specific tags. Legacy `latest` stays on the Aspire 13 line; it isn't a permanent alias for the new repository's `latest`. Subsequent major versions use the new repositories without this legacy syndication. +::: + +The repository change doesn't rename the `aspire-dashboard` container, change its ports or environment variables, or change `aspire dashboard run`. Docker Compose and Kubernetes output generated by an older Aspire release can still contain a legacy image reference. Keep that output aligned with the publisher version rather than assuming the image repository migration changes installed tooling. + ## Login to the dashboard Data displayed in the dashboard can be sensitive. By default, the dashboard is secured with authentication that requires a token to login. @@ -257,7 +283,7 @@ docker run --rm -d --name aspire-dashboard \ -e ASPIRE_DASHBOARD_APPLICATION_NAME=my-app \ -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/dashboard-data \ -e ASPIRE_DASHBOARD_PERSISTENCE_MODE=run \ - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` @@ -274,7 +300,7 @@ docker run --rm -d --name aspire-dashboard ` -e ASPIRE_DASHBOARD_APPLICATION_NAME=my-app ` -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/dashboard-data ` -e ASPIRE_DASHBOARD_PERSISTENCE_MODE=run ` - mcr.microsoft.com/dotnet/aspire-dashboard:latest + mcr.microsoft.com/aspire/dashboard:latest ``` diff --git a/src/frontend/src/content/docs/get-started/deploy-first-app.mdx b/src/frontend/src/content/docs/get-started/deploy-first-app.mdx index ff6d60fdc..0d31e0b24 100644 --- a/src/frontend/src/content/docs/get-started/deploy-first-app.mdx +++ b/src/frontend/src/content/docs/get-started/deploy-first-app.mdx @@ -20,6 +20,10 @@ import csharpStarterPng from '@assets/get-started/csharp-starter.png'; import javascriptStarterDarkPng from '@assets/get-started/javascript-starter-dark.png'; import javascriptStarterLightPng from '@assets/get-started/javascript-starter-light.png'; +:::note[Dashboard image in these examples] +The Docker Compose examples on this page intentionally select `mcr.microsoft.com/aspire/nightly/dashboard:latest`. This floating tag follows the latest nightly dashboard image; it isn't an immutable digest or a stable release. Your installed Aspire publisher can generate a different repository or pin a version-line tag, so these examples don't guarantee its default output. For image selection and compatibility guidance, see [Container image repositories and migration](/dashboard/standalone/#container-image-repositories-and-migration). +::: + +## Update standalone dashboard container references + +If you manage the standalone dashboard as a container, its stable image repository is now `mcr.microsoft.com/aspire/dashboard`; nightly images use `mcr.microsoft.com/aspire/nightly/dashboard`. Updating the Aspire CLI or packages doesn't rewrite image references in your own Docker commands, Compose files, or Kubernetes manifests. + +Before replacing a legacy `dotnet/aspire-dashboard` or `dotnet/nightly/aspire-dashboard` reference, verify that the tag you use exists in the new repository. Legacy repositories continue to receive Aspire 13 servicing images, but their `latest` tag stays on the Aspire 13 line rather than following future major releases. Generated deployment output remains specific to the Aspire publisher version. + +For the repository mapping, tag selection, and compatibility details, see [Container image repositories and migration](/dashboard/standalone/#container-image-repositories-and-migration). + ## Update the VS Code extension (optional) If you have the Aspire extension installed, you can update it to get the latest tooling support: diff --git a/src/frontend/src/data/samples.json b/src/frontend/src/data/samples.json index 41b155cf4..e15de1136 100644 --- a/src/frontend/src/data/samples.json +++ b/src/frontend/src/data/samples.json @@ -488,8 +488,8 @@ "title": "Standalone Aspire dashboard sample app", "description": "View telemetry from any app in the Aspire dashboard. The dashboard supports running standalone, and apps configured with an [OpenTelemetry SDK](https://opentelemetry.io/docs/getting-started/dev/) can send it data.\n\nThis sample is a .NET console app that downloads data from [NuGet](https://nuget.org/). The app sends telemetry to the Aspire dashboard which is viewed in the dashboard telemetry UI.", "href": "https://github.com/microsoft/aspire-samples/tree/main/samples/standalone-dashboard", - "readme": "# Standalone Aspire dashboard sample app\n\nView telemetry from any app in the Aspire dashboard. The dashboard supports running standalone, and apps configured with an [OpenTelemetry SDK](https://opentelemetry.io/docs/getting-started/dev/) can send it data.\n\nThis sample is a .NET console app that downloads data from [NuGet](https://nuget.org/). The app sends telemetry to the Aspire dashboard which is viewed in the dashboard telemetry UI.\n\n![Screenshot of the standalone Aspire dashboard (light theme)](~/assets/samples/standalone-dashboard/aspire-dashboard-screenshot-light.png#gh-light-mode-only)\n![Screenshot of the standalone Aspire dashboard (dark theme)](~/assets/samples/standalone-dashboard/aspire-dashboard-screenshot-dark.png#gh-dark-mode-only)\n\n## Demonstrates\n\n- How to run the Aspire dashboard from a Docker container\n- How to configure a .NET app to export telemetry to the dashboard\n- How to view telemetry in the Aspire dashboard\n\n## Sample prerequisites\n\nThis sample is written in C# and targets .NET 10.0. It requires the [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) or later.\n\nThis sample runs the Aspire dashboard from a Docker container. It requires Docker to be installed.\n\n## Start Aspire dashboard\n\nThe following command starts the Aspire dashboard in a Docker container:\n\n``` bash\ndocker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard mcr.microsoft.com/dotnet/nightly/aspire-dashboard:13.6\n```\n\nThe docker command:\n\n- Starts a container from the `mcr.microsoft.com/dotnet/nightly/aspire-dashboard:13.6` prerelease image.\n- The container has two ports:\n - Port `4317` receives OpenTelemetry data from apps. Apps send data using [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/).\n - Port `18888` has the dashboard UI. Navigate to http://localhost:18888 in the browser to view the dashboard.\n\n> [!NOTE]\n> The dashboard currently only supports the [OTLP/gRPC protocol](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc). Apps sending telemetry to the dashboard must be configured to use the `grpc` protocol. There are a couple of options for configuring apps:\n>\n> - Configure the OpenTelemetry SDK inside the app to use the gRPC OTLP protocol, or\n> - Start the app with the [`OTEL_EXPORTER_OTLP_PROTOCOL` environment variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options) with a value of `grpc`.\n\n## Login to the Aspire dashboard\n\nData displayed in the dashboard can be sensitive. By default, the dashboard is secured with authentication that requires a token to login.\n\nWhen the dashboard is run from a standalone container the login token is printed to the container logs. After copying the highlighted token into the login page, select the *Login* button.\n\n![Screenshot of the Aspire dashboard container logs](~/assets/samples/standalone-dashboard/aspire-dashboard-container-log.png)\n\nFor more information about logging into the dashboard, see [Dashboard authentication](https://aspire.dev/dashboard/explore/#dashboard-authentication).\n\n## Running the sample\n\nTo download and run the sample, follow these steps:\n\n1. Clone the `dotnet/aspire-samples` repository.\n2. Navigate to the folder that holds the sample code.\n3. At the command line, type [`dotnet run ConsoleApp.cs`](https://learn.microsoft.com/dotnet/core/tools/dotnet-run).\n\nRun the .NET app by executing the following at the command prompt (opened to the base directory of the sample):\n\n``` bash\ndotnet run ConsoleApp.cs\n```\n\n1. The console app launches, downloads information about the top NuGet packages and then exits.\n2. View the Aspire dashboard at http://localhost:18888 to see app telemetry.\n 1. View structured logs to see the list of top NuGet packages.\n 2. View traces to see HTTP requests made.\n 3. View metrics to see numeric data about the app such as average HTTP request duration.\n\n## Configure OpenTelemetry\n\nThe telemetry export endpoint is configured with the `OTEL_EXPORTER_OTLP_ENDPOINT` setting. This value is set to `http://localhost:4317` in the sample's `ConsoleApp.run.json` file. Removing the `OTEL_EXPORTER_OTLP_ENDPOINT` value disables exporting telemetry.\n", - "readmeRaw": "# Standalone Aspire dashboard sample app\n\nView telemetry from any app in the Aspire dashboard. The dashboard supports running standalone, and apps configured with an [OpenTelemetry SDK](https://opentelemetry.io/docs/getting-started/dev/) can send it data.\n\nThis sample is a .NET console app that downloads data from [NuGet](https://nuget.org/). The app sends telemetry to the Aspire dashboard which is viewed in the dashboard telemetry UI.\n\n![Screenshot of the standalone Aspire dashboard (light theme)](./images/aspire-dashboard-screenshot-light.png#gh-light-mode-only)\n![Screenshot of the standalone Aspire dashboard (dark theme)](./images/aspire-dashboard-screenshot-dark.png#gh-dark-mode-only)\n\n## Demonstrates\n\n- How to run the Aspire dashboard from a Docker container\n- How to configure a .NET app to export telemetry to the dashboard\n- How to view telemetry in the Aspire dashboard\n\n## Sample prerequisites\n\nThis sample is written in C# and targets .NET 10.0. It requires the [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) or later.\n\nThis sample runs the Aspire dashboard from a Docker container. It requires Docker to be installed.\n\n## Start Aspire dashboard\n\nThe following command starts the Aspire dashboard in a Docker container:\n\n``` bash\ndocker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard mcr.microsoft.com/dotnet/nightly/aspire-dashboard:13.6\n```\n\nThe docker command:\n\n- Starts a container from the `mcr.microsoft.com/dotnet/nightly/aspire-dashboard:13.6` prerelease image.\n- The container has two ports:\n - Port `4317` receives OpenTelemetry data from apps. Apps send data using [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/).\n - Port `18888` has the dashboard UI. Navigate to http://localhost:18888 in the browser to view the dashboard.\n\n> [!NOTE]\n> The dashboard currently only supports the [OTLP/gRPC protocol](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc). Apps sending telemetry to the dashboard must be configured to use the `grpc` protocol. There are a couple of options for configuring apps:\n>\n> - Configure the OpenTelemetry SDK inside the app to use the gRPC OTLP protocol, or\n> - Start the app with the [`OTEL_EXPORTER_OTLP_PROTOCOL` environment variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options) with a value of `grpc`.\n\n## Login to the Aspire dashboard\n\nData displayed in the dashboard can be sensitive. By default, the dashboard is secured with authentication that requires a token to login.\n\nWhen the dashboard is run from a standalone container the login token is printed to the container logs. After copying the highlighted token into the login page, select the *Login* button.\n\n![Screenshot of the Aspire dashboard container logs](./images/aspire-dashboard-container-log.png)\n\nFor more information about logging into the dashboard, see [Dashboard authentication](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/explore#dashboard-authentication).\n\n## Running the sample\n\nTo download and run the sample, follow these steps:\n\n1. Clone the `dotnet/aspire-samples` repository.\n2. Navigate to the folder that holds the sample code.\n3. At the command line, type [`dotnet run ConsoleApp.cs`](https://learn.microsoft.com/dotnet/core/tools/dotnet-run).\n\nRun the .NET app by executing the following at the command prompt (opened to the base directory of the sample):\n\n``` bash\ndotnet run ConsoleApp.cs\n```\n\n1. The console app launches, downloads information about the top NuGet packages and then exits.\n2. View the Aspire dashboard at http://localhost:18888 to see app telemetry.\n 1. View structured logs to see the list of top NuGet packages.\n 2. View traces to see HTTP requests made.\n 3. View metrics to see numeric data about the app such as average HTTP request duration.\n\n## Configure OpenTelemetry\n\nThe telemetry export endpoint is configured with the `OTEL_EXPORTER_OTLP_ENDPOINT` setting. This value is set to `http://localhost:4317` in the sample's `ConsoleApp.run.json` file. Removing the `OTEL_EXPORTER_OTLP_ENDPOINT` value disables exporting telemetry.\n", + "readme": "# Standalone Aspire dashboard sample app\n\nView telemetry from any app in the Aspire dashboard. The dashboard supports running standalone, and apps configured with an [OpenTelemetry SDK](https://opentelemetry.io/docs/getting-started/dev/) can send it data.\n\nThis sample is a .NET console app that downloads data from [NuGet](https://nuget.org/). The app sends telemetry to the Aspire dashboard which is viewed in the dashboard telemetry UI.\n\n![Screenshot of the standalone Aspire dashboard (light theme)](~/assets/samples/standalone-dashboard/aspire-dashboard-screenshot-light.png#gh-light-mode-only)\n![Screenshot of the standalone Aspire dashboard (dark theme)](~/assets/samples/standalone-dashboard/aspire-dashboard-screenshot-dark.png#gh-dark-mode-only)\n\n## Demonstrates\n\n- How to run the Aspire dashboard from a Docker container\n- How to configure a .NET app to export telemetry to the dashboard\n- How to view telemetry in the Aspire dashboard\n\n## Sample prerequisites\n\nThis sample is written in C# and targets .NET 10.0. It requires the [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) or later.\n\nThis sample runs the Aspire dashboard from a Docker container. It requires Docker to be installed.\n\n## Start Aspire dashboard\n\nThe following command starts the Aspire dashboard in a Docker container:\n\n``` bash\ndocker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard mcr.microsoft.com/aspire/nightly/dashboard:13.6\n```\n\nThe docker command:\n\n- Starts a container from the `mcr.microsoft.com/aspire/nightly/dashboard:13.6` prerelease image.\n- The container has two ports:\n - Port `4317` receives OpenTelemetry data from apps. Apps send data using [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/).\n - Port `18888` has the dashboard UI. Navigate to http://localhost:18888 in the browser to view the dashboard.\n\n> [!NOTE]\n> The dashboard currently only supports the [OTLP/gRPC protocol](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc). Apps sending telemetry to the dashboard must be configured to use the `grpc` protocol. There are a couple of options for configuring apps:\n>\n> - Configure the OpenTelemetry SDK inside the app to use the gRPC OTLP protocol, or\n> - Start the app with the [`OTEL_EXPORTER_OTLP_PROTOCOL` environment variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options) with a value of `grpc`.\n\n## Login to the Aspire dashboard\n\nData displayed in the dashboard can be sensitive. By default, the dashboard is secured with authentication that requires a token to login.\n\nWhen the dashboard is run from a standalone container the login token is printed to the container logs. After copying the highlighted token into the login page, select the *Login* button.\n\n![Screenshot of the Aspire dashboard container logs](~/assets/samples/standalone-dashboard/aspire-dashboard-container-log.png)\n\nFor more information about logging into the dashboard, see [Dashboard authentication](https://aspire.dev/dashboard/explore/#dashboard-authentication).\n\n## Running the sample\n\nTo download and run the sample, follow these steps:\n\n1. Clone the `dotnet/aspire-samples` repository.\n2. Navigate to the folder that holds the sample code.\n3. At the command line, type [`dotnet run ConsoleApp.cs`](https://learn.microsoft.com/dotnet/core/tools/dotnet-run).\n\nRun the .NET app by executing the following at the command prompt (opened to the base directory of the sample):\n\n``` bash\ndotnet run ConsoleApp.cs\n```\n\n1. The console app launches, downloads information about the top NuGet packages and then exits.\n2. View the Aspire dashboard at http://localhost:18888 to see app telemetry.\n 1. View structured logs to see the list of top NuGet packages.\n 2. View traces to see HTTP requests made.\n 3. View metrics to see numeric data about the app such as average HTTP request duration.\n\n## Configure OpenTelemetry\n\nThe telemetry export endpoint is configured with the `OTEL_EXPORTER_OTLP_ENDPOINT` setting. This value is set to `http://localhost:4317` in the sample's `ConsoleApp.run.json` file. Removing the `OTEL_EXPORTER_OTLP_ENDPOINT` value disables exporting telemetry.\n", + "readmeRaw": "# Standalone Aspire dashboard sample app\n\nView telemetry from any app in the Aspire dashboard. The dashboard supports running standalone, and apps configured with an [OpenTelemetry SDK](https://opentelemetry.io/docs/getting-started/dev/) can send it data.\n\nThis sample is a .NET console app that downloads data from [NuGet](https://nuget.org/). The app sends telemetry to the Aspire dashboard which is viewed in the dashboard telemetry UI.\n\n![Screenshot of the standalone Aspire dashboard (light theme)](./images/aspire-dashboard-screenshot-light.png#gh-light-mode-only)\n![Screenshot of the standalone Aspire dashboard (dark theme)](./images/aspire-dashboard-screenshot-dark.png#gh-dark-mode-only)\n\n## Demonstrates\n\n- How to run the Aspire dashboard from a Docker container\n- How to configure a .NET app to export telemetry to the dashboard\n- How to view telemetry in the Aspire dashboard\n\n## Sample prerequisites\n\nThis sample is written in C# and targets .NET 10.0. It requires the [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) or later.\n\nThis sample runs the Aspire dashboard from a Docker container. It requires Docker to be installed.\n\n## Start Aspire dashboard\n\nThe following command starts the Aspire dashboard in a Docker container:\n\n``` bash\ndocker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard mcr.microsoft.com/aspire/nightly/dashboard:13.6\n```\n\nThe docker command:\n\n- Starts a container from the `mcr.microsoft.com/aspire/nightly/dashboard:13.6` prerelease image.\n- The container has two ports:\n - Port `4317` receives OpenTelemetry data from apps. Apps send data using [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/).\n - Port `18888` has the dashboard UI. Navigate to http://localhost:18888 in the browser to view the dashboard.\n\n> [!NOTE]\n> The dashboard currently only supports the [OTLP/gRPC protocol](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc). Apps sending telemetry to the dashboard must be configured to use the `grpc` protocol. There are a couple of options for configuring apps:\n>\n> - Configure the OpenTelemetry SDK inside the app to use the gRPC OTLP protocol, or\n> - Start the app with the [`OTEL_EXPORTER_OTLP_PROTOCOL` environment variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options) with a value of `grpc`.\n\n## Login to the Aspire dashboard\n\nData displayed in the dashboard can be sensitive. By default, the dashboard is secured with authentication that requires a token to login.\n\nWhen the dashboard is run from a standalone container the login token is printed to the container logs. After copying the highlighted token into the login page, select the *Login* button.\n\n![Screenshot of the Aspire dashboard container logs](./images/aspire-dashboard-container-log.png)\n\nFor more information about logging into the dashboard, see [Dashboard authentication](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/explore#dashboard-authentication).\n\n## Running the sample\n\nTo download and run the sample, follow these steps:\n\n1. Clone the `dotnet/aspire-samples` repository.\n2. Navigate to the folder that holds the sample code.\n3. At the command line, type [`dotnet run ConsoleApp.cs`](https://learn.microsoft.com/dotnet/core/tools/dotnet-run).\n\nRun the .NET app by executing the following at the command prompt (opened to the base directory of the sample):\n\n``` bash\ndotnet run ConsoleApp.cs\n```\n\n1. The console app launches, downloads information about the top NuGet packages and then exits.\n2. View the Aspire dashboard at http://localhost:18888 to see app telemetry.\n 1. View structured logs to see the list of top NuGet packages.\n 2. View traces to see HTTP requests made.\n 3. View metrics to see numeric data about the app such as average HTTP request duration.\n\n## Configure OpenTelemetry\n\nThe telemetry export endpoint is configured with the `OTEL_EXPORTER_OTLP_ENDPOINT` setting. This value is set to `http://localhost:4317` in the sample's `ConsoleApp.run.json` file. Removing the `OTEL_EXPORTER_OTLP_ENDPOINT` value disables exporting telemetry.\n", "tags": [ "csharp", "dashboard", @@ -621,4 +621,4 @@ "appHostPath": "VolumeMount.AppHost/AppHost.cs", "appHostCode": "var builder = DistributedApplication.CreateBuilder(args);\n\nvar sqlserver = builder.AddSqlServer(\"sqlserver\")\n .WithDataVolume()\n .WithLifetime(ContainerLifetime.Persistent);\n\nvar sqlDatabase = sqlserver.AddDatabase(\"sqldb\");\n\nvar blobs = builder.AddAzureStorage(\"Storage\")\n // Use the Azurite storage emulator for local development\n .RunAsEmulator(emulator => emulator.WithDataVolume())\n .AddBlobs(\"BlobConnection\");\n\nvar migration = builder.AddProject(\"migration\")\n .WithReference(sqlDatabase)\n .WaitFor(sqlDatabase);\n\nbuilder.AddProject(\"blazorweb\")\n .WithReference(sqlDatabase)\n .WaitForCompletion(migration)\n .WithReference(blobs)\n .WaitFor(blobs);\n\nbuilder.Build().Run();" } -] +] \ No newline at end of file diff --git a/src/frontend/tests/unit/dashboard-image-references.vitest.test.ts b/src/frontend/tests/unit/dashboard-image-references.vitest.test.ts new file mode 100644 index 000000000..a4960b889 --- /dev/null +++ b/src/frontend/tests/unit/dashboard-image-references.vitest.test.ts @@ -0,0 +1,157 @@ +import { readdirSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, expect, test } from 'vitest'; +import samples from '@data/samples.json'; + +const testsDir = path.dirname(fileURLToPath(import.meta.url)); +const docsRoot = path.resolve(testsDir, '..', '..', 'src', 'content', 'docs'); +const stableImage = 'mcr.microsoft.com/aspire/dashboard:latest'; +const nightlyImage = 'mcr.microsoft.com/aspire/nightly/dashboard:latest'; +const versionedNightlyImage = 'mcr.microsoft.com/aspire/nightly/dashboard:13.6'; + +function readDoc(file: string): string { + return readFileSync(path.join(docsRoot, file), 'utf8'); +} + +function dockerCommands(source: string): string[] { + return [...source.matchAll(/```(?:bash|powershell)[^\n]*\n([\s\S]*?)```/g)].flatMap( + (match) => match[1].match(/^docker run[^\n]*(?:\n[ \t]+[^\n]*)*/gm) ?? [] + ); +} + +function legacyImageReferences(source: string): string[] { + return ( + source.match( + /mcr\.microsoft\.com\/dotnet\/(?:nightly\/)?aspire-dashboard:\w[\w.-]{0,127}(?=$|[\s`"'@])/g + ) ?? [] + ); +} + +describe('standalone dashboard container images', () => { + test.each([ + ['dashboard/standalone.mdx', 4], + ['dashboard/index.mdx', 2], + ['dashboard/configuration.mdx', 2], + ['dashboard/enable-browser-telemetry/index.mdx', 4], + ])('%s uses the stable image in both shell variants', (file, count) => { + const source = readDoc(file); + const commands = dockerCommands(source); + + expect(commands).toHaveLength(count); + expect(source.match(//g)?.length).toBeGreaterThanOrEqual( + count / 2 + ); + for (const command of commands) { + expect(command.match(/mcr\.microsoft\.com\/\S+/g)).toEqual([stableImage]); + expect(command).toContain('--name aspire-dashboard'); + for (const port of ['18888:18888', '4317:18889', '4318:18890']) { + expect(command).toContain(`-p ${port}`); + } + } + expect(source.match(/```bash\b/g)?.length).toBeGreaterThanOrEqual(count / 2); + expect(source.match(/```powershell\b/g)?.length).toBeGreaterThanOrEqual(count / 2); + }); + + test('preserves telemetry limits and CORS settings', () => { + for (const command of dockerCommands(readDoc('dashboard/configuration.mdx'))) { + for (const setting of ['MAXLOGCOUNT', 'MAXTRACECOUNT', 'MAXMETRICSCOUNT']) { + expect(command).toContain(`-e DASHBOARD__TELEMETRYLIMITS__${setting}='1000'`); + } + } + const browserCommands = dockerCommands(readDoc('dashboard/enable-browser-telemetry/index.mdx')); + expect( + browserCommands.filter((command) => + command.includes('-e DASHBOARD__OTLP__CORS__ALLOWEDORIGINS=https://localhost:8080') + ) + ).toHaveLength(2); + }); + + test('keeps the command explanation and container log name consistent', () => { + const source = readDoc('dashboard/standalone.mdx'); + expect(source).toContain(`Starts a container from the \`${stableImage}\` image.`); + expect(source).toContain('docker container logs aspire-dashboard'); + expect(source).toContain('aspire dashboard run'); + }); + + test('preserves the volume and persistence settings in both shell variants', () => { + const commands = dockerCommands(readDoc('dashboard/standalone.mdx')).filter((command) => + command.includes('--mount') + ); + expect(commands).toHaveLength(2); + for (const command of commands) { + expect(command).toContain( + '--mount type=volume,source=aspire-dashboard-data,target=/dashboard-data' + ); + expect(command).toContain('-e ASPIRE_DASHBOARD_APPLICATION_NAME=my-app'); + expect(command).toContain('-e ASPIRE_DASHBOARD_DATA_DIRECTORY=/dashboard-data'); + expect(command).toContain('-e ASPIRE_DASHBOARD_PERSISTENCE_MODE=run'); + } + }); + + test.each([ + 'latest', + '13', + '13.6', + '13.5', + '14.0', + '13.6.1', + '13.6.1-amd64', + 'preview_1', + 'Preview.1', + '_build', + 'a'.repeat(128), + ])('detects the legacy Docker tag %s in both channels', (tag) => { + for (const repository of ['dotnet/aspire-dashboard', 'dotnet/nightly/aspire-dashboard']) { + const image = `mcr.microsoft.com/${repository}:${tag}`; + expect(legacyImageReferences(`image: "${image}"`)).toEqual([image]); + expect(legacyImageReferences(image)).toEqual([image]); + expect(legacyImageReferences(`${image}@sha256:${'a'.repeat(64)}`)).toEqual([image]); + } + }); + + test('uses canonical tagged image references throughout active docs in all locales', () => { + const legacyImages: string[] = []; + for (const file of readdirSync(docsRoot, { recursive: true, encoding: 'utf8' })) { + if (!/\.mdx?$/.test(file) || /(?:^|[\\/])whats-new[\\/]aspire-\d/.test(file)) { + continue; + } + const images = legacyImageReferences(readDoc(file)); + legacyImages.push(...images.map((image) => `${file}: ${image}`)); + } + expect(legacyImages).toEqual([]); + }); +}); + +describe('deployment example dashboard image references', () => { + test.each([ + ['get-started/deploy-first-app.mdx', nightlyImage], + ['ja/get-started/deploy-first-app.mdx', versionedNightlyImage], + ])('%s preserves its documented nightly image selection', (file, image) => { + const images = [...readDoc(file).matchAll(/image: "(mcr\.microsoft\.com\/[^"]+)"/g)].map( + (match) => match[1] + ); + expect(images).toEqual([image, image]); + }); + + test('distinguishes the English floating examples from installed publisher output', () => { + const source = readDoc('get-started/deploy-first-app.mdx'); + expect(source).toContain(`intentionally select \`${nightlyImage}\``); + expect(source).toContain('Your installed Aspire publisher can generate a different repository'); + expect(source).toContain('/dashboard/standalone/#container-image-repositories-and-migration'); + }); +}); + +describe('standalone dashboard sample image', () => { + test('preserves the upstream nightly version pin in both README fields', () => { + const sample = samples.find((entry) => entry.name === 'standalone-dashboard'); + expect(sample).toBeDefined(); + for (const field of ['readme', 'readmeRaw'] as const) { + const source = sample![field]; + const images = source.match(/mcr\.microsoft\.com\/[^\s`]+/g); + expect(images).toEqual([versionedNightlyImage, versionedNightlyImage]); + expect(source).toContain(`--name aspire-dashboard ${versionedNightlyImage}`); + expect(source).toContain(`\`${versionedNightlyImage}\` prerelease image.`); + } + }); +}); From 5c9d532cfc803eb1844f782bd05c5eb4d6cd903f Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 12 Oct 2026 22:13:30 +0800 Subject: [PATCH 03/12] Apply batched suggestions from code review Co-authored-by: James Newton-King --- src/frontend/src/content/docs/dashboard/configuration.mdx | 2 +- .../docs/dashboard/microsoft-collected-dashboard-telemetry.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/content/docs/dashboard/configuration.mdx b/src/frontend/src/content/docs/dashboard/configuration.mdx index 0439b93b6..6bcb9b460 100644 --- a/src/frontend/src/content/docs/dashboard/configuration.mdx +++ b/src/frontend/src/content/docs/dashboard/configuration.mdx @@ -317,7 +317,7 @@ Telemetry limits have different scopes depending upon the telemetry type: | Option | Description | |--------|-------------| | `Dashboard:ApplicationName`
Default: `Aspire` | The logical application name used to partition persisted data and to scope authentication and antiforgery cookie names. The AppHost supplies its application name automatically. Set it with the `ASPIRE_DASHBOARD_APPLICATION_NAME` environment variable. Configure a distinct name for dashboards whose cookies should be kept separate; see [Cookie scoping by application name](/dashboard/security-considerations/#cookie-scoping-by-application-name). | -| `Dashboard:LaunchContext`
Default: `null` | The launch context reported in dashboard startup telemetry, such as `apphost`, `cli`, or `container`. Set it with the `DASHBOARD__LAUNCHCONTEXT` environment variable. The AppHost and the `aspire dashboard run` CLI command set this automatically; container deployments can set `container` explicitly. Values are matched case-insensitively, and missing or unrecognized values are reported as `unknown`. See [Microsoft-collected dashboard telemetry](/dashboard/microsoft-collected-dashboard-telemetry/). | +| `Dashboard:LaunchContext`
Default: `null` | The launch context reported in dashboard startup telemetry, such as `apphost`, `cli`, or `container`. The AppHost and the `aspire dashboard run` CLI command set this automatically; container deployments can set `container` explicitly. See [Microsoft-collected dashboard telemetry](/dashboard/microsoft-collected-dashboard-telemetry/). | | `Dashboard:UI:DisableResourceGraph`
Default: `false` | Disables displaying the resource graph UI in the dashboard. | | `Dashboard:UI:DisableImport`
Default: `false` | Disables the telemetry import UI in the dashboard. | | `Dashboard:UI:DisableAgentHelp`
Default: `false` | Disables the **AI Agents** button in the dashboard header. When `false`, a button is shown in the header that opens a dialog with instructions for using AI coding agents with the dashboard. | diff --git a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx index 9083d803b..dd88f6b8b 100644 --- a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx +++ b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx @@ -77,7 +77,7 @@ The Aspire dashboard doesn't collect telemetry on Visual Studio versions `< 17.1 | 9.3 | OTel data processing times. | — | | 9.3 | Dashboard-related unhandled exceptions. | — | | 9.3 | GitHub Copilot usage statistics. | — | -| 9.3 | GitHub Copilot help/unhelp feedback. | — | +| 17.0 | Dashboard startup. | — | ## See also From 145095613c615a81732b2deba2509cf1f54fd487 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 12 Oct 2026 22:14:11 +0800 Subject: [PATCH 04/12] Apply suggestion from @JamesNK --- .../microsoft-collected-dashboard-telemetry.mdx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx index dd88f6b8b..5fe75aab4 100644 --- a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx +++ b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx @@ -45,19 +45,6 @@ Alternatively, you can opt-out of telemetry collection by disabling telemetry co When dashboard usage telemetry is enabled, there's a disclosure statement at the bottom of the settings panel, informing you that telemetry is enabled. This disclosure statement appears when usage telemetry is enabled. -## Startup telemetry - -Separately from the IDE-scoped usage telemetry described above, the dashboard always records an `aspire/dashboard/startup` event when it starts, regardless of how it's launched (AppHost, the `aspire dashboard run` CLI command, standalone, or a deployed container). This event records: - -- The startup result (success or failure). -- The elapsed startup duration, in milliseconds. -- The launch context: `apphost`, `cli`, `container`, or `unknown`. -- For failed startups, an error type: `invalid_config` for options validation failures, `address_in_use` for address conflicts, `canceled` for token-driven startup cancellation, or the exception type for other failures. - -The launch context is read from the `Dashboard:LaunchContext` configuration option (`DASHBOARD__LAUNCHCONTEXT` environment variable). The AppHost and the `aspire dashboard run` CLI command set this automatically; container deployments can set it explicitly to `container`. Values are matched case-insensitively, and missing or unrecognized values are reported as `unknown`. See [dashboard configuration](/dashboard/configuration/#other). - -Startup telemetry is sent using the same Azure Monitor reporting path, and the same `ASPIRE_DASHBOARD_TELEMETRY_OPTOUT` opt-out described above, as other dashboard usage and error telemetry. - ## Data points Aspire dashboard usage telemetry doesn't collect personal data, such as, IP addresses or use browser fingerprinting. It doesn't scan your code and doesn't extract source code, authorship, or deployment configuration. The data is sent securely to Microsoft using Azure Monitor through existing telemetry APIs in Visual Studio and Visual Studio Code. From 32f2d1c895952771c0d58924ef8c9115a37b3a0a Mon Sep 17 00:00:00 2001 From: Samson Amaugo Date: Mon, 12 Oct 2026 15:33:12 +0100 Subject: [PATCH 05/12] Fix the dashboard container persistence example: mount the volume where the non-root user can write (#1869) ## Summary The Docker example under "Persist data between container runs" on the standalone dashboard page does not work as written. The container exits a few seconds after starting. **Steps to reproduce** Run the two commands from that section unchanged: docker volume create aspire-dashboard-data docker run --rm -d --name aspire-dashboard -p 18888:18888 -p 4317:18889 -p 4318:18890 --mount type=volume,source=aspire-dashboard-data,target=/dashboard-data -e ASPIRE_DASHBOARD_APPLICATION_NAME=my-app -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/dashboard-data -e ASPIRE_DASHBOARD_PERSISTENCE_MODE=run mcr.microsoft.com/dotnet/aspire-dashboard:latest **Result** The container exits with code 100. Because the example uses `--rm`, the container and its logs are removed, so the reader sees no error. Running it without `--rm` shows: Aspire dashboard version: 13.6.1 System.UnauthorizedAccessException: Access to the path '/dashboard-data/runs' is denied. **Cause** The image runs as a non-root user (uid 1654). `/dashboard-data` does not exist in the image, so Docker creates the new named volume owned by root, and the dashboard cannot create its `runs` directory in it. **Change** - Mount the volume at `/home/app`, the container user's home directory. Docker gives a new volume the ownership of the directory it is mounted over, so the volume is writable by the dashboard. - Set `ASPIRE_DASHBOARD_DATA_DIRECTORY=/home/app/dashboard-data`. - Add one sentence under the example explaining why this path is used. Both the Bash and PowerShell tabs are updated. An alternative would be to create `/dashboard-data` in the image with the right owner, which would make the original example work unchanged. I'm happy to adjust this PR if that is preferred. ## Third-party links and affiliations None ## Validation - Reproduced the failure with the original example on `mcr.microsoft.com/dotnet/aspire-dashboard:latest` (13.6.1), Docker 29.4.3, Docker Desktop on macOS, and on Docker on Linux. - Ran the corrected example twice in a row in `run` mode: the container started with no errors both times, and the volume contained the saved run from the first start. - Also ran it in `Resume` mode with an application sending OTLP telemetry, removed the container, started a new one on the same volume, and confirmed the earlier traces were still shown. Co-authored-by: Claude Opus 5.5 --- src/frontend/src/content/docs/dashboard/standalone.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/content/docs/dashboard/standalone.mdx b/src/frontend/src/content/docs/dashboard/standalone.mdx index 9cb162d46..3c7811156 100644 --- a/src/frontend/src/content/docs/dashboard/standalone.mdx +++ b/src/frontend/src/content/docs/dashboard/standalone.mdx @@ -279,9 +279,9 @@ docker run --rm -d --name aspire-dashboard \ -p 18888:18888 \ -p 4317:18889 \ -p 4318:18890 \ - --mount type=volume,source=aspire-dashboard-data,target=/dashboard-data \ + --mount type=volume,source=aspire-dashboard-data,target=/home/app \ -e ASPIRE_DASHBOARD_APPLICATION_NAME=my-app \ - -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/dashboard-data \ + -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/home/app/dashboard-data \ -e ASPIRE_DASHBOARD_PERSISTENCE_MODE=run \ mcr.microsoft.com/aspire/dashboard:latest ``` @@ -296,9 +296,9 @@ docker run --rm -d --name aspire-dashboard ` -p 18888:18888 ` -p 4317:18889 ` -p 4318:18890 ` - --mount type=volume,source=aspire-dashboard-data,target=/dashboard-data ` + --mount type=volume,source=aspire-dashboard-data,target=/home/app ` -e ASPIRE_DASHBOARD_APPLICATION_NAME=my-app ` - -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/dashboard-data ` + -e ASPIRE_DASHBOARD_DATA_DIRECTORY=/home/app/dashboard-data ` -e ASPIRE_DASHBOARD_PERSISTENCE_MODE=run ` mcr.microsoft.com/aspire/dashboard:latest ``` @@ -306,6 +306,8 @@ docker run --rm -d --name aspire-dashboard `
+The dashboard container runs as a non-root user, so the volume is mounted at that user's home directory, `/home/app`. Docker gives a new volume the ownership of the directory it's mounted over. A volume mounted at a path that doesn't exist in the image is owned by root, and the dashboard fails to start with an "Access to the path is denied" error. + Stop the container and run the same `docker run` command again to access the retained data. Keep the volume, application name, and persistence mode unchanged between container runs. Persisted telemetry can contain sensitive data. Restrict access to the volume and see [Aspire dashboard data persistence](/dashboard/data-persistence/) for persistence behavior and [Dashboard security considerations](/dashboard/security-considerations/#protect-persisted-data) for security requirements. From 8929ab18b0631c82de22ae94aa9049412cdd7316 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 12 Oct 2026 22:41:40 +0800 Subject: [PATCH 06/12] Apply suggestion from @JamesNK --- .../docs/dashboard/microsoft-collected-dashboard-telemetry.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx index 5fe75aab4..a98ac1d4d 100644 --- a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx +++ b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx @@ -63,7 +63,6 @@ The Aspire dashboard doesn't collect telemetry on Visual Studio versions `< 17.1 | 9.3 | Resource restart times. | — | | 9.3 | OTel data processing times. | — | | 9.3 | Dashboard-related unhandled exceptions. | — | -| 9.3 | GitHub Copilot usage statistics. | — | | 17.0 | Dashboard startup. | — | ## See also From c1e2e160c74deb62576d5cb360131b03b55b2bea Mon Sep 17 00:00:00 2001 From: David Pine Date: Tue, 13 Oct 2026 08:27:49 -0500 Subject: [PATCH 07/12] Restore landing page performance and serve the site over HTTP/2 (#1836) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The landing page's Lighthouse score slipped from the high 80s to the high 70s (mobile, simulated slow 4G), and PageSpeed Insights reported 70. Rather than guess, I built a production-like lab (the production build output served over HTTPS + **HTTP/1.1** + Brotli with the same cache headers, because that is what `aspire.dev` serves today), ran Lighthouse 13 with the mobile preset (simulated Slow 4G, 4× CPU) in a fresh browser profile per run, and bisected the page across the commits that changed it. Every number below is the median of five cold runs. There is one commit per cause (plus one review fix to the banner script), so any of them can be reverted on its own. ### Where it regressed | Build (HTTP/1.1) | Score | FCP | LCP | CLS | Requests | | --- | --- | --- | --- | --- | --- | | Before the redesign (`0b54dce5`) | 87 | 2.33 s | 3.60 s | 0.004 | 43 | | Landing redesign (#1420) | 84 | 2.63 s | 3.96 s | 0.005 | 75 | | Release 13.5 content (includes the banner auto-expiry, #1448) | 82 | 2.63 s | 3.84 s | 0.093 | 75 | | `main` (`a097c7e7`) | 78 | 2.78 s | 4.28 s | 0.105 | 88 | | **This PR** | **86** (85, 86 and 87 in three separate batches) | **2.25 s** | **3.77 s** | **0.001** | **61** | Serving the same bytes over HTTP/2: `main` 90 → this PR 93. ### Causes and fixes I measured each lever on `main` in isolation before changing any code. | Cause | Fix | Alone | | --- | --- | --- | | The banner (#1448) is rendered `hidden` and a bundled script reveals it after first paint, shifting the whole page down (CLS 0.09). | Render it visible and hide it with a tiny pre-paint script when the reader dismissed it or its sunset/auto-dismiss window has passed (the absolute sunset is checked before storage is read, so blocked storage cannot paint an expired banner). A test runs the emitted script against `resolveBannerVisibility` so the two cannot drift. | 78 → 80 | | Poppins is declared in `site.css`, so it is only discovered after that stylesheet downloads; text re-flows when it swaps in (CLS 0.08). | Preload the three weights the first viewport uses. Each is still fetched once. | 78 → 81 (FCP −0.30 s) | | The redesign set `loading="eager"` on 35 icons thousands of pixels below the fold; on HTTP/1.1 they compete with CSS and fonts for six connections. | Use the default lazy loading again. Native lazy loading never starts for `display: none` content, so a small helper (`loadLazyImagesNearViewport`) loads the icons in hidden environment panels and the inactive AppHost language as their section nears the viewport, and switching panels or language stays instant. | 78 → 81 (LCP −0.32 s, 88 → 61 requests) | | `AsciinemaPlayer` imported its CSS from a bundled ` ) } @@ -79,6 +110,7 @@ const firstSeenKey = bannerHash // so shipped behavior can't diverge from the tests. This bundled module reads // its per-banner config from `data-*` attributes on the element (a bundled // script can't use `define:vars`), leaving only DOM/localStorage plumbing here. + // The pre-paint script above applies the same decision before first paint. import { parseFirstSeen, resolveBannerVisibility } from '@utils/banner-expiry'; const initializeBanner = () => { diff --git a/src/frontend/src/components/starlight/Head.astro b/src/frontend/src/components/starlight/Head.astro index 9fce57471..ef3ae838a 100644 --- a/src/frontend/src/components/starlight/Head.astro +++ b/src/frontend/src/components/starlight/Head.astro @@ -1,5 +1,8 @@ --- import 'tippy.js/dist/tippy.css'; +import poppinsRegular from '@fontsource/poppins/files/poppins-latin-400-normal.woff2?url'; +import poppinsSemiBold from '@fontsource/poppins/files/poppins-latin-600-normal.woff2?url'; +import poppinsBold from '@fontsource/poppins/files/poppins-latin-700-normal.woff2?url'; import DefaultHead from '@astrojs/starlight/components/Head.astro'; import { ClientRouter } from 'astro:transitions'; import AccessibleCodeButtons from '../AccessibleCodeButtons.astro'; @@ -7,6 +10,10 @@ import SiteTour from '../SiteTour.astro'; import { getStructuredData } from '@utils/structured-data'; import { getOgMetadata } from '@utils/page-metadata'; +// The Poppins weights that text in the first viewport renders with. The same files back the +// @font-face rules in site.css, so these resolve to the already-emitted assets. +const preloadedFonts = [poppinsRegular, poppinsSemiBold, poppinsBold]; + const repoUrl = ( import.meta.env.PUBLIC_REPO_URL || import.meta.env.REPO_URL || @@ -40,6 +47,18 @@ function computeSourceUrl() { +{ + /* + * Fonts are declared in site.css, so without these the browser only discovers them after that + * stylesheet has downloaded and parsed. Preloading starts the downloads with the document and + * lets the text paint in Poppins instead of swapping in (and re-flowing) after first paint. + */ +} +{ + preloadedFonts.map((href) => ( + + )) +} ") + ).toBe(true); + expect( + importsCssFromBundledScript( + "---\nimport 'pkg/player.css';\n---\n" + ) + ).toBe(false); + expect( + importsCssFromBundledScript( + "---\n// not a " + ) + ).toBe(false); + expect( + importsCssFromBundledScript( + "---\n---\n" + ) + ).toBe(false); + }); + + test('images that opt out of lazy loading', () => { + expect(optsOutOfLazyLoading('')).toBe(true); + expect( + optsOutOfLazyLoading("") + ).toBe(true); + expect(optsOutOfLazyLoading("const props = { loading: 'eager' as const };")).toBe(true); + expect(optsOutOfLazyLoading("images.forEach((image) => { image.loading = 'eager'; });")).toBe( + false + ); + expect(optsOutOfLazyLoading('')).toBe(false); + }); + }); +}); From 73158d1929860ac896485d12ad0d5d8cd5991b57 Mon Sep 17 00:00:00 2001 From: Alistair Matthews Date: Tue, 13 Oct 2026 17:07:33 +0100 Subject: [PATCH 08/12] Propagate the API Reference Astro component (#1849) ## Summary The API Reference Astro component is complete and deployed but only used in **Get Started** Aspire.dev content. This PR propagates its usage to all other content files where appropriate: - It's only used on the first reference to a given API on each page. - It's only used where there is both a C# and a JavaScript version of the referenced API. Fixes: #1848 ## Third-party links and affiliations None ## Validation - `pnpm test:unit:api-reference` - `pnpm run dev` and manually check some instances of the `ApiReference` component. --------- Co-authored-by: David Pine Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Copilot-Session: 92354b96-5c95-491b-93fe-453cb0e1499d --- .../app-host/certificate-configuration.mdx | 11 ++--- .../content/docs/app-host/container-files.mdx | 9 ++-- .../docs/app-host/container-registry.mdx | 5 ++- .../src/content/docs/app-host/eventing.mdx | 13 +++--- .../docs/app-host/executable-resources.mdx | 9 ++-- .../app-host/migrate-from-docker-compose.mdx | 23 +++++----- .../docs/app-host/resource-lifetimes.mdx | 15 ++++--- .../docs/app-host/typescript-apphost.mdx | 5 ++- .../content/docs/app-host/with-terminal.mdx | 7 +-- .../content/docs/app-host/withdockerfile.mdx | 11 ++--- .../multi-language-architecture.mdx | 5 ++- .../architecture/resource-api-patterns.mdx | 3 +- .../docs/architecture/resource-examples.mdx | 2 + .../architecture/resource-hierarchies.mdx | 7 +-- .../docs/architecture/resource-publishing.mdx | 3 +- .../docs/dashboard/ephemeral-terminals.mdx | 4 +- .../src/content/docs/dashboard/explore.mdx | 5 ++- .../dashboard/telemetry-after-deployment.mdx | 3 +- .../src/content/docs/dashboard/terminals.mdx | 5 ++- .../docs/deployment/azure/app-service.mdx | 5 ++- .../deployment/azure/azure-developer-cli.mdx | 5 ++- .../azure/azure-security-best-practices.mdx | 5 ++- .../docs/deployment/azure/container-apps.mdx | 9 ++-- .../docs/deployment/azure/sandboxes.mdx | 15 ++++--- .../docs/deployment/custom-deployments.mdx | 5 ++- .../docs/deployment/deploy-with-aspire.mdx | 3 +- .../docs/deployment/docker-compose.mdx | 23 +++++----- .../content/docs/deployment/environments.mdx | 5 ++- .../docs/deployment/javascript-apps.mdx | 27 +++++------ .../deployment/kubernetes-gateway-aks.mdx | 9 ++-- .../deployment/kubernetes-ingress-aks.mdx | 9 ++-- .../docs/deployment/kubernetes-ingress.mdx | 7 +-- .../docs/deployment/kubernetes/aks.mdx | 25 ++++++----- .../docs/deployment/kubernetes/clusters.mdx | 9 ++-- .../deployment/kubernetes/helm-charts.mdx | 3 +- .../kubernetes/persistent-volumes.mdx | 5 ++- .../src/content/docs/deployment/pipelines.mdx | 9 ++-- .../docs/diagnostics/aspireacadomains001.mdx | 3 +- .../docs/diagnostics/aspireacanaming001.mdx | 3 +- .../docs/diagnostics/aspireazure002.mdx | 3 +- .../docs/diagnostics/aspireazure003.mdx | 3 +- .../docs/diagnostics/aspireblazor001.mdx | 3 +- .../docs/diagnostics/aspirebrowserlogs001.mdx | 3 +- .../diagnostics/aspirecertificates001.mdx | 5 ++- .../docs/diagnostics/aspirecommand001.mdx | 3 +- .../docs/diagnostics/aspirecompute002.mdx | 3 +- .../docs/diagnostics/aspirecompute003.mdx | 3 +- .../docs/diagnostics/aspirecosmosdb001.mdx | 3 +- .../docs/diagnostics/aspirecsharpapps001.mdx | 3 +- .../aspiredockerfilebuilder001.mdx | 3 +- .../diagnostics/aspiredotnetproject001.mdx | 5 ++- .../docs/diagnostics/aspiredotnettool001.mdx | 3 +- .../docs/diagnostics/aspiredurabletask001.mdx | 11 ++--- .../docs/diagnostics/aspireextension001.mdx | 3 +- .../diagnostics/aspirehostingpython001.mdx | 3 +- .../docs/diagnostics/aspirejavascript001.mdx | 11 ++--- .../content/docs/diagnostics/aspiremcp001.mdx | 3 +- .../docs/diagnostics/aspirepersistence001.mdx | 9 ++-- .../docs/diagnostics/aspirepipelines003.mdx | 3 +- .../docs/diagnostics/aspirepostgres001.mdx | 5 ++- .../docs/diagnostics/aspireprobes001.mdx | 3 +- .../diagnostics/aspireprocesscommand001.mdx | 3 +- .../docs/diagnostics/aspireprojects001.mdx | 3 +- .../docs/diagnostics/aspireradius003.mdx | 1 + .../docs/diagnostics/aspireterminal001.mdx | 3 +- .../docs/diagnostics/aspireusersecrets001.mdx | 5 ++- .../src/content/docs/diagnostics/overview.mdx | 14 +++--- .../docs/extensibility/custom-resources.mdx | 5 ++- .../extensibility/interaction-service.mdx | 3 +- .../multi-language-integration-authoring.mdx | 3 +- .../fundamentals/annotations-overview.mdx | 9 ++-- .../fundamentals/container-networking.mdx | 3 +- .../fundamentals/custom-resource-commands.mdx | 5 ++- .../fundamentals/custom-resource-urls.mdx | 11 ++--- .../fundamentals/environment-variables.mdx | 5 ++- .../docs/fundamentals/external-parameters.mdx | 13 +++--- .../docs/fundamentals/health-checks.mdx | 7 +-- .../docs/fundamentals/http-commands.mdx | 3 +- .../docs/fundamentals/networking-overview.mdx | 9 ++-- .../fundamentals/persist-data-volumes.mdx | 13 +++--- .../docs/fundamentals/service-discovery.mdx | 5 ++- .../get-started/add-aspire-existing-app.mdx | 2 +- .../docs/get-started/ai-coding-agents.mdx | 1 + .../content/docs/get-started/aspire-sdk.mdx | 3 +- .../get-started/aspire-vscode-extension.mdx | 1 + .../ai/github-models/github-models-host.mdx | 5 ++- .../integrations/ai/ollama/ollama-connect.mdx | 3 +- .../integrations/ai/ollama/ollama-host.mdx | 9 ++-- .../integrations/ai/openai/openai-host.mdx | 9 ++-- .../caching/garnet/garnet-connect.mdx | 3 +- .../caching/garnet/garnet-host.mdx | 7 +-- .../redis-distributed-get-started.mdx | 3 +- .../redis-distributed-host.mdx | 11 ++--- .../integrations/caching/redis-extensions.mdx | 5 ++- .../caching/redis/redis-connect.mdx | 3 +- .../integrations/caching/redis/redis-host.mdx | 9 ++-- .../caching/valkey/valkey-connect.mdx | 3 +- .../caching/valkey/valkey-host.mdx | 9 ++-- .../integrations/cloud/azure/aks/index.mdx | 9 ++-- .../azure-ai-foundry-connect.mdx | 3 +- .../azure-ai-foundry-get-started.mdx | 5 ++- .../azure-ai-foundry-host.mdx | 43 +++++++++--------- .../azure-ai-inference-host.mdx | 3 +- .../azure-ai-search/azure-ai-search-host.mdx | 9 ++-- .../azure-app-configuration-host.mdx | 19 ++++---- .../azure-app-service-get-started.mdx | 3 +- .../azure-app-service-host.mdx | 13 +++--- .../azure/azure-application-insights.mdx | 9 ++-- .../azure-cache-redis-connect.mdx | 5 ++- .../azure-cache-redis-host.mdx | 13 +++--- .../cloud/azure/azure-connector-namespace.mdx | 5 ++- .../azure-container-registry-connect.mdx | 5 ++- .../azure-container-registry-get-started.mdx | 3 +- .../azure-container-registry-host.mdx | 15 ++++--- .../azure-cosmos-db-connect.mdx | 5 ++- .../azure-cosmos-db/azure-cosmos-db-host.mdx | 27 +++++------ .../cloud/azure/azure-data-explorer.mdx | 11 ++--- .../cloud/azure/azure-default-credential.mdx | 3 +- .../azure-event-hubs-host.mdx | 19 ++++---- .../cloud/azure/azure-front-door.mdx | 11 ++--- .../azure-functions-connect.mdx | 3 +- .../azure-functions-get-started.mdx | 3 +- .../azure-functions/azure-functions-host.mdx | 15 ++++--- .../azure-key-vault/azure-key-vault-host.mdx | 17 +++---- .../cloud/azure/azure-log-analytics.mdx | 7 +-- .../azure/azure-openai/azure-openai-host.mdx | 13 +++--- .../azure-postgresql-connect.mdx | 3 +- .../azure-postgresql-get-started.mdx | 3 +- .../azure-postgresql-host.mdx | 19 ++++---- .../azure-service-bus-host.mdx | 21 ++++----- .../azure-signalr/azure-signalr-connect.mdx | 3 +- .../azure-signalr/azure-signalr-host.mdx | 13 +++--- .../azure-sql-database-connect.mdx | 5 ++- .../azure-sql-database-get-started.mdx | 5 ++- .../azure-sql-database-host.mdx | 19 ++++---- .../azure-storage-blobs-connect.mdx | 7 +-- .../azure-storage-blobs-host.mdx | 21 ++++----- .../cloud/azure/azure-storage-datalake.mdx | 7 +-- .../azure-storage-queues-connect.mdx | 3 +- .../azure-storage-queues-get-started.mdx | 3 +- .../azure-storage-queues-host.mdx | 13 +++--- .../azure-storage-tables-connect.mdx | 3 +- .../azure-storage-tables-get-started.mdx | 3 +- .../azure-storage-tables-host.mdx | 21 ++++----- .../cloud/azure/azure-virtual-network.mdx | 37 +++++++-------- .../azure-web-pubsub-connect.mdx | 3 +- .../azure-web-pubsub-host.mdx | 13 +++--- .../cloud/azure/configure-container-apps.mdx | 17 +++---- .../cloud/azure/container-app-jobs.mdx | 9 ++-- .../cloud/azure/customize-resources.mdx | 13 +++--- .../cloud/azure/local-provisioning.mdx | 5 ++- .../integrations/cloud/azure/overview.mdx | 13 +++--- .../cloud/azure/user-assigned-identity.mdx | 7 +-- .../docs/integrations/compute/docker.mdx | 31 ++++++------- .../docs/integrations/compute/floci.mdx | 7 +-- .../content/docs/integrations/compute/k3s.mdx | 17 +++---- .../docs/integrations/compute/kubernetes.mdx | 13 +++--- .../hosting-integrations.mdx | 7 +-- .../secure-communication.mdx | 3 +- .../clickhouse/clickhouse-connect.mdx | 3 +- .../databases/clickhouse/clickhouse-host.mdx | 5 ++- .../azure-cosmos-db/azure-cosmos-db-host.mdx | 11 ++--- .../azure-sql/azure-sql-get-started.mdx | 3 +- .../efcore/azure-sql/azure-sql-host.mdx | 11 ++--- .../databases/efcore/migrations.mdx | 9 ++-- .../efcore/mongodb/mongodb-efcore-connect.mdx | 3 +- .../databases/efcore/mysql/mysql-connect.mdx | 3 +- .../databases/efcore/oracle/oracle-host.mdx | 9 ++-- .../efcore/postgres/postgresql-connect.mdx | 3 +- .../databases/efcore/seed-database.mdx | 5 ++- .../efcore/sql-server/sql-server-connect.mdx | 3 +- .../elasticsearch/elasticsearch-connect.mdx | 5 ++- .../elasticsearch/elasticsearch-host.mdx | 3 +- .../databases/kurrentdb/kurrentdb-connect.mdx | 3 +- .../meilisearch/meilisearch-connect.mdx | 3 +- .../meilisearch/meilisearch-host.mdx | 7 +-- .../databases/milvus/milvus-host.mdx | 5 ++- .../databases/mongodb/mongodb-extensions.mdx | 5 ++- .../databases/mongodb/mongodb-host.mdx | 25 ++++++----- .../databases/mysql/mysql-extensions.mdx | 7 +-- .../databases/mysql/mysql-get-started.mdx | 3 +- .../databases/mysql/mysql-host.mdx | 9 ++-- .../databases/postgres/postgres-host.mdx | 13 +++--- .../postgres/postgresql-extensions.mdx | 9 ++-- .../databases/ravendb/ravendb-connect.mdx | 3 +- .../databases/ravendb/ravendb-host.mdx | 3 +- .../sql-server/sql-server-extensions.mdx | 7 +-- .../databases/sql-server/sql-server-host.mdx | 9 ++-- .../databases/sqlite/sqlite-connect.mdx | 3 +- .../databases/sqlite/sqlite-get-started.mdx | 3 +- .../databases/sqlite/sqlite-host.mdx | 5 ++- .../databases/surrealdb/surrealdb-connect.mdx | 3 +- .../databases/surrealdb/surrealdb-host.mdx | 7 +-- .../integrations/devtools/browser-logs.mdx | 3 +- .../integrations/devtools/dab/dab-host.mdx | 3 +- .../integrations/devtools/dev-tunnels.mdx | 7 +-- .../devtools/flagd/flagd-host.mdx | 5 ++- .../devtools/goff/goff-connect.mdx | 3 +- .../integrations/devtools/goff/goff-host.mdx | 9 ++-- .../docs/integrations/devtools/k6/k6-host.mdx | 11 ++--- .../devtools/mailpit/mailpit-connect.mdx | 3 +- .../sql-projects/sql-projects-host.mdx | 13 +++--- .../integrations/dotnet/blazor-connect.mdx | 3 +- .../dotnet/blazor-get-started.mdx | 5 ++- .../integrations/dotnet/blazor-hosting.mdx | 2 +- .../dotnet/csharp-file-based-apps.mdx | 5 ++- .../dotnet/dotnet-tool-resources.mdx | 15 ++++--- .../integrations/dotnet/launch-profiles.mdx | 7 +-- .../content/docs/integrations/dotnet/maui.mdx | 5 ++- .../integrations/dotnet/project-resources.mdx | 15 ++++--- .../docs/integrations/frameworks/bun-apps.mdx | 5 ++- .../frameworks/deno/deno-get-started.mdx | 3 +- .../frameworks/deno/deno-host.mdx | 11 ++--- .../frameworks/dotnet/dotnet-get-started.mdx | 5 ++- .../frameworks/dotnet/dotnet-host.mdx | 9 ++-- .../frameworks/go/go-get-started.mdx | 3 +- .../integrations/frameworks/go/go-host.mdx | 19 ++++---- .../frameworks/java/java-connect.mdx | 4 +- .../integrations/frameworks/javascript.mdx | 31 ++++++------- .../frameworks/nodejs-extensions.mdx | 11 ++--- .../docs/integrations/frameworks/orleans.mdx | 5 ++- .../frameworks/perl/perl-get-started.mdx | 3 +- .../frameworks/perl/perl-host.mdx | 23 +++++----- .../frameworks/powershell/powershell-host.mdx | 11 ++--- .../docs/integrations/frameworks/python.mdx | 25 ++++++----- .../frameworks/rust/rust-host.mdx | 2 +- .../integrations/frameworks/wpf-winforms.mdx | 3 +- .../apache-kafka/apache-kafka-host.mdx | 3 +- .../messaging/lavinmq/lavinmq-host.mdx | 5 ++- .../messaging/nats/nats-get-started.mdx | 3 +- .../integrations/messaging/nats/nats-host.mdx | 3 +- .../messaging/rabbitmq/rabbitmq-connect.mdx | 3 +- .../messaging/rabbitmq/rabbitmq-host.mdx | 7 +-- .../observability/seq/seq-connect.mdx | 3 +- .../integrations/reverse-proxies/yarp.mdx | 11 ++--- .../docs/integrations/security/keycloak.mdx | 19 ++++---- .../ja/app-host/certificate-configuration.mdx | 11 ++--- .../docs/ja/app-host/container-files.mdx | 9 ++-- .../docs/ja/app-host/container-registry.mdx | 5 ++- .../src/content/docs/ja/app-host/eventing.mdx | 13 +++--- .../docs/ja/app-host/executable-resources.mdx | 9 ++-- .../app-host/migrate-from-docker-compose.mdx | 21 ++++----- .../docs/ja/app-host/resource-lifetimes.mdx | 5 ++- .../docs/ja/app-host/withdockerfile.mdx | 9 ++-- .../multi-language-architecture.mdx | 5 ++- .../ja/architecture/resource-api-patterns.mdx | 3 +- .../ja/architecture/resource-examples.mdx | 2 + .../ja/architecture/resource-hierarchies.mdx | 7 +-- .../ja/architecture/resource-publishing.mdx | 3 +- .../content/docs/ja/deployment/pipelines.mdx | 9 ++-- .../ja/extensibility/custom-resources.mdx | 5 ++- .../ja/extensibility/interaction-service.mdx | 3 +- .../multi-language-integration-authoring.mdx | 3 +- .../fundamentals/custom-resource-commands.mdx | 3 +- .../ja/fundamentals/custom-resource-urls.mdx | 11 ++--- .../ja/fundamentals/external-parameters.mdx | 13 +++--- .../docs/ja/fundamentals/health-checks.mdx | 7 +-- .../docs/ja/fundamentals/http-commands.mdx | 3 +- .../ja/fundamentals/networking-overview.mdx | 9 ++-- .../ja/fundamentals/persist-data-volumes.mdx | 13 +++--- .../ja/fundamentals/service-discovery.mdx | 5 ++- .../get-started/add-aspire-existing-app.mdx | 9 ++-- .../docs/ja/get-started/aspire-mcp-server.mdx | 3 +- .../get-started/aspire-vscode-extension.mdx | 1 + .../docs/ja/get-started/deploy-first-app.mdx | 9 ++-- .../src/content/docs/ja/get-started/faq.mdx | 6 ++- .../content/docs/ja/get-started/first-app.mdx | 17 +++---- .../ja/get-started/resource-mcp-servers.mdx | 5 ++- .../docs/ja/get-started/troubleshooting.mdx | 5 ++- .../integrations/dotnet/launch-profiles.mdx | 7 +-- .../docs/ja/testing/accessing-resources.mdx | 3 +- .../docs/ja/testing/write-your-first-test.mdx | 3 +- .../content/docs/ja/whats-new/aspire-13-1.mdx | 11 ++--- .../content/docs/ja/whats-new/aspire-13-2.mdx | 33 +++++++------- .../content/docs/ja/whats-new/aspire-13-3.mdx | 33 +++++++------- .../content/docs/ja/whats-new/aspire-13.mdx | 43 +++++++++--------- .../cli/commands/aspire-docs-api-search.mdx | 3 +- .../reference/cli/commands/aspire-init.mdx | 3 +- .../docs/testing/accessing-resources.mdx | 3 +- .../docs/testing/advanced-scenarios.mdx | 7 +-- .../docs/testing/write-your-first-test.mdx | 3 +- .../content/docs/whats-new/aspire-13-1.mdx | 11 ++--- .../content/docs/whats-new/aspire-13-2.mdx | 35 ++++++++------- .../content/docs/whats-new/aspire-13-3.mdx | 33 +++++++------- .../content/docs/whats-new/aspire-13-4.mdx | 33 +++++++------- .../content/docs/whats-new/aspire-13-5.mdx | 19 ++++---- .../content/docs/whats-new/aspire-13-6.mdx | 43 +++++++++--------- .../src/content/docs/whats-new/aspire-13.mdx | 45 ++++++++++--------- .../src/content/docs/whats-new/aspire-9-1.mdx | 5 ++- .../src/content/docs/whats-new/aspire-9-2.mdx | 11 ++--- .../src/content/docs/whats-new/aspire-9-3.mdx | 33 +++++++------- .../src/content/docs/whats-new/aspire-9-4.mdx | 21 ++++----- .../src/content/docs/whats-new/aspire-9-5.mdx | 23 +++++----- .../src/content/docs/whats-new/aspire-9.mdx | 13 +++--- .../tests/unit/api-reference.vitest.test.ts | 12 +++++ .../dashboard-image-references.vitest.test.ts | 4 +- 296 files changed, 1444 insertions(+), 1137 deletions(-) diff --git a/src/frontend/src/content/docs/app-host/certificate-configuration.mdx b/src/frontend/src/content/docs/app-host/certificate-configuration.mdx index 7acf8fc54..3ade07657 100644 --- a/src/frontend/src/content/docs/app-host/certificate-configuration.mdx +++ b/src/frontend/src/content/docs/app-host/certificate-configuration.mdx @@ -6,13 +6,14 @@ description: Configure HTTPS endpoints and certificate trust for Aspire resource import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; import OsAwareTabs from '@components/OsAwareTabs.astro'; +import ApiReference from '@components/ApiReference.astro'; Aspire provides two complementary sets of certificate APIs: 1. **HTTPS endpoint APIs**: Configure the certificates that resources use for their own HTTPS endpoints (server authentication) 2. **Certificate trust APIs**: Configure which certificates resources trust when making outbound HTTPS connections (client authentication) -Both sets of APIs work together to enable secure HTTPS communication during local development. For example, a Vite frontend might use `WithHttpsDeveloperCertificate` to serve HTTPS traffic, while also using `WithDeveloperCertificateTrust` to trust the dashboard's OTLP endpoint certificate. +Both sets of APIs work together to enable secure HTTPS communication during local development. For example, a Vite frontend might use to serve HTTPS traffic, while also using to trust the dashboard's OTLP endpoint certificate. -Use the `AddContainerRegistry` method to configure a generic container registry for your application. This works with any Docker-compatible registry including DockerHub, GitHub Container Registry, Harbor, and private registries. +Use the method to configure a generic container registry for your application. This works with any Docker-compatible registry including DockerHub, GitHub Container Registry, Harbor, and private registries. ### Basic usage @@ -303,7 +304,7 @@ In the preceding example: ### Using an existing ACR -To use an existing Azure Container Registry, call the `PublishAsExisting` method when you add the ACR: +To use an existing Azure Container Registry, call the method when you add the ACR: diff --git a/src/frontend/src/content/docs/app-host/eventing.mdx b/src/frontend/src/content/docs/app-host/eventing.mdx index ba6dafd55..f45685daa 100644 --- a/src/frontend/src/content/docs/app-host/eventing.mdx +++ b/src/frontend/src/content/docs/app-host/eventing.mdx @@ -6,6 +6,7 @@ description: Use the Aspire AppHost eventing APIs for lifecycle events, custom e import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; +import ApiReference from '@components/ApiReference.astro'; In Aspire, eventing allows you to publish and subscribe to events during various AppHost life cycles. Eventing is more flexible than life cycle events. Both let you run arbitrary code during event callbacks, but eventing offers finer control of event timing, publishing, and provides supports for custom events. @@ -110,7 +111,7 @@ builder.Eventing.Subscribe( `builder.Eventing.Subscribe()` API. Use the named callback APIs generated for each supported event, such as `subscribeBeforeStart`, `subscribeAfterResourcesCreated`, `addEventingSubscriber`, and resource - callbacks like `onResourceReady`. + callbacks like . -- `OnInitializeResource` / `onInitializeResource`: Subscribes to the `InitializeResourceEvent`. -- `OnResourceEndpointsAllocated` / `onResourceEndpointsAllocated`: Subscribes to the `ResourceEndpointsAllocatedEvent` event. -- `OnConnectionStringAvailable` / `onConnectionStringAvailable`: Subscribes to the `ConnectionStringAvailableEvent` event. -- `OnBeforeResourceStarted` / `onBeforeResourceStarted`: Subscribes to the `BeforeResourceStartedEvent` event. +- : Subscribes to the `InitializeResourceEvent`. +- : Subscribes to the `ResourceEndpointsAllocatedEvent` event. +- : Subscribes to the `ConnectionStringAvailableEvent` event. +- : Subscribes to the `BeforeResourceStartedEvent` event. - `OnResourceReady` / `onResourceReady`: Subscribes to the `ResourceReadyEvent` event. -- `OnResourceStopped` / `onResourceStopped`: Subscribes to the `ResourceStoppedEvent` event. +- : Subscribes to the `ResourceStoppedEvent` event. When the AppHost is run, by the time the Aspire dashboard is displayed, you should see the following log output in the console: diff --git a/src/frontend/src/content/docs/app-host/executable-resources.mdx b/src/frontend/src/content/docs/app-host/executable-resources.mdx index d02b1ead8..118f282e6 100644 --- a/src/frontend/src/content/docs/app-host/executable-resources.mdx +++ b/src/frontend/src/content/docs/app-host/executable-resources.mdx @@ -4,8 +4,9 @@ description: Host external executable applications in your Aspire AppHost using --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import ApiReference from '@components/ApiReference.astro'; -In Aspire, you can host external executable applications alongside your projects using the `AddExecutable` method. This capability is useful when you need to integrate executable applications or tools into your distributed application, such as Node.js applications, Python scripts, or specialized CLI tools. +In Aspire, you can host external executable applications alongside your projects using the method. This capability is useful when you need to integrate executable applications or tools into your distributed application, such as Node.js applications, Python scripts, or specialized CLI tools. ## When to use executable resources @@ -122,7 +123,7 @@ const app = await builder.addExecutable("worker", "python", ".", ["worker.py"]) -When one resource depends on another, `WithReference` passes along environment variables containing the dependent resource's connection details. For example, the `worker` executable's reference to `redis` and `postgres` provides it with the `ConnectionStrings__cache` and `ConnectionStrings__appdb` environment variables, which contain connection strings to these resources. +When one resource depends on another, passes along environment variables containing the dependent resource's connection details. For example, the `worker` executable's reference to `redis` and `postgres` provides it with the `ConnectionStrings__cache` and `ConnectionStrings__appdb` environment variables, which contain connection strings to these resources. ### Access specific endpoint information @@ -282,7 +283,7 @@ When upgrading to Aspire 13.3, replace every earlier per-kind environment helper ## Publishing with PublishAsDockerFile -For production deployment, executable resources need to be containerized. Use the `PublishAsDockerFile` method to specify how the executable should be packaged: +For production deployment, executable resources need to be containerized. Use the method to specify how the executable should be packaged: @@ -353,7 +354,7 @@ When working with executable resources: 1. **Use explicit paths**: For better reliability, use full paths to executables when possible. 1. **Handle dependencies**: Use `WithReference` to establish proper dependency relationships. -1. **Configure explicit start**: Use `WithExplicitStart()` for executables that shouldn't start automatically. +1. **Configure explicit start**: Use for executables that shouldn't start automatically. 1. **Prepare for deployment**: Always use `PublishAsDockerFile()` for production scenarios. 1. **Environment isolation**: Use environment variables rather than command-line arguments for sensitive configuration. 1. **Resource naming**: Use descriptive names that clearly identify the executable's purpose. diff --git a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx index 249a48645..c69a2f18d 100644 --- a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx +++ b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx @@ -5,6 +5,7 @@ description: Compare Aspire and Docker Compose for local development, service di import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; +import ApiReference from '@components/ApiReference.astro'; Docker Compose and Aspire both describe and run multi-service applications. This guide compares their local development workflows and maps Compose services, dependencies, and configuration to an Aspire AppHost written in TypeScript or C#. @@ -157,17 +158,17 @@ await builder.build().run(); **Key differences explained:** - **Build vs. project** — Docker Compose `build:` services become `AddProject()` for .NET apps, which runs them directly instead of in containers - **Ports** — Both examples explicitly map ports (3000 and 5000) -- **Startup order** — Docker Compose uses `depends_on` with health conditions; Aspire uses `WaitFor()` for startup ordering -- **Service discovery** — `WithReference()` only configures service discovery and connection strings; it doesn't control startup order -- **Connection strings** — By default, `WithReference(database)` provides `ConnectionStrings__myapp` using the resource name from `AddDatabase()`. To match a different name like `DefaultConnection`, use a named reference: `.WithReference(database, "DefaultConnection")` -- **Volumes** — `WithDataVolume()` must be called explicitly to add persistent storage; it's not automatic +- **Startup order** — Docker Compose uses `depends_on` with health conditions; Aspire uses for startup ordering +- **Service discovery** — only configures service discovery and connection strings; it doesn't control startup order +- **Connection strings** — By default, `WithReference(database)` provides `ConnectionStrings__myapp` using the resource name from . To match a different name like `DefaultConnection`, use a named reference: `.WithReference(database, "DefaultConnection")` +- **Volumes** — must be called explicitly to add persistent storage; it's not automatic - **Image versions** — `WithImageTag("15")` pins PostgreSQL to version 15 ### Container-based services @@ -277,13 +278,13 @@ Aspire generates .NET-format connection strings, which differ from Docker Compos - Docker Compose: `DATABASE_URL=postgresql://postgres:secret@postgres:5432/main` - Aspire: `ConnectionStrings__main=Host=localhost;Port=12345;Username=postgres;Password=;Database=main` -If your application expects URL-format environment variables, construct them manually with `WithEnvironment()`. See [Environment variables and configuration](#environment-variables-and-configuration) for details. +If your application expects URL-format environment variables, construct them manually with . See [Environment variables and configuration](#environment-variables-and-configuration) for details. **Key differences explained:** -- **Image versions** — Explicitly specified with `WithImageTag()` to match Docker Compose -- **Dockerfile builds** — Docker Compose `build: .` maps to `AddDockerfile("web", ".")`, which builds a container image from a Dockerfile. Use `AddContainer()` for pre-built images that use `image:` in Docker Compose +- **Image versions** — Explicitly specified with to match Docker Compose +- **Dockerfile builds** — Docker Compose `build: .` maps to `AddDockerfile("web", ".")`, which builds a container image from a Dockerfile. Use for pre-built images that use `image:` in Docker Compose - **Ports** — `WithHostPort()` maps to a static host port; without it, Aspire assigns a random port - **Volumes** — `WithDataVolume()` must be called explicitly to add persistent storage - **Startup ordering** — `WaitFor()` controls startup order, similar to Docker Compose `depends_on` with conditions @@ -462,7 +463,7 @@ await builder.build().run(); **Key differences:** - **Named volumes** — Created with `AddVolume()` and shared between containers -- **Bind mounts** — Use `WithBindMount()` for host directory access +- **Bind mounts** — Use for host directory access ### Networking @@ -532,14 +533,14 @@ Successfully migrating from Docker Compose to Aspire requires a systematic appro - **Configure dependencies** with `WithReference()` for service discovery - **Add startup ordering** with `WaitFor()` to match `depends_on` behavior - **Set up environment variables** — Note that connection string formats will differ - - **Migrate health checks** — Use `WithHttpHealthCheck()` or `WithHealthCheck()` for custom checks + - **Migrate health checks** — Use or for custom checks 4. ### Handle data migration For persistent data: - Use `WithDataVolume()` for automatic volume management with integrations - - Use `WithVolume()` for named volumes that need to persist data + - Use for named volumes that need to persist data - Use `WithBindMount()` for host directory mounts when you need direct access to host files 5. ### Test and validate diff --git a/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx b/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx index a39514c1c..22214da3d 100644 --- a/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx +++ b/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx @@ -10,6 +10,7 @@ import LearnMore from '@components/LearnMore.astro'; import persistentContainer from '@assets/fundamentals/persistent-container-dark.png'; import persistentContainerLight from '@assets/fundamentals/persistent-container-light.png'; import persistentContainerDocker from '@assets/whats-new/aspire-9/persistent-container-docker-desktop.png'; +import ApiReference from '@components/ApiReference.astro'; Aspire resources support a number of different lifetime modes. For example, the default **session lifetime** starts a resource when the AppHost starts and shuts it down when the AppHost exits. A **persistent lifetime** leaves a resource running when the AppHost exits and can reuse the same instance on the next run. @@ -29,11 +30,11 @@ A session lifetime creates the resource when the AppHost starts and disposes of Use session lifetime for resources that should only exist while the AppHost is running, such as local test dependencies, temporary containers, or processes that don't need stable state across runs. Session resources also default to proxied endpoints, which are available while the AppHost is running. -If you previously configured another lifetime and want to return a resource to the default behavior, call `WithSessionLifetime()`. For container resources, `WithLifetime(ContainerLifetime.Session)` is still supported. +If you previously configured another lifetime and want to return a resource to the default behavior, call . For container resources, `WithLifetime(ContainerLifetime.Session)` is still supported. ### Persistent lifetime -A persistent lifetime reuses a previously created resource when possible and doesn't dispose of it when the AppHost stops. Configure this behavior with `WithPersistentLifetime()`, or with the existing container-specific `WithLifetime(ContainerLifetime.Persistent)` API for container resources. +A persistent lifetime reuses a previously created resource when possible and doesn't dispose of it when the AppHost stops. Configure this behavior with , or with the existing container-specific `WithLifetime(ContainerLifetime.Persistent)` API for container resources. Use persistent lifetime for resources that are expensive to initialize, need stable local endpoints, or should remain available while you restart or rebuild the AppHost. Common examples include databases, message brokers, emulators, long-running executables, and project resources that should continue running after the AppHost exits. @@ -80,9 +81,9 @@ Aspire evaluates the source resource's lifetime when it prepares the application ## Defer resource start with explicit start -Use `WithExplicitStart()` to prevent a resource from starting automatically with the rest of the AppHost. The resource appears in the dashboard but remains stopped until you start it manually. +Use to prevent a resource from starting automatically with the rest of the AppHost. The resource appears in the dashboard but remains stopped until you start it manually. -Starting in Aspire 13.5, `WithExplicitStart()` also affects when execution configuration callbacks (for example, `WithEnvironment` and `WithArgs`) are evaluated, depending on whether the resource is session-scoped or persistent. +Starting in Aspire 13.5, `WithExplicitStart()` also affects when execution configuration callbacks (for example, and ) are evaluated, depending on whether the resource is session-scoped or persistent. ### Session-scoped explicit-start resources @@ -257,7 +258,7 @@ Persistent project and executable resources are run by Aspire's orchestrator so ## Match another resource's lifetime -Use `WithLifetimeOf` when a companion resource should follow another resource's lifetime. This is useful when a sidecar, helper process, or supporting service should become persistent only when its source resource is persistent. +Use when a companion resource should follow another resource's lifetime. This is useful when a sidecar, helper process, or supporting service should become persistent only when its source resource is persistent. @@ -305,7 +306,7 @@ The dependent resource's lifetime is evaluated when Aspire prepares the applicat ## Scope cleanup to a parent process -Use `WithParentProcessLifetime` when a resource should survive AppHost restarts but be cleaned up when another process exits. Aspire records the parent process identity instead of retaining a live process handle, so the cleanup scope follows the specific process instance instead of a reused process ID. +Use when a resource should survive AppHost restarts but be cleaned up when another process exits. Aspire records the parent process identity instead of retaining a live process handle, so the cleanup scope follows the specific process instance instead of a reused process ID. @@ -413,7 +414,7 @@ For example, if you have a service named `"postgres"` in an AppHost project loca ### Custom container names -For advanced scenarios, you can set a custom container name using the `WithContainerName` method: +For advanced scenarios, you can set a custom container name using the method: diff --git a/src/frontend/src/content/docs/app-host/typescript-apphost.mdx b/src/frontend/src/content/docs/app-host/typescript-apphost.mdx index 27c4a361c..6728fe5fc 100644 --- a/src/frontend/src/content/docs/app-host/typescript-apphost.mdx +++ b/src/frontend/src/content/docs/app-host/typescript-apphost.mdx @@ -7,6 +7,7 @@ description: Learn the files and configuration that make up a TypeScript AppHost import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; import FileTree from 'starlight-plugin-icons/components/FileTree.astro'; import LearnMore from '@components/LearnMore.astro'; +import ApiReference from '@components/ApiReference.astro'; When you create a TypeScript AppHost with `aspire new`, the CLI scaffolds a project with the following structure: @@ -295,7 +296,7 @@ The Aspire CLI supports the following package managers at the **AppHost root** | Deno | `packageManager`, `deno.lock`, `deno.json`, or `deno.jsonc` | Deno 2 or later | | Yarn Classic (v1) | `yarn.lock` with `# yarn lockfile v1` or `packageManager` with `yarn@1.x` | Not supported | -This policy governs the **AppHost root only**. Apps the AppHost orchestrates — for example, a Node.js service added with `addNodeApp`, a Bun guest app, or a workspace package — can use any package manager their own tooling requires; they are independent of the AppHost-root toolchain. +This policy governs the **AppHost root only**. Apps the AppHost orchestrates — for example, a Node.js service added with , a Bun guest app, or a workspace package — can use any package manager their own tooling requires; they are independent of the AppHost-root toolchain. Aspire end-to-end tests cover TypeScript AppHosts with representative `packageManager` pins such as `npm@10.0.0`, `pnpm@10.0.0`, `yarn@4.14.1`, and `bun@1.2.0`. These tested versions are representative points within the supported ranges, not the only versions you can use. @@ -456,7 +457,7 @@ Bun has built-in TypeScript support, so it runs `apphost.mts` directly without ` ### Use Deno as the AppHost runtime -Install Deno 2 or later and select it with a Deno configuration file, lockfile, or a `packageManager` entry such as `"deno@2.0.0"`. The generated AppHost module and resource APIs stay the same. This is distinct from [hosting a Deno application](/integrations/frameworks/deno/deno-host/): `addDenoApp` models a guest resource and doesn't choose the AppHost runtime. +Install Deno 2 or later and select it with a Deno configuration file, lockfile, or a `packageManager` entry such as `"deno@2.0.0"`. The generated AppHost module and resource APIs stay the same. This is distinct from [hosting a Deno application](/integrations/frameworks/deno/deno-host/): models a guest resource and doesn't choose the AppHost runtime. Aspire restores dependencies with `deno install` and validates the AppHost with `deno check`. Deno uses its own configuration rather than `tsconfig.apphost.json`. Watch mode uses Deno's native watcher and checks types on every restart, without `tsx` or `nodemon`. The CLI rejects Deno 1.x. diff --git a/src/frontend/src/content/docs/app-host/with-terminal.mdx b/src/frontend/src/content/docs/app-host/with-terminal.mdx index 3f7ebb319..40f341228 100644 --- a/src/frontend/src/content/docs/app-host/with-terminal.mdx +++ b/src/frontend/src/content/docs/app-host/with-terminal.mdx @@ -10,8 +10,9 @@ import terminalResourceDark from '@assets/dashboard/terminals/terminal-resource- import terminalResourceLight from '@assets/dashboard/terminals/terminal-resource-light.png'; import terminalDetachedDark from '@assets/dashboard/terminals/terminal-detached-dark.png'; import terminalDetachedLight from '@assets/dashboard/terminals/terminal-detached-light.png'; +import ApiReference from '@components/ApiReference.astro'; -If you have a terminal user interface (TUI) application or a shell-based experience that you want to exercise while it runs under Aspire, add `WithTerminal(...)` to the resource. Aspire then exposes an interactive terminal session that you can attach to from the [Aspire dashboard](/dashboard/overview/) or from the [`aspire terminal`](/reference/cli/commands/aspire-terminal/) CLI command. +If you have a terminal user interface (TUI) application or a shell-based experience that you want to exercise while it runs under Aspire, add to the resource. Aspire then exposes an interactive terminal session that you can attach to from the [Aspire dashboard](/dashboard/overview/) or from the [`aspire terminal`](/reference/cli/commands/aspire-terminal/) CLI command. For an introduction to the resource Terminal view, terminal dock, and detached windows, start with [Dashboard terminals](/dashboard/terminals/). @@ -78,7 +79,7 @@ Reach for `WithTerminal` when a resource is interactive rather than a plain back The [TypeScript terminal basics sample](https://github.com/microsoft/aspire-samples/tree/main/samples/terminals/basics-typescript) and [C# terminal basics sample](https://github.com/microsoft/aspire-samples/tree/main/samples/terminals/basics-csharp) demonstrate this with a containerized REST client, an API, and Redis. -The [TypeScript AppHost](https://github.com/microsoft/aspire-samples/blob/main/samples/terminals/basics-typescript/apphost.mts) and [C# AppHost](https://github.com/microsoft/aspire-samples/blob/main/samples/terminals/basics-csharp/apphost.cs) build the client's image with `AddDockerfile`, pass the API endpoint through `BASE_URL`, wait for the API, and enable the terminal with `WithTerminal()`. The client runs as the resource's main process; there is no separate client session to create. +The [TypeScript AppHost](https://github.com/microsoft/aspire-samples/blob/main/samples/terminals/basics-typescript/apphost.mts) and [C# AppHost](https://github.com/microsoft/aspire-samples/blob/main/samples/terminals/basics-csharp/apphost.cs) build the client's image with , pass the API endpoint through `BASE_URL`, wait for the API, and enable the terminal with `WithTerminal()`. The client runs as the resource's main process; there is no separate client session to create. Follow either sample's README to send a request from the resource terminal, change the stored data through Redis's separate REPL command, and read it back through the API. This illustrates the distinction between an interactive resource and an [ephemeral terminal](/dashboard/ephemeral-terminals/) without requiring host installations of the client tools. @@ -170,7 +171,7 @@ builder.Build().Run(); ## Terminals and replicas -Each replica of a resource gets its own independent terminal session. Aspire creates one terminal host per parent replica, so requesting three replicas yields three separate terminals. The order of `WithReplicas` and `WithTerminal` does not matter. For a project-based interactive app in `../Agent/Agent.csproj`: +Each replica of a resource gets its own independent terminal session. Aspire creates one terminal host per parent replica, so requesting three replicas yields three separate terminals. The order of and `WithTerminal` does not matter. For a project-based interactive app in `../Agent/Agent.csproj`: diff --git a/src/frontend/src/content/docs/app-host/withdockerfile.mdx b/src/frontend/src/content/docs/app-host/withdockerfile.mdx index df30b8257..0c1cbab72 100644 --- a/src/frontend/src/content/docs/app-host/withdockerfile.mdx +++ b/src/frontend/src/content/docs/app-host/withdockerfile.mdx @@ -5,8 +5,9 @@ description: Add Dockerfiles to your Aspire app model with WithDockerfile — bu --- import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; +import ApiReference from '@components/ApiReference.astro'; -With Aspire it's possible to specify a _Dockerfile_ to build when the [AppHost](/get-started/app-host/) is started using either the `AddDockerfile` or `WithDockerfile` extension methods. +With Aspire it's possible to specify a _Dockerfile_ to build when the [AppHost](/get-started/app-host/) is started using either the or extension methods. These two methods serve different purposes: @@ -126,7 +127,7 @@ await pgsql.withPgAdmin(); // Still works because it's still a PostgreSQL resour ## Generate a Dockerfile programmatically -Use `AddDockerfileBuilder` or `WithDockerfileBuilder` when you need Aspire to generate a Dockerfile from AppHost code. These APIs are useful when the Dockerfile depends on AppHost configuration, when you want to compose Dockerfile fragments, or when you want to keep multi-stage image build logic near the resource definition. +Use or when you need Aspire to generate a Dockerfile from AppHost code. These APIs are useful when the Dockerfile depends on AppHost configuration, when you want to compose Dockerfile fragments, or when you want to keep multi-stage image build logic near the resource definition.