diff --git a/src/frontend/config/sidebar/deployment.topics.ts b/src/frontend/config/sidebar/deployment.topics.ts index 40a20221a..5826b9a6c 100644 --- a/src/frontend/config/sidebar/deployment.topics.ts +++ b/src/frontend/config/sidebar/deployment.topics.ts @@ -130,6 +130,10 @@ export const deploymentTopics: StarlightSidebarTopicsUserConfig = { label: 'Docker Compose', slug: 'deployment/docker-compose', }, + { + label: 'Radius', + slug: 'deployment/radius', + }, { label: 'Kubernetes', collapsed: false, diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index 2267e1b32..8fe87bb1e 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -315,6 +315,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { label: 'Configure Azure Container Apps', slug: 'integrations/cloud/azure/configure-container-apps', }, + { + label: 'Azure Connector Namespace', + slug: 'integrations/cloud/azure/azure-connector-namespace', + }, { label: 'Default Azure credential', slug: 'integrations/cloud/azure/azure-default-credential', 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 ddee03826..29984ed37 100644 --- a/src/frontend/src/content/docs/app-host/typescript-apphost.mdx +++ b/src/frontend/src/content/docs/app-host/typescript-apphost.mdx @@ -292,6 +292,7 @@ The Aspire CLI supports the following package managers at the **AppHost root** | pnpm | `packageManager` or `pnpm-lock.yaml` | pnpm 10 or later | | Yarn | `packageManager`, `yarn.lock`, `.yarnrc.yml`, or `.yarn/` | Yarn 4 or later (Berry) | | Bun | `packageManager`, `bun.lock`, or `bun.lockb` | Bun 1.2 or later | +| 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. @@ -299,7 +300,7 @@ This policy governs the **AppHost root only**. Apps the AppHost orchestrates — 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. +## Hostname inheritance + +`WithHostname` / `withHostname` on an Ingress or Gateway supplies the hostname for paths and routes that don't specify one. A hostname supplied explicitly to a path or route takes precedence. This lets you configure one shared hostname without accidentally publishing the hostless paths as catch-all rules. + +`WithDefaultBackend` / `withDefaultBackend` is a catch-all and doesn't inherit that hostname, including the TLS compatibility rule generated for it. + ## TLS and certificates When you configure TLS with `WithTls()`, Aspire handles the initial bootstrapping: diff --git a/src/frontend/src/content/docs/deployment/kubernetes/aks.mdx b/src/frontend/src/content/docs/deployment/kubernetes/aks.mdx index ad5f28e41..57b3a9377 100644 --- a/src/frontend/src/content/docs/deployment/kubernetes/aks.mdx +++ b/src/frontend/src/content/docs/deployment/kubernetes/aks.mdx @@ -506,6 +506,22 @@ aspire publish -o aks-artifacts This generates Helm charts and Bicep infrastructure templates that you can review, customize, and deploy using your own CI/CD pipeline or GitOps workflow. +## Clean up a deployment + +Run `aspire destroy` for the deployed AppHost and environment to remove its resources: + +```bash title="Destroy the selected AKS deployment" +aspire destroy --environment my-environment +``` + +Aspire acquires credentials for the target AKS cluster before running Kubernetes cleanup; it doesn't rely on a preselected ambient `kubectl` context. Helm cleanup, including external charts opted into uninstall and cert-manager cleanup, runs before deletion of the Azure provisioning resources. + +:::danger[Destructive operation] +Destroy removes the deployment's Azure resources, including the cluster. Review the selected environment and confirmation prompt before continuing, and back up data you need to retain. +::: + +See the [`aspire destroy` reference](/reference/cli/commands/aspire-destroy/) for AppHost selection and automation options. + ## Azure-specific considerations ### Authentication diff --git a/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx b/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx index 511f48eed..fa8deeb99 100644 --- a/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx +++ b/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx @@ -323,6 +323,46 @@ Resource names in Kubernetes must follow DNS naming conventions. The integration Use [external parameters](/fundamentals/external-parameters/) to configure values that differ between development and production environments. +### Parameters inside environment expressions + +Parameters embedded inside environment expressions are emitted as their own Helm values. For example, when a URL contains a host parameter, you can override that parameter at deployment time without reconstructing the entire URL. The publisher declares both the composed environment value and the nested parameter in `values.yaml`; deployment resolves the expression using the parameter's effective value. + +Use an Aspire reference expression for composition, not a TypeScript string interpolation of a resource handle: + + + + +```typescript title="apphost.mts" twoslash +import { createBuilder, refExpr } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); +await builder.addKubernetesEnvironment('k8s'); +const host = await builder.addParameter('host', { value: 'localhost' }); +const app = await builder.addContainer('app', 'nginx'); +await app.withEnvironment('SOME_URL', refExpr`http://${host}/test`); + +await builder.build().run(); +``` + + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); +builder.AddKubernetesEnvironment("k8s"); +var host = builder.AddParameter("host", "localhost"); + +builder.AddContainer("app", "nginx") + .WithEnvironment("SOME_URL", $"http://{host}/test"); + +builder.Build().Run(); +``` + + + + +Conflicting Helm value paths, including names that collide after normalization, fail publishing rather than overwriting another entry. + ### Service discovery In Kubernetes, services discover each other using the cluster's built-in DNS. A service named `api` is reachable at `api..svc.cluster.local`. The generated Helm charts configure service references automatically using Kubernetes-native DNS resolution. diff --git a/src/frontend/src/content/docs/deployment/radius.mdx b/src/frontend/src/content/docs/deployment/radius.mdx new file mode 100644 index 000000000..2cab98eb5 --- /dev/null +++ b/src/frontend/src/content/docs/deployment/radius.mdx @@ -0,0 +1,117 @@ +--- +title: Deploy Aspire applications with Radius +description: Publish Aspire apps to Radius, understand recipe-backed connection values and credentials, and resolve deployment and publish diagnostics. +--- + +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import InstallPackage from '@components/InstallPackage.astro'; + +Radius is a compute environment for `aspire publish` and `aspire deploy`. Adding it doesn't change local execution: `aspire run` still runs your resources locally. + +:::caution[Prototype integration] +`Aspire.Hosting.Radius` is an early prototype. Pin its package version and review generated Bicep before deploying. Cloud provider, recipe, and secret-store APIs have their own experimental diagnostics; runtime publish validation errors aren't compiler diagnostics you can suppress. +::: + +## Prerequisites + +- A Kubernetes cluster with Radius v0.60.0 or later; v0.60.2 is recommended +- The `rad` CLI on `PATH` and a workspace configured with `rad init` for your target cluster +- Container images that the cluster can pull + +Upgrade older control planes with `rad upgrade kubernetes`. Before deployment, Aspire checks the control plane targeted by the active Radius workspace, honoring `ASPIRE_RADIUS_KUBE_CONTEXT`. A detected version below v0.60 fails with `ASPIRERADIUS091`; an unreadable version isn't proof of compatibility. Older control planes can silently drop fields from the generated recipe pack. + +## Add the compute environment + + + + + + +```typescript title="apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); +const radius = await builder.addRadiusEnvironment('radius'); +const web = await builder.addContainer('web', 'nginx'); +await web.withHttpEndpoint({ targetPort: 80 }); +await web.withComputeEnvironment(radius); + +await builder.build().run(); +``` + + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); +var radius = builder.AddRadiusEnvironment("radius"); + +builder.AddContainer("web", "nginx") + .WithHttpEndpoint(targetPort: 80) + .WithComputeEnvironment(radius); + +builder.Build().Run(); +``` + + + + +Generate artifacts for review, then deploy to the configured environment: + +```bash title="Publish and deploy to Radius" +aspire publish -o radius-artifacts +aspire deploy +``` + +Container workloads are emitted as `Radius.Compute/containers`. Project resources require a prebuilt, pushed image attached with `WithContainerImage` / `withContainerImage`; the Radius publisher doesn't build that project image for you. Include any files requested by container-file publishing in the externally built image. + +## Understand recipe-backed connections + +Redis, PostgreSQL, MongoDB, SQL Server, and RabbitMQ are **backing resources** provisioned by Radius recipes, not ordinary container workloads. Recipes determine their deployed addresses. Aspire projects consumer connection strings, individual connection properties, URIs, and service-discovery values from the backing Radius resource, not from the local Aspire endpoint. + +| Resource | Deployed credential behavior | +| -------- | ---------------------------- | +| PostgreSQL | Required username and password properties receive the same parameters used by the consumer connection string | +| RabbitMQ | An explicit username is required; the password is supplied through a `Radius.Security/secrets` resource ID | +| MongoDB and SQL Server | Legacy `Applications.*` recipes generate credentials; consumers use recipe outputs, with warnings when explicit AppHost parameters are replaced | +| Redis | The pinned recipe deploys **without authentication**; generated passwords are discarded with `ASPIRERADIUS075`, while explicit passwords fail with `ASPIRERADIUS085` | + +Don't copy run-mode connection strings into deployment configuration. Host and port values come from the backing resource's properties, and legacy recipe passwords use `listSecrets()`. URI credential values are encoded before composition. Radius also injects `CONNECTION__` variables for its `connections` block; these don't replace Aspire's `ConnectionStrings__*` contract. + +Connection strings use [portable aliases](/fundamentals/environment-variables/#portable-connection-name-encoding). Connection-property prefixes retain their own rules: `db__primary` produces `DB__PRIMARY_PASSWORD`, while its connection-string alias is `ConnectionStrings__db_primary`. + +### Protect credential-bearing values + +Aspire publishes credential-bearing environment values through `valueFrom.secretKeyRef` backed by `Radius.Security/secrets`, rather than putting them directly in the Kubernetes Deployment specification. A recipe-generated `listSecrets()` expression avoids writing the resolved password in local publish artifacts, but it can still expose the resolved value in deployment records. Radius's own connection variables can also contain plaintext credentials. Restrict access to the cluster, deployment records, and secrets. + +For workloads that require authenticated Redis, provision a suitable service yourself instead of assuming the pinned unauthenticated recipe applies the local password. + +## Resolve publish diagnostics + +These runtime diagnostics identify unsupported projections or inconsistent output. Fix the application model or callback rather than suppressing them. + +| Diagnostic | Remediation | +| ---------- | ----------- | +| `ASPIRERADIUS070` | Review the warning that a recipe-generated credential replaces a referenced parameter | +| `ASPIRERADIUS072` | Reference only the database supported by the recipe; multiple child databases on one server aren't independently provisioned | +| `ASPIRERADIUS073`, `ASPIRERADIUS078`, `ASPIRERADIUS086` | Remove unsupported formatting, deploy-time conditions, or run-only values from published connection expressions | +| `ASPIRERADIUS074`, `ASPIRERADIUS084` | Keep backing constructs and generated environment secrets that consumers still reference | +| `ASPIRERADIUS075`, `ASPIRERADIUS085` | Review the unauthenticated Redis recipe; don't assume a supplied password will be installed | +| `ASPIRERADIUS076` | Supply the connection properties required by the mapped Radius resource type | +| `ASPIRERADIUS077` | Reference the primary endpoint instead of a secondary endpoint the recipe doesn't deploy | +| `ASPIRERADIUS080` | Review the warning for a named SQL Server child database the legacy recipe doesn't create | +| `ASPIRERADIUS081` | Don't project local TLS scheme, URL, or TLS-enabled values when the backing recipe has no transport-security output | +| `ASPIRERADIUS082` | Give RabbitMQ an explicit username rather than the loopback-only `guest` account | +| `ASPIRERADIUS083`, `ASPIRERADIUS087`, `ASPIRERADIUS088` | Use valid Kubernetes names and secret keys, and set either a literal environment value or a complete secret reference | +| `ASPIRERADIUS089` | Keep the broker's credential aligned with its consumers when customizing infrastructure | +| `ASPIRERADIUS090` | Rename colliding Kubernetes secrets, including collisions with generated `-env-secret` names | +| `ASPIRERADIUS091` | Upgrade the target Radius control plane to v0.60 or later | + +`ASPIRERADIUS071` and `ASPIRERADIUS079` indicate an internal resource-to-connection-schema mismatch. Report them with the package version and a minimal reproduction instead of substituting a local endpoint. + +## See also + +- [Radius installation](https://docs.radapp.io/installation/) +- [Radius integration configuration and recipe APIs](https://github.com/microsoft/aspire/blob/e8fd6fbb954f50ccd2e66479538392f65e13e71d/src/Aspire.Hosting.Radius/README.md) +- [Connection strings and environment variables](/fundamentals/environment-variables/) +- [Deployment state caching](/deployment/deployment-state-caching/) diff --git a/src/frontend/src/content/docs/diagnostics/aspiredotnetproject001.mdx b/src/frontend/src/content/docs/diagnostics/aspiredotnetproject001.mdx index 69adfd969..a6bba8c23 100644 --- a/src/frontend/src/content/docs/diagnostics/aspiredotnetproject001.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspiredotnetproject001.mdx @@ -4,7 +4,7 @@ seoTitle: 'ASPIREDOTNETPROJECT001: AddDotnetProject types and members' description: Learn what causes the Aspire compiler warning ASPIREDOTNETPROJECT001 and how to fix it so your AppHost builds cleanly. --- -import { Badge } from '@astrojs/starlight/components'; +import { Badge, Aside } from '@astrojs/starlight/components'; + + > AddDotnetProject types and members are for evaluation purposes only and are subject to change or removal in future updates. Suppress this diagnostic to proceed. -This diagnostic warning is reported when using experimental `AddDotnetProject` APIs from the `Aspire.Hosting.Dotnet` integration, including: +In Aspire 13.5, this diagnostic is reported when using the following experimental APIs from `Aspire.Hosting.Dotnet`: - `AddDotnetProject` extension methods - `DotnetProjectResource` These APIs add a C# project or file-based C# app to the application model as an `ExecutableResource` that's launched through the .NET SDK. -## Example +## Example in Aspire 13.5 The following code generates `ASPIREDOTNETPROJECT001`: @@ -36,7 +40,9 @@ builder.Build().Run(); ## To correct this warning -Suppress the warning with one of the following methods: +If you use Aspire 13.6 or later, these APIs don't need a diagnostic suppression. Remove suppressions that were added for them. + +For earlier versions, or the still-experimental [Dotnet project Blazor gateway](/integrations/dotnet/blazor-hosting/#add-a-blazor-gateway-for-a-c-project-resource), suppress the warning with one of the following methods: - Set the severity of the rule in the _.editorconfig_ file. diff --git a/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx b/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx index e1bcceae0..2ea965cdc 100644 --- a/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx +++ b/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx @@ -744,6 +744,8 @@ await myResource.withMyCallback(async (context) => { The `Action` delegate type is ATS-compatible. The TypeScript side receives an async function. If your exported method invokes that synchronous delegate inline, use `RunSyncOnBackgroundThread = true` on `[AspireExport]` so the runtime can process nested async callback responses without blocking the RPC dispatcher. ::: +Callback parameters typed as `Action>` (a builder for a concrete exported resource type, rather than a plain callback context) are marshalled using that concrete resource type's identity, so generated guest-language wrappers resolve to the correct typed handle at runtime — for example, a Python callback that receives a `RedisCommanderResource` builder can call `with_host_port` on it directly. + ## Services available from callback service providers Several ATS callback contexts expose an `IServiceProvider` handle through a `services()` or `serviceProvider()` accessor. These accessors are async `PropertyAccessor` values, so await them before using the returned service provider. For example, resource events expose `await event.services()`, command contexts expose `await context.serviceProvider()`, and `DistributedApplicationExecutionContext` exposes `await executionContext.serviceProvider()`. diff --git a/src/frontend/src/content/docs/fundamentals/environment-variables.mdx b/src/frontend/src/content/docs/fundamentals/environment-variables.mdx index aa92c1dea..03cbd126e 100644 --- a/src/frontend/src/content/docs/fundamentals/environment-variables.mdx +++ b/src/frontend/src/content/docs/fundamentals/environment-variables.mdx @@ -16,13 +16,13 @@ Aspire generates environment variables in different formats depending on the typ ### Connection strings -When you reference a resource that exposes a connection string (such as a database, cache, or messaging resource), Aspire generates an environment variable using the `ConnectionStrings__` prefix: +When you reference a resource that exposes a connection string (such as a database, cache, or messaging resource), Aspire keeps the resource name, or an explicit `connectionName`, as the **logical connection name**. The original environment variable uses the `ConnectionStrings__` prefix: ```txt ConnectionStrings__{resource-name} ``` -The resource name is used **as-is** (preserving the original casing and hyphens). For example: +Aspire also generates a **portable alias** for deployment targets with stricter environment-variable naming rules. The logical name doesn't change. For example: ```csharp title="C# — AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); @@ -38,18 +38,55 @@ var api = builder.AddProject("api") builder.Build().Run(); ``` -The `api` resource receives the following environment variables: +On targets that support both spellings, the `api` resource receives both aliases for each connection: -| Environment variable | Description | -| ----------------------------- | --------------------------------------------- | -| `ConnectionStrings__my-cache` | Connection string for the Redis cache | -| `ConnectionStrings__my-db` | Connection string for the PostgreSQL database | +| Original environment variable | Portable environment variable | Description | +| ----------------------------- | ----------------------------- | ----------- | +| `ConnectionStrings__my-cache` | `ConnectionStrings__my_cache` | Connection string for the Redis cache | +| `ConnectionStrings__my-db` | `ConnectionStrings__my_db` | Connection string for the PostgreSQL database | - +Portable connection names preserve casing, replace characters other than ASCII letters, digits, or underscores with `_`, prefix a leading digit with `_`, and collapse consecutive underscores to a single `_`. Collapsing underscores prevents the suffix from introducing another .NET configuration path delimiter (`__`). + +| Logical connection name | Portable environment variable | +| ----------------------- | ----------------------------- | +| `mydb` | `ConnectionStrings__mydb` | +| `my-db` | `ConnectionStrings__my_db` | +| `my--db` | `ConnectionStrings__my_db` | +| `my__db` | `ConnectionStrings__my_db` | +| `MyDb` | `ConnectionStrings__MyDb` | +| `1db` | `ConnectionStrings___1db` | + +The `ConnectionStrings__` prefix is unchanged; encoding applies only to the suffix. When both spellings are identical, Aspire emits one variable. + +Alias collision checks are case-insensitive. Different references that map to the same physical name, such as logical names `my-db` and `my_db`, fail during environment resolution instead of overwriting each other. Choose distinct explicit `connectionName` values on those references. + +An integration can override the physical name through `IResourceWithConnectionString.ConnectionStringEnvironmentVariable`. Aspire emits that exact name only, without normalization; `connectionName` doesn't rename it. Publishers still validate explicit and unrelated environment variables, so portable aliases don't make an arbitrary invalid variable name valid. + +#### Migrating connection-string consumers + +Update your Aspire client integrations alongside the AppHost packages. Updated integrations resolve `ConnectionStrings:` through the composed .NET configuration first, then try the portable key only if the logical lookup returns `null`. This isn't a provider-by-provider search across both aliases. + +Direct `IConfiguration.GetConnectionString` calls don't automatically translate hyphens or collapse underscores. For a known logical name such as `my-cache`, use the explicit fallback shown in [Accessing environment variables](#accessing-environment-variables). Applications that read environment variables directly can use the portable physical name. + +If you must keep an older client integration, set the reference's `connectionName` to a portable name such as `my_db` and use **that same name** in the application's client registration or configuration lookup. Changing the reference without changing the consumer isn't sufficient. + +Connection-property prefixes retain their separate encoding rules: in Radius, the logical name `db__primary` produces `DB__PRIMARY_PASSWORD` alongside `ConnectionStrings__db_primary`, not `DB_PRIMARY_PASSWORD`. + +#### Custom publishers and integrations + +For generated injections, inspect `ConnectionStringReference` values in the environment-variable dictionary, not resource annotations. Their `EnvironmentVariableNames` property exposes a `ConnectionStringEnvironmentVariableNames` record with `LogicalName`, `OriginalName`, `PortableName`, and `IsExplicit`. Its `Create` factory derives names from a resource and logical name; `GetPhysicalNames` enumerates the distinct physical aliases. + +:::caution[Experimental naming metadata] +`ConnectionStringEnvironmentVariableNames` and `ConnectionStringReference.EnvironmentVariableNames` are experimental under `ASPIRECONNECTIONSTRINGS001` and may change. This doesn't make ordinary `WithReference` usage experimental. +::: + +A standalone reference created with the existing two-argument constructor has no naming metadata. Don't infer that it's a generated alias. Resolve the reference's `ConnectionStringExpression`, not `Resource.ConnectionStringExpression`, because a reference can select another value on the same resource, such as Qdrant's HTTP connection. + +Publisher alias projection relies on at least one entry retaining its reference metadata. Replacing both entries with user-authored values removes that metadata, so normal environment-name validation applies instead. ### Endpoint URLs @@ -128,7 +165,7 @@ For example, a resource named `foundry-demo-proj` becomes `FOUNDRY_DEMO_PROJ` in @@ -136,11 +173,12 @@ Connection string variables (`ConnectionStrings__`) do **not** apply encoding to ### C\# -In .NET applications, Aspire client integrations handle environment variable access automatically. For manual access: +In .NET applications, updated Aspire client integrations handle connection-string alias lookup automatically. For manual access, try the logical key first and then its portable form: ```csharp title="C# — Program.cs" // Connection strings -string cache = builder.Configuration.GetConnectionString("my-cache"); +string? cache = builder.Configuration.GetConnectionString("my-cache") + ?? builder.Configuration.GetConnectionString("my_cache"); // Endpoint URLs string apiUrl = builder.Configuration.GetValue("MY_API_HTTP"); @@ -155,7 +193,7 @@ string host = builder.Configuration.GetValue("MY_CLICKHOUSE_HOST"); import os # Connection strings -cache_conn = os.getenv("ConnectionStrings__my-cache") +cache_conn = os.getenv("ConnectionStrings__my_cache") # Endpoint URLs api_url = os.getenv("MY_API_HTTP") @@ -167,8 +205,8 @@ db_host = os.getenv("MY_CLICKHOUSE_HOST") ### JavaScript / TypeScript ```javascript title="JavaScript — app.js" -// Connection strings (use bracket notation for names with hyphens) -const cacheConn = process.env['ConnectionStrings__my-cache']; +// Connection strings +const cacheConn = process.env.ConnectionStrings__my_cache; // Endpoint URLs const apiUrl = process.env.MY_API_HTTP; @@ -179,7 +217,7 @@ const dbHost = process.env.MY_CLICKHOUSE_HOST; diff --git a/src/frontend/src/content/docs/get-started/ai-coding-agents.mdx b/src/frontend/src/content/docs/get-started/ai-coding-agents.mdx index a1f8734b3..440b16f94 100644 --- a/src/frontend/src/content/docs/get-started/ai-coding-agents.mdx +++ b/src/frontend/src/content/docs/get-started/ai-coding-agents.mdx @@ -46,9 +46,11 @@ When you create a new Aspire project with `aspire new` or `aspire init`, you're +Standalone interactive setup offers MCP as an explicit opt-in. Setup chained from `aspire new` or `aspire init` doesn't offer it. For non-interactive setup, pass `aspire agent init --mcp` if you want MCP configuration; otherwise setup installs skills without enabling an MCP connection. + ## What gets configured -The `aspire agent init` command detects your AI development environment and creates the appropriate configuration files: +The `aspire agent init` command detects your AI development environment, including an installed GitHub Copilot app even when the standalone Copilot CLI isn't available on `PATH`, and creates the configuration files you select: ### Aspire skill files diff --git a/src/frontend/src/content/docs/get-started/aspire-skills.mdx b/src/frontend/src/content/docs/get-started/aspire-skills.mdx index 87c53c35c..30bddf01a 100644 --- a/src/frontend/src/content/docs/get-started/aspire-skills.mdx +++ b/src/frontend/src/content/docs/get-started/aspire-skills.mdx @@ -29,7 +29,7 @@ Use Aspire's first-party agent setup when creating a new app, adding Aspire to a aspire agent init ``` -Run `aspire agent init` in an existing Aspire project when you want to set up AI coding agents or refresh installed skill files. +Run `aspire agent init` in an existing Aspire project when you want to set up AI coding agents or refresh installed skill files. Skills don't require MCP. MCP setup is an explicit opt-in during standalone interactive setup or through `--mcp`; setup chained from `aspire new` or `aspire init` doesn't offer it. For command options and examples, see the [`aspire agent init` command diff --git a/src/frontend/src/content/docs/get-started/troubleshooting.mdx b/src/frontend/src/content/docs/get-started/troubleshooting.mdx index e6703d416..b7b96a158 100644 --- a/src/frontend/src/content/docs/get-started/troubleshooting.mdx +++ b/src/frontend/src/content/docs/get-started/troubleshooting.mdx @@ -180,6 +180,14 @@ Also verify: aspire update --self ``` +### Authenticated feeds return 401 + +Bundled NuGet search and restore run in-process and initialize NuGet's credential service so installed credential-provider plugins can authenticate to feeds such as Azure Artifacts. + +If an authenticated feed still returns `401`, check the configured feed URL, package source mapping, and credential provider installation. Authenticate using the provider's documented workflow, and verify a restore from that same feed outside Aspire, for example with `dotnet restore --interactive` on a project that actually references a package from it. `dotnet nuget locals` only inspects or clears caches; it doesn't verify feed authentication. + +Bundled NuGet operations initialize credentials non-interactively. Complete any required interactive sign-in first rather than expecting the Aspire operation to display a credential prompt. Non-bundled search still uses `dotnet package search`. + ## TypeScript AppHost issues ### "Command not found" errors diff --git a/src/frontend/src/content/docs/integrations/caching/redis/redis-host.mdx b/src/frontend/src/content/docs/integrations/caching/redis/redis-host.mdx index 5129889ca..280f1b5ea 100644 --- a/src/frontend/src/content/docs/integrations/caching/redis/redis-host.mdx +++ b/src/frontend/src/content/docs/integrations/caching/redis/redis-host.mdx @@ -399,7 +399,7 @@ await builder.addNodeApp("api", "./api", "index.js") -The preceding code adds a container based on the `ghcr.io/joeferner/redis-commander` image. The Redis Commander UI is available from the Aspire dashboard and connects automatically to the Redis resource. +The preceding code adds a container based on the `ghcr.io/joeferner/redis-commander` image. The Redis Commander UI connects automatically to the Redis resource. Open **Manage (Commander)** on a Redis resource in the dashboard; the management container is hidden from the main resource list. Redis Insight follows the same pattern with **Manage (Insights)**. @@ -464,6 +464,42 @@ var exampleProject = builder.AddProject() The TypeScript AppHost doesn't currently expose a `withClearCommand()` API for Redis. This feature is only available in the C# AppHost. +## Add Redis resource with a REPL command + +The `WithRepl` method adds an opt-in **REPL** command to the Redis resource in the Aspire dashboard. Selecting the command while the container is running opens an authenticated `redis-cli` session in the dashboard's terminal dock—no local Redis client installation is required: + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const cache = await builder.addRedis("cache"); +await cache.withRepl(); + +await builder.build().run(); +``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache") + .WithRepl(); + +builder.Build().Run(); +``` + + + +The REPL command is disabled by default and is only registered in run mode—it isn't available in published applications. Use `quit` to exit `redis-cli` cleanly before closing the terminal tab; closing the tab alone can leave `redis-cli` running inside the container, and stopping the container ends any remaining REPL processes. The session runs inside the container using Docker (or the configured Podman runtime), and passwords are passed through environment variables rather than command-line arguments. When TLS is enabled, the in-container REPL uses the non-TLS port over loopback. + +:::caution +Only enable `WithRepl()` for resources whose authenticated client access is appropriate for everyone who can access the dashboard. The shell uses the resource's configured credentials and isn't read-only. Sharing the dashboard through a tunnel, Codespaces, or VS Code remote development also exposes this capability to anyone who can execute resource commands. +::: + ## Pass custom environment variables By default, Aspire injects the Redis connection information using variable names derived from the resource name (for example, `CACHE_URI`, `CACHE_HOST`, `CACHE_PORT`, `CACHE_PASSWORD`). If your consuming app expects a different set of environment variable names, pass individual connection properties from the AppHost: diff --git a/src/frontend/src/content/docs/integrations/caching/valkey/valkey-host.mdx b/src/frontend/src/content/docs/integrations/caching/valkey/valkey-host.mdx index 8da612561..4f932c78f 100644 --- a/src/frontend/src/content/docs/integrations/caching/valkey/valkey-host.mdx +++ b/src/frontend/src/content/docs/integrations/caching/valkey/valkey-host.mdx @@ -284,6 +284,42 @@ await builder.addNodeApp("api", "./api", "index.js") When no `password` parameter is provided, Aspire generates a strong password automatically using the `CreateDefaultPasswordParameter` method. +## Add Valkey resource with a REPL command + +The `WithRepl` method adds an opt-in **REPL** command to the Valkey resource in the Aspire dashboard. Selecting the command while the container is running opens an authenticated `valkey-cli` session in the dashboard's terminal dock—no local Valkey client installation is required: + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const cache = await builder.addValkey("cache"); +await cache.withRepl(); + +await builder.build().run(); +``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddValkey("cache") + .WithRepl(); + +builder.Build().Run(); +``` + + + +The REPL command is disabled by default and is only registered in run mode—it isn't available in published applications. Use `quit` to exit `valkey-cli` cleanly before closing the terminal tab; closing the tab alone can leave `valkey-cli` running inside the container, and stopping the container ends any remaining REPL processes. The session runs inside the container using Docker (or the configured Podman runtime), and passwords are passed through environment variables rather than command-line arguments. + +:::caution +Only enable `WithRepl()` for resources whose authenticated client access is appropriate for everyone who can access the dashboard. The shell uses the resource's configured credentials and isn't read-only. Sharing the dashboard through a tunnel, Codespaces, or VS Code remote development also exposes this capability to anyone who can execute resource commands. +::: + ## Pass custom environment variables By default, Aspire injects the Valkey connection information using variable names derived from the resource name (for example, `CACHE_URI`, `CACHE_HOST`, `CACHE_PORT`, `CACHE_PASSWORD`). If your consuming app expects a different set of environment variable names, pass individual connection properties from the AppHost: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-connect.mdx index 932c6cc73..aa693a997 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-connect.mdx @@ -98,6 +98,24 @@ MYPROJECT_URI=https://my-foundry.services.ai.azure.com/api/projects/my-project?a The project resource never exposes an API key or a separate project-name property through Aspire. Authenticate with `DefaultAzureCredential` and use `Uri` directly as the project endpoint. +### Foundry Toolbox resource + +A Toolbox exposes one MCP endpoint for its configured tools. See [Add a Toolbox](../azure-ai-foundry-host/#add-a-toolbox) for the AppHost walkthrough. + +| Property | Description | +| -------- | ----------- | +| `Uri` | Default MCP endpoint, or the endpoint of a pinned immutable version | +| `ProjectEndpoint` | Parent Foundry project endpoint | +| `Name` | Toolbox name | +| `ApiVersion` | Toolbox data-plane API version | +| `Version` | Pinned immutable version, when configured | +| `FoundryFeatures` | Required `Foundry-Features` request-header value | +| `AuthorizationScope` | Microsoft Entra scope for Toolbox requests | + +For a resource named `field-tools`, read `FIELD_TOOLS_URI`, `FIELD_TOOLS_FOUNDRYFEATURES`, and `FIELD_TOOLS_AUTHORIZATIONSCOPE`. Acquire an Entra token for the supplied scope, include the `Foundry-Features` header, and perform the MCP `initialize` and `tools/list` handshake against `Uri`. The composed connection string contains `Uri=https://.../toolboxes/field-tools/mcp`. + +Tool approval policies returned during discovery aren't enforced by the Toolbox service. Your client must inspect them and obtain approval before calling a tool. + ## Connect from your app Pick the language your consuming app is written in. Each example assumes your AppHost adds a Foundry deployment resource named `chat` and references it from the consuming app. diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx index 5472194ef..73218eb65 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-host.mdx @@ -353,6 +353,119 @@ await foundry `AddProject` creates a default Azure Container Registry for hosted agents only in publish mode (when deploying to Azure). In local run mode, no default registry is created. Use `WithContainerRegistry` when you want to point the project at a specific registry. +## Add a Toolbox + +A [Toolbox](https://learn.microsoft.com/azure/foundry/agents/how-to/tools/toolbox) is a Foundry data-plane resource that bundles reusable tools behind a single MCP endpoint. Toolboxes don't have an ARM or Bicep representation — Aspire manages them directly through the Foundry data-plane API. Use `AddToolbox` on a Foundry project to declare one: + + + + +```typescript title="apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; +import { FoundryToolboxMcpGlobalApprovalMode } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const foundry = await builder.addFoundry('foundry'); +const project = await foundry.addProject('project'); +const search = await builder.addAzureSearch('search'); + +const toolbox = await project.addToolbox('field-tools'); +await toolbox.withDescription('Tools for field technicians.'); +await toolbox.withWebSearchTool({ + name: 'web-search', + description: 'Search the public web.', +}); +await toolbox.withMcpTool('inventory', 'https://inventory.example.com/mcp', { + serverDescription: 'Inventory MCP server.', + approvalPolicy: { + global: FoundryToolboxMcpGlobalApprovalMode.Always, + }, +}); +await toolbox.withAISearchTool('knowledge-base', search, 'docs'); + +const api = await builder.addProject('api', '../Api/Api.csproj'); +await api.withReference(toolbox); +await api.waitFor(toolbox); + +await builder.build().run(); +``` + + + + + +```csharp title="AppHost.cs" +using Aspire.Hosting.Foundry; + +var builder = DistributedApplication.CreateBuilder(args); + +var foundry = builder.AddFoundry("foundry"); +var project = foundry.AddProject("project"); +var search = builder.AddAzureSearch("search"); + +var toolbox = project.AddToolbox("field-tools") + .WithDescription("Tools for field technicians.") + .WithWebSearchTool("web-search", "Search the public web.") + .WithMcpTool( + "inventory", + "https://inventory.example.com/mcp", + new FoundryToolboxMcpToolOptions + { + ServerDescription = "Inventory MCP server.", + ApprovalPolicy = new() + { + Global = FoundryToolboxMcpGlobalApprovalMode.Always + } + }) + .WithAISearchTool("knowledge-base", search, "docs"); + +builder.AddProject("api") + .WithReference(toolbox) + .WaitFor(toolbox); + +builder.Build().Run(); +``` + + + + +Parameter details: + +The identity running `aspire run` or `aspire deploy` needs the **Foundry User** role on the project to manage Toolbox versions. Deployed compute resources that reference the Toolbox receive this role on the project automatically. The Search index named `docs` must already exist and contain data: neither `AddAzureSearch` nor `WithAISearchTool` creates or populates it. Toolbox availability depends on the Foundry service preview and its supported regions. + +| API | Parameter | Description | +| --- | --- | --- | +| `AddToolbox(...)` | `name` | The Aspire resource name and the Toolbox name. | +| `WithDescription(...)` | `description` | A description persisted with each Toolbox version. | +| `WithWebSearchTool(...)` | `name`, `description` | Adds a web search tool definition to the Toolbox. | +| `WithMcpTool(...)` | `name`, `endpoint`, `options` | Adds an MCP tool definition. `endpoint` accepts a string URI, an `EndpointReference`, or a `ReferenceExpression` for composed URLs. `options` configures the MCP server label, description, and approval policy. | +| `WithAISearchTool(...)` | `name`, `search`, `indexName`, `description` | Adds an Azure AI Search tool backed by an `AddAzureSearch` resource and an existing search index. | + + + + + +Aspire reuses the current default Toolbox version when its configuration matches. Otherwise, it creates and promotes a new immutable version, using a deterministic configuration fingerprint to detect changes. The default consumer endpoint always serves the promoted version; set the Toolbox resource's `Version` only when a consumer must pin a specific immutable version. + +Ownership metadata provides best-effort coordination, not an atomic lease. The service doesn't expose an ETag or conditional update operation. Aspire checks ownership and the current default before promotion and verifies the result afterward, failing rather than overwriting contradictory concurrent changes. + +### Use an existing Toolbox + +Use the existing-resource methods to validate a remote Toolbox without resolving modeled tools, creating versions, or changing the default: + +| Method | `aspire run` | `aspire deploy` | +| --- | --- | --- | +| `RunAsExisting()` | Validate existing | Reconcile managed | +| `PublishAsExisting()` | Reconcile managed | Validate existing | +| `AsExisting()` | Validate existing | Validate existing | + +These methods apply to the Toolbox resource itself. Existing mode validates the remote Toolbox, and a pinned version if supplied, without resolving local tools or promoting a version. See [Toolbox connection properties](../azure-ai-foundry-connect/#foundry-toolbox-resource) for the consumer's endpoint, authentication scope, and required request header. + ## Add a hosted agent to Azure AI Foundry Use `AsHostedAgent` in C# or `asHostedAgent` in TypeScript to configure an executable or containerized app as a hosted agent in a Foundry project: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-inference/azure-ai-inference-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-inference/azure-ai-inference-connect.mdx index 47be3bd88..a4c5604d2 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-inference/azure-ai-inference-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-inference/azure-ai-inference-connect.mdx @@ -181,6 +181,18 @@ builder.AddAzureChatCompletionsClient( The Azure AI Inference client integration participates in Aspire health checks. The integration wires into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. +The chat-completions and embeddings checks perform a model-info request using `GetModelInfoAsync`, which calls the endpoint's `/info` route. A reachable endpoint that doesn't implement this route can therefore fail its health check even when inference requests work. + +For an endpoint without model-info support, explicitly disable this integration's health check and choose an application-appropriate readiness probe: + +```csharp title="Program.cs" +builder.AddAzureChatCompletionsClient( + connectionName: "ai-foundry", + configureSettings: settings => settings.DisableHealthChecks = true); +``` + +This behavior belongs to `Aspire.Azure.AI.Inference`; it doesn't add health-check support to the separate Azure OpenAI integration. + ### Observability and telemetry The Aspire Azure AI Inference client integration automatically configures logging, tracing, and metrics through OpenTelemetry. diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-connector-namespace.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-connector-namespace.mdx new file mode 100644 index 000000000..822e77a35 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-connector-namespace.mdx @@ -0,0 +1,142 @@ +--- +title: Azure Connector Namespace hosting integration +description: Model Azure Connector Namespace connections, managed MCP servers, operation allow-lists, and access policies in C# and TypeScript Aspire AppHosts. +--- + +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import InstallPackage from '@components/InstallPackage.astro'; + +Azure Connector Namespace connects applications to external services such as Office 365 and SharePoint. Aspire models the namespace, authenticated connections, managed MCP server configurations, and access policies together. + +:::caution[Preview access] +The package and Azure service are preview features. Your subscription and region need Connector Namespace preview access. You need permission to create the namespace and child resources, and an authorized user must complete any connector-specific OAuth consent. +::: + +## Install the integration + + + +Configure [Azure provisioning](/integrations/cloud/azure/local-provisioning/) before running or deploying the AppHost. The integration provisions real Azure resources; it doesn't provide a local connector emulator. + +## Add a connection and managed MCP server + +A **connection** is an authenticated binding to a service. A **managed MCP server configuration** exposes selected operations from that connection as MCP tools. The current preview supports one connector per managed MCP server configuration. + +This example exposes only the Office 365 `GetEmailsV3` operation. Replace the tenant and principal IDs with your own Microsoft Entra IDs and verify the connector's operation IDs against the metadata available in your region. + + + + +```typescript title="apphost.mts" twoslash +import { + AzureConnectorNamespaceMcpAccessPolicyPrincipalType, + createBuilder, +} from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); +const connectors = await builder.addAzureConnectorNamespace('connectors'); +const outlook = await connectors.addConnection('outlook', 'office365', { + connectionName: 'office365-outlook', + displayName: 'Office 365 Outlook', +}); +await outlook.withAccessPolicy('worker-access', { + objectId: '33333333-3333-3333-3333-333333333333', + tenantId: '22222222-2222-2222-2222-222222222222', +}); + +const worker = await builder.addProject('worker', '../Worker/Worker.csproj'); +await worker.withReference(outlook); + +const mcp = await connectors.addMcpServerConfig('outlook-mcp'); +await mcp.withConnector('office365', outlook, { + operations: [{ name: 'GetEmailsV3', displayName: 'Get emails' }], +}); +await mcp.withAccessPolicy('developer-access', { + objectId: '11111111-1111-1111-1111-111111111111', + tenantId: '22222222-2222-2222-2222-222222222222', + principalType: AzureConnectorNamespaceMcpAccessPolicyPrincipalType.User, +}); + +await builder.build().run(); +``` + + + + +```csharp title="AppHost.cs" +using Aspire.Hosting.Azure; + +var builder = DistributedApplication.CreateBuilder(args); +var connectors = builder.AddAzureConnectorNamespace("connectors"); +var outlook = connectors.AddConnection( + "outlook", + "office365", + new AzureConnectorNamespaceConnectionOptions + { + ConnectionName = "office365-outlook", + DisplayName = "Office 365 Outlook" + }) + .WithAccessPolicy("worker-access", new AzureConnectorNamespaceAccessPolicyOptions + { + ObjectId = "33333333-3333-3333-3333-333333333333", + TenantId = "22222222-2222-2222-2222-222222222222" + }); + +builder.AddProject("worker") + .WithReference(outlook); + +connectors.AddMcpServerConfig("outlook-mcp") + .WithConnector("office365", outlook, new AzureConnectorNamespaceMcpConnectorOptions + { + Operations = + [ + new AzureConnectorNamespaceMcpOperationOptions + { + Name = "GetEmailsV3", + DisplayName = "Get emails" + } + ] + }) + .WithAccessPolicy("developer-access", new AzureConnectorNamespaceMcpAccessPolicyOptions + { + ObjectId = "11111111-1111-1111-1111-111111111111", + TenantId = "22222222-2222-2222-2222-222222222222", + PrincipalType = AzureConnectorNamespaceMcpAccessPolicyPrincipalType.User + }); + +builder.Build().Run(); +``` + + + + +The worker reference supplies `outlook__connectorGatewayName` and `outlook__connectionName` for the Azure Connector SDK. It **doesn't grant access**: the connection policy must identify the Entra principal that the worker actually uses. An explicit connection name on the reference can change the consumer's configuration prefix. + +After provisioning, open `https://connectors.azure.com////overview` and authorize connections that require consent. Aspire doesn't automate consent or store OAuth credentials. + +## Limit and revoke access + +Keep the two authorization surfaces separate: + +- **Connection policies** grant a specified Entra principal access to the connection. Use `WithIdentityAccessPolicy` / `withIdentityAccessPolicy` for a user-assigned managed identity without hard-coding its principal ID. +- **MCP server policies** grant an Entra user or group access to the managed MCP endpoint. This preview doesn't support service principals or managed identities for MCP access policies. +- **Operation allow-lists** restrict the connector operations exposed as MCP tools. Expose only what your application needs; don't put credentials or tokens in descriptions or operation metadata. + +:::danger[Removing code doesn't revoke deployed access] +Incremental ARM deployments don't delete child resources omitted from the next deployment. Removing a connection, MCP configuration, or access policy from the AppHost doesn't revoke its deployed access. Explicitly delete the child resource in Azure or tear down its provisioning environment when retiring it. +::: + +## Reference existing resources + +Use the standard Azure `PublishAsExisting` / `publishAsExisting` and `AsExisting` / `asExisting` workflows for a namespace. Existing connection and MCP configuration children support `AsExisting` / `asExisting` and are emitted as read-only Bicep references. + +When adding a new access policy beneath an existing namespace, set the Azure deployment location to the namespace's location. Bicep can't read the existing location early enough to assign the child resource location automatically. + +The integration doesn't support secret-valued connection parameter sets, connector triggers, event subscriptions, hosted MCP servers, or arbitrary MCP operation parameter schemas. Create connections that require unsupported secret parameter sets outside Aspire and reference them as existing resources. + +## See also + +- [Azure Connector Namespace overview](https://learn.microsoft.com/azure/connector-namespace/connector-namespace-overview) +- [Create a Connector Namespace connection](https://learn.microsoft.com/azure/connector-namespace/create-connector-namespace-connection) +- [Local Azure provisioning](/integrations/cloud/azure/local-provisioning/) +- [Customize Azure resources](/integrations/cloud/azure/customize-resources/) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-host.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-host.mdx index 81dc7fabb..ea7610a0e 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-host.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-host.mdx @@ -154,6 +154,8 @@ When you call `RunAsEmulator`, it configures the Cosmos DB resource to run local ### Configure emulator gateway port +The vNext emulator automatically exports its own traces and metrics to the Aspire dashboard. Aspire configures its OTLP endpoint and enables the emulator's built-in exporter with `ENABLE_OTLP_EXPORTER=true`. This is emulator telemetry, not a replacement for instrumenting your consuming application, and it doesn't apply to the classic emulator. + By default, the Cosmos DB emulator container exposes the following endpoint: | Endpoint | Container port | Host port | diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx index fb922a3d3..b8b0b1068 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx @@ -160,14 +160,29 @@ For TypeScript and other polyglot AppHosts, add the `Aspire.Hosting.Azure.Provis aspire add Aspire.Hosting.Azure.Provisioning.Storage ``` -The examples below use these packages, depending on the resource being customized: - -| Hosting integration | Opt-in provisioning package | -| ------------------- | --------------------------------------------------- | -| Azure Storage | `Aspire.Hosting.Azure.Provisioning.Storage` | -| Azure Service Bus | `Aspire.Hosting.Azure.Provisioning.ServiceBus` | -| Azure Key Vault | `Aspire.Hosting.Azure.Provisioning.KeyVault` | -| Azure Managed Redis | `Aspire.Hosting.Azure.Provisioning.RedisEnterprise` | +Select a provisioning package for the SDK models you want to customize: + +The **Selected SDK models** column lists representative models, not every model exposed by each package. Packages can also expose child resources and supporting models. + +| Hosting integration | Opt-in provisioning package | Selected SDK models | +| ----------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| Azure App Configuration | `Aspire.Hosting.Azure.Provisioning.AppConfiguration` | `AppConfigurationStore` | +| Azure Container Apps | `Aspire.Hosting.Azure.Provisioning.AppContainers` | `ContainerAppManagedEnvironment`, `ContainerApp`, `ContainerAppJob` | +| Azure App Service | `Aspire.Hosting.Azure.Provisioning.AppService` | `AppServicePlan`, `WebSite` | +| Azure Front Door | `Aspire.Hosting.Azure.Provisioning.Cdn` | `CdnProfile` | +| Azure Kubernetes Service | `Aspire.Hosting.Azure.Provisioning.ContainerService` | `ContainerServiceManagedCluster` | +| Azure Data Explorer | `Aspire.Hosting.Azure.Provisioning.Kusto` | `KustoCluster` | +| Azure networking | `Aspire.Hosting.Azure.Provisioning.Network` | `VirtualNetwork`, `NetworkSecurityGroup`, `NatGateway`, `PublicIPAddress`, `PrivateEndpoint`, `NetworkSecurityPerimeter` | +| Azure private DNS | `Aspire.Hosting.Azure.Provisioning.PrivateDns` | `PrivateDnsZone` | +| Azure Database for PostgreSQL | `Aspire.Hosting.Azure.Provisioning.PostgreSql` | `PostgreSqlFlexibleServer` | +| Azure Cache for Redis | `Aspire.Hosting.Azure.Provisioning.Redis` | `RedisResource` | +| Azure Managed Redis | `Aspire.Hosting.Azure.Provisioning.RedisEnterprise` | `RedisEnterpriseCluster` | +| Azure SignalR Service | `Aspire.Hosting.Azure.Provisioning.SignalR` | `SignalRService` | +| Azure Storage | `Aspire.Hosting.Azure.Provisioning.Storage` | `StorageAccount` | +| Azure Service Bus | `Aspire.Hosting.Azure.Provisioning.ServiceBus` | `ServiceBusNamespace` | +| Azure Key Vault | `Aspire.Hosting.Azure.Provisioning.KeyVault` | `KeyVaultService` | + +Package names follow the Azure Provisioning SDK, which can differ from the hosting integration name: Front Door uses `Cdn`, Kubernetes uses `ContainerService`, and PostgreSQL uses the SDK spelling `PostgreSql`. Network and PrivateDns are separate opt-ins, as are Redis and RedisEnterprise. To customize supporting resources such as a container registry or Log Analytics workspace, also add the corresponding provisioning package; a transitive hosting dependency doesn't enable its SDK proxies. Each provisioning package references its hosting integration and the shared `Aspire.Hosting.Azure.Provisioning` runtime. Install only the SDK proxies your AppHost uses. Existing C# customization through `Azure.Provisioning.*` doesn't require these proxy packages. @@ -181,6 +196,86 @@ For the complete factory method reference, C# SDK and Bicep mappings, and Storag Lookups are scoped to the current infrastructure callback. A no-argument root lookup matches the hosting resource's Bicep identifier, not its physical Azure name. Use an identifier-based lookup or typed resource list for child resources; a companion resource can have a separate callback. +### Service-specific lookups + +The selected models in the table aren't all no-argument lookup roots: + +- **App Configuration**: Use `getAppConfigurationStore()` in the store's infrastructure callback. +- **Container Apps**: Use `getContainerAppManagedEnvironment()` in the environment callback. Apps and jobs require identifier-based lookup in their publish callbacks. Their SDK Bicep identifiers use the normalized workload name, not the synthetic hosting resource identifier. +- **App Service**: Use `getAppServicePlanByIdentifier(...)` with the environment's Bicep identifier followed by `_asplan`. Sites use the Bicep identifier `webapp` and must be accessed in the website publish callback, not the environment callback. Neither plans nor sites have a no-argument root lookup. +- **Child resources**: Use identifier-based lookup for resources such as Kusto databases. Don't assume the parent resource's no-argument lookup selects a child. + +For example, add a tag to the App Configuration store that Aspire creates. The infrastructure callback runs before Aspire emits the resource's Bicep; the lookup selects the store within that callback, rather than querying an existing Azure deployment. + + + + +Add the App Configuration provisioning package from your AppHost directory: + +```bash title="Add typed App Configuration customization" +aspire add Aspire.Hosting.Azure.Provisioning.AppConfiguration +``` + +```typescript title="apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); +const configuration = await builder.addAzureAppConfiguration('configuration'); + +await configuration.configureInfrastructure(async (infrastructure) => { + const store = await infrastructure.getAppConfigurationStore(); + const tags = await store.tags.get(); + await tags.set('environment', 'production'); +}); + +await builder.build().run(); +``` + + + + +Add the hosting integration; C# accesses the Azure Provisioning SDK directly: + +```bash title="Add App Configuration hosting integration" +aspire add Aspire.Hosting.Azure.AppConfiguration +``` + +```csharp title="AppHost.cs" +using Azure.Provisioning.AppConfiguration; + +var builder = DistributedApplication.CreateBuilder(args); +var configuration = builder.AddAzureAppConfiguration("configuration"); + +configuration.ConfigureInfrastructure(infrastructure => +{ + var store = infrastructure.GetProvisionableResources() + .OfType() + .Single(); + store.Tags["environment"] = "production"; +}); + +builder.Build().Run(); +``` + + + + +### IP address collections and projection limits + +The AppContainers SDK's `OutboundIPAddressList` and the AppService SDK's `IPAddresses`, `ExternalInboundIPAddresses`, `InternalInboundIPAddresses`, `LinuxOutboundIPAddresses`, and `WindowsOutboundIPAddresses` use IP address collection proxies. + +Writable collections accept IPv4 or IPv6 strings and compatible Bicep value handles for add, insert, and set operations. Invalid address strings fail validation. Element getters return Bicep value handles that preserve literal values, expressions, resource references, and secure-value metadata. An exported collection isn't necessarily writable: Azure SDK read-only output restrictions still apply. + +The projection deliberately excludes members without a type-safe representation: + +| Provisioning package suffix | Excluded member | Unsupported SDK shape | +| --------------------------- | --------------------------- | ----------------------------- | +| `ContainerService` | `CustomCATrustCertificates` | `BicepList` | +| `Network` | `AdditionalProperties` | `BicepDictionary` | +| `Redis` | `AdditionalProperties` | `BicepDictionary` | + +These exclusions apply to the polyglot proxy surface, not direct Azure Provisioning SDK access in C#. Adding a proxy package doesn't change authentication, resource lifecycles, or deployment defaults. + See the [provisioning SDK inventory and compatibility boundaries](https://github.com/microsoft/aspire/blob/a11eca9611073f7cf66fa87faac63c2119e87713/src/Aspire.Hosting.Azure.Provisioning/README.md#hosting-to-provisioning-inventory). diff --git a/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx b/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx index c417a1b7d..f72838b63 100644 --- a/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx +++ b/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx @@ -256,6 +256,50 @@ await pg.withKubernetesPersistentVolume(pgData); For the full configuration surface, binding overloads, access modes, and generated output, see [Persistent volumes on Kubernetes](/deployment/kubernetes/persistent-volumes/). +## Inline ephemeral CSI volumes + +Use `CsiVolumeSourceV1` and the `VolumeV1.Csi` property to model inline CSI volumes in C#. Unlike a persistent volume claim, an inline CSI volume is declared directly in a pod and has that pod's lifetime. Drivers can use it to project external secrets, certificates, or storage at mount time. + +Install the CSI driver in the cluster first and create any driver-specific configuration. For the Secrets Store CSI driver, the following example assumes a `SecretProviderClass` named `app-secrets` exists in the workload namespace: + +```csharp title="AppHost.cs" +using Aspire.Hosting.Kubernetes.Resources; + +var builder = DistributedApplication.CreateBuilder(args); +builder.AddKubernetesEnvironment("k8s"); + +builder.AddContainer("web", "nginx") + .PublishAsKubernetesService(resource => + { + if (resource.Workload is Deployment deployment) + { + var pod = deployment.Spec.Template.Spec; + pod.Volumes.Add(new VolumeV1 + { + Name = "secrets-store", + Csi = new CsiVolumeSourceV1 + { + Driver = "secrets-store.csi.k8s.io", + ReadOnly = true, + VolumeAttributes = { ["secretProviderClass"] = "app-secrets" } + } + }); + pod.Containers.Single().VolumeMounts.Add(new VolumeMountV1 + { + Name = "secrets-store", + MountPath = "/mnt/secrets", + ReadOnly = true + }); + } + }); + +builder.Build().Run(); +``` + +`Driver` identifies the installed driver. `VolumeAttributes` carries driver-specific values, `FsType` selects a filesystem when the driver supports it, and `NodePublishSecretRef` can reference mount credentials in a Kubernetes Secret in the same namespace. `ReadOnly` defaults to Kubernetes' read/write behavior when omitted; set it explicitly for secret projections. + +This C# resource-model type isn't exported as a typed TypeScript AppHost API. For custom manifests from either language, see [Add custom Kubernetes manifests](#add-custom-kubernetes-manifests). Declaring the volume doesn't install a driver, create a `SecretProviderClass`, or grant the workload permission to read an external secret store. + ## Customize individual resources Use `PublishAsKubernetesService` to modify the generated Kubernetes resources for individual services: diff --git a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-host.mdx b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-host.mdx index 6a7019d3d..698102dd6 100644 --- a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-host.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-host.mdx @@ -664,6 +664,42 @@ await mongo.withLifetime("Persistent"); +## Add MongoDB resource with a REPL command + +The `WithRepl` method adds an opt-in **REPL** command to the MongoDB server resource in the Aspire dashboard. Selecting the command while the container is running opens the bundled `mongosh` client in the dashboard's terminal dock, authenticated against `admin` with the resource's configured credentials—no local MongoDB client installation is required: + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const mongo = await builder.addMongoDB("mongo"); +await mongo.withRepl(); + +await builder.build().run(); +``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var mongo = builder.AddMongoDB("mongo") + .WithRepl(); + +builder.Build().Run(); +``` + + + +The REPL command is disabled by default and is only registered in run mode—it isn't available in published applications. Use `exit` to end the `mongosh` session cleanly before closing the terminal tab; closing the tab alone can leave `mongosh` running inside the container, and stopping the container ends any remaining REPL processes. The session connects directly to the server inside its container, including replica set members, and credentials are passed through the environment rather than command-line arguments. When TLS is enabled, the shell uses the configured certificate trust bundle and validates the server certificate for `localhost`; custom certificates must cover `localhost` and their issuing CA must be trusted through Aspire's certificate configuration. + +:::caution +Only enable `WithRepl()` for resources whose authenticated client access is appropriate for everyone who can access the dashboard. The shell uses the resource's configured credentials and isn't read-only. Sharing the dashboard through a tunnel, Codespaces, or VS Code remote development also exposes this capability to anyone who can execute resource commands. +::: + ## Pass custom environment variables By default, Aspire injects the MongoDB connection information using variable names derived from the resource name (for example, `MONGODB_URI`, `MONGODB_HOST`, `MONGODB_PORT`). If your consuming app expects a different set of environment variable names, pass individual connection properties from the AppHost: diff --git a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-host.mdx b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-host.mdx index 819e9219c..f66de1666 100644 --- a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-host.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-host.mdx @@ -478,6 +478,42 @@ await builder.addNodeApp("api", "./api", "index.js") When no `password` parameter is provided, Aspire generates a strong password automatically using the `CreateDefaultPasswordParameter` method. For more information, see [External parameters](/get-started/resources/). +## Add MySQL resource with a REPL command + +The `WithRepl` method adds an opt-in **REPL** command to the MySQL server resource in the Aspire dashboard. Selecting the command while the container is running opens the bundled `mysql` client in the dashboard's terminal dock, authenticated as `root` with the resource's configured password—no local MySQL client installation is required: + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const mysql = await builder.addMySql("mysql"); +await mysql.withRepl(); + +await builder.build().run(); +``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var mysql = builder.AddMySql("mysql") + .WithRepl(); + +builder.Build().Run(); +``` + + + +The REPL command is disabled by default and is only registered in run mode—it isn't available in published applications. Use `quit` to exit `mysql` cleanly before closing the terminal tab; closing the tab alone can leave `mysql` running inside the container, and stopping the container ends any remaining REPL processes. The session runs inside the container using Docker (or the configured Podman runtime), and the password is passed through an environment variable rather than command-line arguments or SQL history. + +:::caution +Only enable `WithRepl()` for resources whose authenticated client access is appropriate for everyone who can access the dashboard. The shell uses the resource's configured credentials and isn't read-only. Sharing the dashboard through a tunnel, Codespaces, or VS Code remote development also exposes this capability to anyone who can execute resource commands. +::: + ## Pass custom environment variables By default, Aspire injects the MySQL connection information using variable names derived from the resource name (for example, `MYSQLDB_URI`, `MYSQLDB_HOST`, `MYSQLDB_PORT`, `MYSQLDB_PASSWORD`). If your consuming app expects a different set of environment variable names, pass individual connection properties from the AppHost: diff --git a/src/frontend/src/content/docs/integrations/databases/postgres/postgres-host.mdx b/src/frontend/src/content/docs/integrations/databases/postgres/postgres-host.mdx index a8a3a9fe9..3974147fd 100644 --- a/src/frontend/src/content/docs/integrations/databases/postgres/postgres-host.mdx +++ b/src/frontend/src/content/docs/integrations/databases/postgres/postgres-host.mdx @@ -232,6 +232,8 @@ await builder.addNodeApp("api", "./api", "index.js") The preceding code adds a container based on the `docker.io/dpage/pgadmin4` image. The container is used to manage the PostgreSQL server and database resources and serves a web-based admin dashboard for PostgreSQL databases. +The dashboard hides the pgAdmin management container from the main resource list. Open its **Manage** link from the PostgreSQL resource instead. + ### Configure the pgAdmin host port @@ -549,6 +551,42 @@ await builder.addNodeApp("api", "./api", "index.js") +## Add PostgreSQL resource with a REPL command + +The `WithRepl` method adds an opt-in **REPL** command to the PostgreSQL server resource in the Aspire dashboard. Selecting the command while the container is running opens `psql` in the dashboard's terminal dock, already connected to the `postgres` database with the resource's configured credentials—no local PostgreSQL client installation is required: + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const postgres = await builder.addPostgres("postgres"); +await postgres.withRepl(); + +await builder.build().run(); +``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres") + .WithRepl(); + +builder.Build().Run(); +``` + + + +The REPL command is disabled by default and is only registered in run mode—it isn't available in published applications. Use `\connect` to switch databases and `\q` to exit `psql` cleanly before closing the terminal tab; closing the tab alone can leave `psql` running inside the container, and stopping the container ends any remaining REPL processes. The session runs inside the container using Docker (or the configured Podman runtime), and passwords are passed through environment variables rather than command-line arguments. + +:::caution +Only enable `WithRepl()` for resources whose authenticated client access is appropriate for everyone who can access the dashboard. The shell uses the resource's configured credentials and isn't read-only. Sharing the dashboard through a tunnel, Codespaces, or VS Code remote development also exposes this capability to anyone who can execute resource commands. +::: + ## Pass custom environment variables By default, Aspire injects the PostgreSQL connection information using variable names derived from the resource name (for example, `POSTGRESDB_URI`, `POSTGRESDB_HOST`, `POSTGRESDB_PORT`). If your consuming app expects a different set of environment variable names, pass individual connection properties from the AppHost: diff --git a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-host.mdx b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-host.mdx index a581366de..abe7e1ede 100644 --- a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-host.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-host.mdx @@ -416,6 +416,49 @@ await builder.build().run(); For a list of available tags, see [SQL Server container image tags](https://mcr.microsoft.com/en-us/artifact/mar/mssql/server/tags). +## Add SQL Server resource with a REPL command + +The `WithRepl` method adds an opt-in **REPL** command to the SQL Server resource in the Aspire dashboard. Selecting the command while the container is running opens `sqlcmd` in the dashboard's terminal dock, connected inside the container as `sa` to the `master` database—no local SQL client installation is required: + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const sql = await builder.addSqlServer("sqlserver"); +await sql.withRepl(); + +await builder.build().run(); +``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var sql = builder.AddSqlServer("sqlserver") + .WithRepl(); + +builder.Build().Run(); +``` + + + +Enter SQL statements followed by `GO` on its own line to execute a batch: + +```sql title="Execute a SQL batch" +SELECT DB_NAME(); +GO +``` + +Use `USE [db];` followed by `GO` to switch databases, and `QUIT` to exit `sqlcmd` cleanly before closing the terminal tab; closing the tab alone can leave `sqlcmd` running inside the container, and stopping the container ends any remaining REPL processes. The REPL command is disabled by default and is only registered in run mode—it isn't available in published applications. It uses the configured password without putting it in command-line arguments, and trusts the local server's self-signed certificate, matching the integration's local connection string. It supports both `/opt/mssql-tools18/bin/sqlcmd` in newer SQL Server images and `/opt/mssql-tools/bin/sqlcmd` in older images; custom images must include one of these clients. + +:::caution +Only enable `WithRepl()` for resources whose authenticated client access is appropriate for everyone who can access the dashboard. The shell runs as `sa` and can execute server-side operating system commands when enabled. Sharing the dashboard through a tunnel, Codespaces, or VS Code remote development also exposes this capability to anyone who can execute resource commands. +::: + ## Pass custom environment variables By default, Aspire injects the SQL Server connection information using variable names derived from the resource name (for example, `DATABASE_URI`, `DATABASE_HOST`, `DATABASE_PORT`). If your consuming app expects a different set of environment variable names, pass individual connection properties from the AppHost: diff --git a/src/frontend/src/content/docs/integrations/devtools/dev-tunnels.mdx b/src/frontend/src/content/docs/integrations/devtools/dev-tunnels.mdx index 65c931bd5..979d1051b 100644 --- a/src/frontend/src/content/docs/integrations/devtools/dev-tunnels.mdx +++ b/src/frontend/src/content/docs/integrations/devtools/dev-tunnels.mdx @@ -314,6 +314,16 @@ Verify that: - You're using the correct tunnel URL - Anonymous access is configured correctly if accessing without authentication +#### Dashboard doesn't show a tunnel URL + +Dev tunnel endpoints stay unallocated until the integration publishes the +real tunnel endpoint. The dashboard and MCP resource snapshots then show +the public tunnel URL. + +If you're using Aspire 13.5 and the resource reaches the _Running_ and +_Healthy_ states without showing a URL, update to Aspire 13.6 or later +to resolve a known endpoint-publication regression. + ## See also - [Dev tunnels overview](https://learn.microsoft.com/azure/developer/dev-tunnels/overview) diff --git a/src/frontend/src/content/docs/integrations/dotnet/blazor-hosting.mdx b/src/frontend/src/content/docs/integrations/dotnet/blazor-hosting.mdx index 89d177598..8a083a2d4 100644 --- a/src/frontend/src/content/docs/integrations/dotnet/blazor-hosting.mdx +++ b/src/frontend/src/content/docs/integrations/dotnet/blazor-hosting.mdx @@ -6,6 +6,7 @@ description: Learn how to use the Aspire Blazor hosting integration APIs to mode import { Image } from 'astro:assets'; import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; +import ApiReference from '@components/ApiReference.astro'; import LearnMore from '@components/LearnMore.astro'; import blazorIcon from '@assets/icons/blazor-icon.svg'; @@ -206,8 +207,64 @@ await builder.build().run(); examples, see [Connect Blazor apps and APIs](../blazor-connect/). +## Add a Blazor Gateway for a C# project resource + +[`AddDotnetProjectBlazorGateway`](/reference/api/csharp/aspire.hosting.blazor/blazorgatewayextensions/methods/#adddotnetprojectblazorgateway) adds a Blazor Gateway that hosts a [`DotnetProjectResource`](/integrations/frameworks/dotnet/dotnet-host/) (a C# project or file-based app added with ) instead of the standard `ProjectResource`-based gateway. Use the distinct [`WithBlazorClientApp`](/reference/api/csharp/aspire.hosting.blazor/blazorgatewayextensions/methods/#withblazorclientapp-iresourcebuilder-dotnetprojectresource-iresourcebuilder-blazorwasmappresource-string-string-bool) overload on this resource to attach a Blazor WebAssembly client app: + + + + +```typescript title="apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const client = await builder.addBlazorWasmProject( + 'client', + '../Client/Client.csproj' +); +const gateway = await builder.addDotnetProjectBlazorGateway('gateway'); + +await gateway.withBlazorClientApp(client); + +await builder.build().run(); +``` + + + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +#pragma warning disable ASPIREBLAZOR001, ASPIREDOTNETPROJECT001 + +var client = builder.AddBlazorWasmProject("client"); + +builder.AddDotnetProjectBlazorGateway("gateway") + .WithBlazorClientApp(client); + +builder.Build().Run(); +``` + + + + + + +The gateway forwards the client's service references and supports publishing through the shared Blazor client attachment and publish-companion pipeline. Browser-debugger resources are created only for local runs. + ## See also - [Get started with Blazor hosting](/integrations/dotnet/blazor-get-started/) - [Connect Blazor apps and APIs](/integrations/dotnet/blazor-connect/) +- [Set up .NET / C# apps in the AppHost](/integrations/frameworks/dotnet/dotnet-host/) +- [ASPIREDOTNETPROJECT001](/diagnostics/aspiredotnetproject001/) - [Aspire integrations overview](/integrations/overview/) diff --git a/src/frontend/src/content/docs/integrations/dotnet/project-resources.mdx b/src/frontend/src/content/docs/integrations/dotnet/project-resources.mdx index 2a80ff468..0aa7aaf4b 100644 --- a/src/frontend/src/content/docs/integrations/dotnet/project-resources.mdx +++ b/src/frontend/src/content/docs/integrations/dotnet/project-resources.mdx @@ -474,6 +474,23 @@ restore failures aren't retried using another strategy. File-based apps, project-specific build environments, individual Rebuild commands, and publishing keep their existing build and restore paths. +### Multithreaded builds + +Aspire probes the `dotnet` SDK selected for each build context — honoring `global.json` — and, when it +supports the MSBuild `-mt` switch, passes it to coordinated traversal builds, file-based app builds, and +individual project [rebuild commands](/app-host/hot-reload-and-watch/#recommended-workflow). `-mt` lets the +SDK execute supported build tasks with multithreaded task execution, which can reduce the time it takes for +resources to become ready. + + + ## How project references work The C# and TypeScript AppHosts differ in how they reference .NET projects: @@ -542,6 +559,12 @@ In a **TypeScript AppHost**, `addProject(name, path)` always takes a path, so th Some .NET app types use specialized integrations instead of `AddProject`. For example, [.NET MAUI integration](/integrations/dotnet/maui/) uses `AddMauiProject` because MAUI apps aren't added to the AppHost through `ProjectReference` metadata. +## Migrate from legacy project resources + +The `aspire-project-v2-migration` skill assesses legacy project resources in C# or TypeScript AppHosts targeting Aspire 13.6 or newer and proposes exact edits for approval. It preserves supported configuration and flags unsupported patterns, including Azure Functions and custom integrations tied to `ProjectResource`. + +The skill doesn't upgrade your AppHost's Aspire version. Upgrade first, then follow [Aspire skills](/get-started/aspire-skills/) to install the migration skill and review its proposal before applying it. + ## See also - [Aspire SDK](/get-started/aspire-sdk/) diff --git a/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-get-started.mdx b/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-get-started.mdx index d7489189c..66a8e20d7 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-get-started.mdx @@ -19,8 +19,8 @@ import csharpIcon from '@assets/icons/csharp.svg'; The Aspire `Aspire.Hosting.Dotnet` integration lets you add C# projects and file-based C# apps to your AppHost **by path**, without referencing a project from the AppHost's own solution. It's the C# peer of the `Aspire.Hosting.Go`, `Aspire.Hosting.Python`, and `Aspire.Hosting.JavaScript` hosting integrations. -:::caution[Experimental] -`AddDotnetProject` / `addDotnetProject` is experimental and exposed under the `ASPIREDOTNETPROJECT001` diagnostic. Its API surface may change in future releases. +:::note +`Aspire.Hosting.Dotnet` is a prerelease package. `AddDotnetProject` / `addDotnetProject` doesn't require suppressing `ASPIREDOTNETPROJECT001`, but the API surface may change. The separate [Dotnet project Blazor gateway](/integrations/dotnet/blazor-hosting/#add-a-blazor-gateway-for-a-c-project-resource) is experimental. ::: ## Why use the Dotnet hosting integration diff --git a/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-host.mdx b/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-host.mdx index cc5ff9401..aa545f13b 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-host.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/dotnet/dotnet-host.mdx @@ -23,8 +23,8 @@ This article is the reference for the Aspire Dotnet hosting integration. It enum If you're new to the Dotnet integration, start with the [Get started with the .NET / C# app integration](/integrations/frameworks/dotnet/dotnet-get-started/) guide. -:::caution[Experimental] -`AddDotnetProject` / `addDotnetProject` is experimental and exposed under the `ASPIREDOTNETPROJECT001` diagnostic. Its API surface may change in future releases. +:::note +`Aspire.Hosting.Dotnet` is a prerelease package. `AddDotnetProject`, `DotnetProjectResource`, and the related `WithBuildEnvironment` overloads don't require suppressing `ASPIREDOTNETPROJECT001`, but the API surface may change. The separate [Dotnet project Blazor gateway](/integrations/dotnet/blazor-hosting/#add-a-blazor-gateway-for-a-c-project-resource) is experimental. ::: If your C# AppHost needs to reference the resource type directly — for example, to declare a strongly typed variable or a method parameter — import it from the `Aspire.Hosting.Dotnet` namespace, matching the pattern used by the Go, Python, and JavaScript hosting integrations: diff --git a/src/frontend/src/content/docs/integrations/frameworks/rust/rust-get-started.mdx b/src/frontend/src/content/docs/integrations/frameworks/rust/rust-get-started.mdx index bff12ba05..0b1ffcb23 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/rust/rust-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/rust/rust-get-started.mdx @@ -1,11 +1,10 @@ --- title: Get started with the Rust integration category: quickstart -description: Use the Community Toolkit Rust integration to run Cargo or Bacon applications, configure endpoints, and monitor them with Aspire. +description: Run Rust applications with Aspire's first-party Cargo integration, configure endpoints, debug in Visual Studio Code, and publish container images. --- import { - Badge, LinkButton, Steps, TabItem, @@ -24,13 +23,11 @@ import rustIcon from '@assets/icons/rust-icon.png'; data-zoom-off /> - - -The Community Toolkit Rust hosting integration runs Rust applications through Cargo or Bacon alongside the other resources in your Aspire AppHost. Rust app resources support endpoints, service discovery, health checks, environment configuration, and OpenTelemetry export. They are also configured for Dockerfile publishing. +The first-party `Aspire.Hosting.Rust` integration runs Cargo applications alongside the other resources in your Aspire AppHost. Rust resources support endpoints, service discovery, health checks, environment configuration, OpenTelemetry export, debugging, and generated Dockerfiles for publishing. ## How the pieces fit together -The integration is installed in the AppHost. The AppHost starts Cargo or Bacon in the Rust application's working directory, applies standard Aspire resource configuration, and exposes the resulting resource in the dashboard. +The integration is installed in the AppHost. The AppHost starts Cargo in the Rust application's working directory, applies standard Aspire resource configuration, and exposes the resulting resource in the dashboard. ```mermaid architecture-beta @@ -40,7 +37,7 @@ architecture-beta service hosting(server)[Rust hosting integration] in apphost service resource(logos:rust)[Rust app resource] in apphost - service toolchain(logos:rust)[Cargo or Bacon] in rustapp + service toolchain(logos:rust)[Cargo] in rustapp service app(logos:rust)[Rust process] in rustapp hosting:R --> L:resource @@ -50,37 +47,27 @@ architecture-beta ## Prerequisites -- Install Rust with [rustup](https://www.rust-lang.org/tools/install) and make `cargo` available on your `PATH`. -- Install [Bacon](https://dystroy.org/bacon/) when you use `AddBaconApp` / `addBaconApp`. +- Install Rust with [rustup](https://www.rust-lang.org/tools/install) and make Cargo 1.71 or later available on your `PATH`. - Create an [Aspire AppHost](/get-started/app-host/) in C# or TypeScript. 1. ### Install the hosting package - Add `CommunityToolkit.Aspire.Hosting.Rust` to your AppHost. You can use `aspire add communitytoolkit-rust` or install the NuGet package directly. + Add the first-party hosting package from the AppHost directory: + + ```bash title="Add Rust hosting" + aspire add Aspire.Hosting.Rust + ``` 2. ### Add a Rust app Register the directory that contains your Rust project, then configure an endpoint for the port that the app reads from `PORT`. - - - ```csharp title="AppHost.cs" - var builder = DistributedApplication.CreateBuilder(args); - - builder.AddRustApp("rust-api", "../rust-api") - .WithHttpEndpoint(port: 8080, env: "PORT") - .WithExternalHttpEndpoints(); - - builder.Build().Run(); - ``` - - - ```typescript title="apphost.mts" + ```typescript title="apphost.mts" twoslash import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); @@ -92,12 +79,26 @@ architecture-beta await builder.build().run(); ``` + + + + + ```csharp title="AppHost.cs" + var builder = DistributedApplication.CreateBuilder(args); + + builder.AddRustApp("rust-api", "../rust-api") + .WithHttpEndpoint(port: 8080, env: "PORT") + .WithExternalHttpEndpoints(); + + builder.Build().Run(); + ``` + 3. ### Configure the app resource - Choose Cargo or Bacon, pass command arguments, add health checks, and learn about publishing in the [Rust AppHost reference](/integrations/frameworks/rust/rust-host/). + Configure Cargo options separately from application arguments, add health checks, and learn about debugging and publishing in the [Rust AppHost reference](/integrations/frameworks/rust/rust-host/). - - -This reference describes the Community Toolkit Rust hosting integration. If you are new to it, begin with [Get started with the Rust integration](/integrations/frameworks/rust/rust-get-started/). +This reference describes the first-party `Aspire.Hosting.Rust` integration. If you are new to it, begin with [Get started with the Rust integration](/integrations/frameworks/rust/rust-get-started/). Existing Toolkit applications should review [migration guidance](#migrate-from-the-community-toolkit). :::note[Prerequisites] -Install [Rust and Cargo](https://www.rust-lang.org/tools/install). Install [Bacon](https://dystroy.org/bacon/) too when you use the Bacon resource API. +Install [Rust and Cargo](https://www.rust-lang.org/tools/install), with Cargo 1.71 or later on `PATH`. ::: ## Install the package - - - -```bash title="Terminal" -aspire add communitytoolkit-rust -``` - -Or add [📦 CommunityToolkit.Aspire.Hosting.Rust](https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Rust) to the AppHost project. - - - - ```bash title="Terminal" -aspire add communitytoolkit-rust +aspire add Aspire.Hosting.Rust ``` -This adds the package to `aspire.config.json` and generates the TypeScript AppHost module. - - - +This adds [📦 Aspire.Hosting.Rust](https://www.nuget.org/packages/Aspire.Hosting.Rust) to the AppHost and regenerates the SDK for a TypeScript AppHost. ## Add a Cargo app `AddRustApp` / `addRustApp` starts `cargo run` in the supplied working directory. The path is resolved relative to the AppHost directory, so it normally contains the Rust project's `Cargo.toml`. - - -```csharp title="AppHost.cs" -var builder = DistributedApplication.CreateBuilder(args); - -var api = builder.AddRustApp("rust-api", "../rust-api"); - -builder.Build().Run(); -``` - - -```typescript title="apphost.mts" +```typescript title="apphost.mts" twoslash import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); @@ -77,88 +49,108 @@ await builder.build().run(); ``` - - -## Pass Cargo arguments and choose a working directory -The optional `args` are appended after `cargo run`. For example, `--release` produces `cargo run --release`; use `--` before arguments intended for your Rust application. The working directory is normalized to the current platform after Aspire combines it with the AppHost directory. - - ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); -var api = builder.AddRustApp( - name: "rust-api", - workingDirectory: "../rust-api", - args: ["--release", "--", "--environment", "development"]); +var api = builder.AddRustApp("rust-api", "../rust-api"); builder.Build().Run(); ``` + + +## Configure Cargo and application arguments + +Keep Cargo build options separate from arguments for your Rust program. Use `WithCargoArgs` / `withCargoArgs` for Cargo and `WithArgs` / `withArgs` for the application; Aspire inserts the separator. Use typed target-selection methods so debugging and publishing can identify the produced binary. + + -```typescript title="apphost.mts" +```typescript title="apphost.mts" twoslash import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); -const api = await builder.addRustApp('rust-api', '../rust-api', [ - '--release', - '--', - '--environment', - 'development', -]); +const api = await builder.addRustApp('rust-api', '../rust-api'); +await api.withCargoBinTarget('worker'); +await api.withCargoFeatures(['tls']); +await api.withCargoArgs(['--no-default-features']); +await api.withArgs(['--environment', 'development']); await builder.build().run(); ``` - -## Add a Bacon app - -`AddBaconApp` / `addBaconApp` runs the [Bacon](https://dystroy.org/bacon/) CLI from the working directory. Without arguments it runs `bacon run`; supply `args` to use another Bacon command. - - ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); -var checks = builder.AddBaconApp( - name: "rust-checks", - workingDirectory: "../rust-api", - args: ["check"]); +var api = builder.AddRustApp("rust-api", "../rust-api") + .WithCargoBinTarget("worker") + .WithCargoFeatures("tls") + .WithCargoArgs("--no-default-features") + .WithArgs("--environment", "development"); builder.Build().Run(); ``` + + +| Cargo option | Use it to | +| ------------ | --------- | +| `WithCargoPackage` / `withCargoPackage` | Select a workspace member | +| `WithCargoBinTarget` / `withCargoBinTarget` | Select a binary target | +| `WithCargoExample` / `withCargoExample` | Select an example instead of a binary | +| `WithCargoManifestPath` / `withCargoManifestPath` | Select a manifest relative to the app directory for publishing | +| `WithCargoFeatures` / `withCargoFeatures` | Accumulate feature names | +| `WithCargoReleaseBuild` / `withCargoReleaseBuild` | Use the release profile, enabled by default for publishing | +| `WithCargoLocked` / `withCargoLocked` | Require the lockfile to stay unchanged, enabled by default for publishing when a lockfile exists | +| `WithCargoProfile` / `withCargoProfile` | Choose a named profile instead of the release toggle | +| `WithCargoTarget` / `withCargoTarget` | Select a target triple | + +## Migrate from the Community Toolkit + +For Cargo applications, replace `CommunityToolkit.Aspire.Hosting.Rust` with `Aspire.Hosting.Rust`. Don't install both packages expecting their `AddRustApp` extension methods to be interchangeable. + +- Replace the Toolkit's `workingDirectory` named argument with `appDirectory` in C#. +- Move Cargo options from the Toolkit's `args` array to the first-party Cargo methods above. Move program arguments after the old `--` separator to `WithArgs` / `withArgs`. +- Review publishing: the first-party integration can generate a Dockerfile, but an existing Dockerfile in the app directory takes precedence. +- Check custom target triples, base images, manifests, and workspace paths before publishing. + +### Toolkit-only Bacon support + +`AddBaconApp` / `addBaconApp` remains a **Community Toolkit-only** API. Keep `CommunityToolkit.Aspire.Hosting.Rust` and install [Bacon](https://dystroy.org/bacon/) for that workflow; the first-party package doesn't provide a drop-in replacement. The Toolkit runs `bacon run` by default, supports an argument array for other commands, and requires an authored Dockerfile for publishing. Those are Toolkit behaviors, not first-party Cargo publishing guarantees. + +## Configure endpoints, environment, and health checks + +Rust app resources support standard executable-resource configuration. Use `WithHttpEndpoint` / `withHttpEndpoint` to allocate a port and put it in an environment variable that the application reads. Use `WithHttpHealthCheck` / `withHttpHealthCheck` when the application exposes an HTTP health endpoint. `WithExternalHttpEndpoints` / `withExternalHttpEndpoints` makes an HTTP endpoint externally accessible. + + -```typescript title="apphost.mts" +```typescript title="apphost.mts" twoslash import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); -const checks = await builder.addBaconApp('rust-checks', '../rust-api', [ - 'check', -]); +const api = await builder.addRustApp('rust-api', '../rust-api'); +await api.withEnvironment('RUST_LOG', 'info'); +await api.withHttpEndpoint({ port: 8080, env: 'PORT' }); +await api.withExternalHttpEndpoints(); +await api.withHttpHealthCheck({ path: '/health' }); await builder.build().run(); ``` - -## Configure endpoints, environment, and health checks - -Rust app resources support standard executable-resource configuration. Use `WithHttpEndpoint` / `withHttpEndpoint` to allocate a port and put it in an environment variable that the application reads. Use `WithHttpHealthCheck` / `withHttpHealthCheck` when the application exposes an HTTP health endpoint. `WithExternalHttpEndpoints` / `withExternalHttpEndpoints` makes an HTTP endpoint externally accessible. - - ```csharp title="AppHost.cs" @@ -174,32 +166,23 @@ builder.Build().Run(); ``` - - -```typescript title="apphost.mts" -import { createBuilder } from './.aspire/modules/aspire.mjs'; + -const builder = await createBuilder(); +The integration configures the Rust app with the OpenTelemetry Protocol exporter. Add OpenTelemetry instrumentation to the Rust application to emit telemetry to Aspire. You can also use standard resource references to model dependencies and provide their configuration to the Rust process. -const api = await builder.addRustApp('rust-api', '../rust-api'); -await api.withEnvironment('RUST_LOG', 'info'); -await api.withHttpEndpoint({ port: 8080, env: 'PORT' }); -await api.withExternalHttpEndpoints(); -await api.withHttpHealthCheck({ path: '/health' }); +## Debug Rust resources -await builder.build().run(); -``` +Debugging is enabled automatically by `AddRustApp` / `addRustApp`. Use Aspire's normal **Start Debugging** flow in Visual Studio Code. Install [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) on Windows or [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) on Linux and macOS. - - +Rust resources hosted by a C# or TypeScript AppHost are distinct from experimental Rust-language `apphost.rs` AppHosts. You don't need to enable an experimental AppHost-language flag to host a Rust resource. -The integration configures the Rust app with the OpenTelemetry Protocol exporter. Add OpenTelemetry instrumentation to the Rust application to emit telemetry to Aspire. You can also use standard resource references to model dependencies and provide their configuration to the Rust process. +## Publish Rust apps -The dashboard exposes the standard executable-resource lifecycle actions and process logs. The integration doesn't add Rust-specific dashboard commands. +`aspire publish` and `aspire deploy` use the app directory as the build context. If it contains a `Dockerfile`, Aspire uses it as authored. Otherwise, Aspire generates a multi-stage Dockerfile that compiles the crate and runs it as a non-root `app` user. A `rust-toolchain.toml` pin is installed by rustup in the build image. -## Publish Rust apps +Everything needed by the build must be inside that context. For a crate with workspace inheritance or sibling path dependencies, use the workspace root as `appDirectory` and select the member with `WithCargoPackage` / `withCargoPackage`. -Both Cargo and Bacon app resources are configured as Dockerfile-published resources when they are added. During `aspire publish`, Aspire converts the executable resource to a container resource and uses the Rust app's working directory as the Docker build context. Include a suitable `Dockerfile` there. The local Cargo or Bacon arguments are cleared for the containerized resource, so configure the Dockerfile with the command and arguments it needs. +The default images use musl. A target triple doesn't install a linker or other cross-compilation tooling. When you need custom images, set both `buildImage` and `runtimeImage` in **one** `WithDockerfileBaseImage` / `withDockerfileBaseImage` call; subsequent calls replace the previous image configuration. Keep the target ABI, build image, and runtime image compatible. Non-Linux targets or architectures without a supported container-platform mapping require an authored Dockerfile. ## See also diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-init.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-init.mdx index ef2a17894..d0a1e8e51 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-init.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-init.mdx @@ -28,11 +28,13 @@ aspire agent init [options] ## Description -The `aspire agent init` command initializes Aspire skills, companion tools, and MCP (Model Context Protocol) server configuration for your development environment. It presents an interactive multi-step flow to configure AI coding agent support: +The `aspire agent init` command initializes Aspire skills and companion tools for your development environment. MCP (Model Context Protocol) server configuration is optional. It presents an interactive multi-step flow to configure AI coding agent support: 1. **Select skill locations** — choose where skill files are installed (Standard `.agents/skills/`, Claude Code `.claude/skills/`, GitHub Skills `.github/skills/`, OpenCode `.opencode/skill/`). The **Standard** location is the only option that defaults as pre-selected. 2. **Select skills and tools** — choose which Aspire workflow skills and companion tools to install. The Aspire workflow skills come from the Aspire skills bundle; optional companion tools such as `playwright-cli` and `dotnet-inspect` can be selected explicitly. -3. **Apply selections** — installs the chosen skills into each selected location and sets up the MCP server connection. +3. **Apply selections** — installs the chosen skills into each selected location. Standalone interactive setup offers MCP configuration as an explicit opt-in; it isn't selected by default. + +Setup chained from `aspire new` or `aspire init` doesn't offer MCP configuration. Non-interactive setup also skips MCP unless you supply `--mcp`. Skills teach agents to use the CLI without requiring an MCP server. The command also removes skill files from any locations that were deselected, keeping your workspace clean. @@ -48,9 +50,9 @@ The command also removes skill files from any locations that were deselected, ke ### Skills catalog and defaults -The Aspire skills bundle includes six workflow skills: `aspire`, `aspire-init`, `aspire-orchestration`, `aspire-monitoring`, `aspire-deployment`, and `aspireify`. The CLI reads the bundle catalog, so bundle-provided skills are available in the interactive prompt and through `--skills` by name. +The Aspire skills bundle includes seven workflow skills: `aspire`, `aspire-init`, `aspire-orchestration`, `aspire-monitoring`, `aspire-deployment`, `aspire-project-v2-migration`, and `aspireify`. The CLI reads the bundle catalog, so bundle-provided skills are available in the interactive prompt and through `--skills` by name. -Standalone `aspire agent init` pre-selects the bundle skills that are safe to add to an existing workspace: `aspire`, `aspire-init`, `aspire-orchestration`, `aspire-monitoring`, and `aspire-deployment`. The `aspireify` skill remains available but opt-in because it's a one-time AppHost wiring workflow. When `aspire init` chains into agent setup, `aspireify` is pre-selected because it is the natural follow-up after adding an AppHost skeleton to an existing repository. +All applicable bundle skills are pre-selected in both standalone and chained setup, including `aspireify` and `aspire-project-v2-migration`. Installing a skill doesn't execute its workflow: review and approve migration or AppHost-wiring changes when you ask an agent to use it. Companion tools remain opt-in, and project-language applicability can limit the offered skills. ### Bundle integrity verification @@ -64,7 +66,7 @@ When one or more skill files are installed or updated, the command prints a sing ```text title="Output" 🤖 Installed Aspire agent skills: - Skills: aspire, aspire-deployment, aspire-init, aspire-monitoring, aspire-orchestration + Skills: aspire, aspire-deployment, aspire-init, aspire-monitoring, aspire-orchestration, aspire-project-v2-migration, aspireify Locations: .agents/skills, ~/.agents/skills ✅ Agent environment configuration complete. ``` @@ -90,7 +92,11 @@ The following options are available: - **`--skills `** - Comma-separated list of skills to install. Aspire 13.4 includes the Aspire workflow skills `aspire`, `aspire-init`, `aspire-orchestration`, `aspire-monitoring`, `aspire-deployment`, and `aspireify`; companion options can include `playwright-cli` and, for .NET AppHosts, `dotnet-inspect`. The available list can vary by Aspire CLI version and project type. Use `all` to install all available skills or `none` to skip skill installation. When not specified, the command prompts interactively. + Comma-separated list of skills to install from the [skills catalog](#skills-catalog-and-defaults); companion options can include `playwright-cli` and, for .NET AppHosts, `dotnet-inspect`. The available list can vary by Aspire CLI version and project type. Use `all` to install all available skills or `none` to skip skill installation. When not specified, the command prompts interactively. + +- **`--mcp`** + + Explicitly opt into configuring the Aspire MCP server for detected agent environments. Without this option, non-interactive setup installs skills without configuring MCP. - @@ -115,7 +121,7 @@ The following options are available: - Install all Aspire workflow skills from the Aspire skills bundle in the standard location: ```bash title="Aspire CLI" - aspire agent init --skill-locations standard --skills aspire,aspire-init,aspire-orchestration,aspire-monitoring,aspire-deployment,aspireify + aspire agent init --skill-locations standard --skills aspire,aspire-init,aspire-orchestration,aspire-monitoring,aspire-deployment,aspire-project-v2-migration,aspireify ``` - Install all available skills and companion options in all supported skill locations: diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-describe.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-describe.mdx index a339187a0..38896ed98 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire-describe.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-describe.mdx @@ -37,6 +37,10 @@ When executed without the `--apphost` option, the command: The `aspire resources` command is a backward-compatible alias for `aspire describe`. Both names invoke the same command. + + ## Arguments - **``** diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-attach.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-attach.mdx index 42ad9b713..ec3fafcdd 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-attach.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-attach.mdx @@ -35,8 +35,6 @@ While attached, the following hotkeys are available: If the selected replica has already exited, the command attaches to the historical output buffer; no live input is sent. -Because `WithTerminal` is experimental, this command is hidden behind a feature flag. Enable it with `aspire config set features.terminalCommandsEnabled true`. - ## Arguments The following arguments are available: diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-ps.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-ps.mdx index a30112bd4..f15dd2a16 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-ps.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal-ps.mdx @@ -24,7 +24,7 @@ The `aspire terminal ps` command lists every resource in the connected AppHost t Resources whose terminal host isn't reachable are still listed with a status that indicates they're unavailable, rather than being silently dropped. -Because `WithTerminal` is experimental, this command is hidden behind a feature flag. Enable it with `aspire config set features.terminalCommandsEnabled true`. The connected AppHost must advertise the `terminals.v1` capability (Aspire.Hosting 13.4 or later). +The connected AppHost must advertise the `terminals.v1` capability (Aspire.Hosting 13.4 or later). The default output is a human-readable table with the following columns: diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal.mdx index bf2861d06..1c32bd17c 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-terminal.mdx @@ -22,12 +22,6 @@ aspire terminal [command] [options] The `aspire terminal` command provides subcommands for working with interactive terminal sessions exposed by resources that were registered using [`WithTerminal()`](/app-host/with-terminal/) in the AppHost. You can list which resources have a terminal and attach your local terminal to a running session. -Because `WithTerminal` is experimental, the `aspire terminal` command group is hidden behind a feature flag. Enable it before use: - -```bash title="Enable the aspire terminal commands" -aspire config set features.terminalCommandsEnabled true -``` - The connected AppHost must advertise the `terminals.v1` capability (Aspire.Hosting 13.4 or later). Against an older AppHost the subcommands report that terminals are not supported. ## Options diff --git a/src/frontend/src/content/docs/whats-new/aspire-13-6.mdx b/src/frontend/src/content/docs/whats-new/aspire-13-6.mdx index 9b5c78a4e..48d5cb4c1 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-13-6.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-13-6.mdx @@ -31,7 +31,7 @@ import terminalInteractionLight from '@assets/whats-new/aspire-13.6.0/terminal-i import runHistoryLight from '@assets/whats-new/aspire-13.6.0/run-history-light.webp'; import runHistoryDark from '@assets/whats-new/aspire-13.6.0/run-history-dark.webp'; -Aspire 13.6 lets you revisit completed application runs with **SQLite-backed telemetry and run history**, and work with **AppHost-owned terminals** without leaving the dashboard. It adds **first-party Java and Rust hosting**, preview **Azure Connector Namespace** support, and experimental **Azure Container Apps Sandboxes**. Portable volume paths, coordinated .NET builds, and new CLI workflows make local development and deployment more consistent. +Aspire 13.6 lets you revisit completed application runs with **SQLite-backed telemetry and run history**, and work with **AppHost-owned terminals** without leaving the dashboard. It adds **first-party Java and Rust hosting**, preview **Azure Connector Namespace** support, and preview **Azure Container Apps Sandboxes**. Portable volume paths, coordinated .NET builds, and new CLI workflows make local development and deployment more consistent. We'd love to hear what you think. Drop by [ Discord](https://aka.ms/aspire-discord) to chat with the team and the community, or file feedback and issues on [ GitHub](https://github.com/microsoft/aspire/issues). @@ -135,6 +135,12 @@ Terminal interactions bring setup workflows into a focused dialog: These APIs use `ASPIRETERMINAL001`. An AppHost-owned terminal belongs to its creator: closing a viewer isn't a general substitute for disposing the terminal, and stopping the AppHost stops its owned terminals. Resource terminals configured with `WithTerminal` remain separate from AppHost-owned dock tabs. +#### Database and cache REPLs + +Opt into `WithRepl` / `withRepl` on [PostgreSQL](/integrations/databases/postgres/postgres-host/#add-postgresql-resource-with-a-repl-command), [MySQL](/integrations/databases/mysql/mysql-host/#add-mysql-resource-with-a-repl-command), [MongoDB](/integrations/databases/mongodb/mongodb-host/#add-mongodb-resource-with-a-repl-command), [SQL Server](/integrations/databases/sql-server/sql-server-host/#add-sql-server-resource-with-a-repl-command), [Redis](/integrations/caching/redis/redis-host/#add-redis-resource-with-a-repl-command), or [Valkey](/integrations/caching/valkey/valkey-host/#add-valkey-resource-with-a-repl-command) to open the container's bundled client from a **REPL** dashboard command. No local database client installation is needed. + +REPL commands are run-only and disabled unless you opt in. They use the resource's actual credentials and aren't read-only, so enable them only for trusted dashboard users. Exit the client explicitly before closing its terminal tab; closing the viewer alone can leave the client process running inside the container. + See [resource terminals](/app-host/with-terminal/) and the [AppHost-owned terminal @@ -149,6 +155,11 @@ Authentication and antiforgery cookie names now include an application-specific Other dashboard improvements include: +- The dashboard ships as Native AOT and uses Fluent UI v5. Normal startup selects the packaged dashboard automatically, without a new configuration switch. +- Pinning or unpinning a historical run keeps the selector open and preserves the current selection. +- The empty terminal dock shows **No docked terminals**, a **More information** link, and the backtick-key hint for hiding the panel. +- Management UI integrations expose **Manage** links on the resources they administer, reducing the need to find a separate management container. +- The `azure-environment` resource uses a filled cloud icon instead of the generic resource icon. - Cross-origin or malformed `/_blazor` WebSocket upgrades are rejected before a dashboard circuit is allocated. - Pausing telemetry displays a consistent warning across telemetry pages. - Dashboard Markdown links use stricter URL validation. @@ -182,6 +193,10 @@ The new `Aspire.Hosting.Rust` package models Cargo applications through `AddRust The first-party package doesn't yet include the Community Toolkit integration's Bacon support. Custom build and runtime images also remain responsible for ABI and linker compatibility. + + See [Rust hosting and Toolkit migration](/integrations/frameworks/rust/rust-host/). + + #### Azure Connector Namespace The preview `Aspire.Hosting.Azure.ConnectorNamespace` package lets you model connections to external services and expose selected operations through managed MCP server configurations. Configure explicit operation allow-lists and Microsoft Entra access policies in your AppHost rather than managing each connection separately. @@ -190,12 +205,12 @@ The service requires preview access in your Azure subscription and region. Refer See the [Connector Namespace integration - guide](https://github.com/microsoft/aspire/blob/a11eca9611073f7cf66fa87faac63c2119e87713/src/Aspire.Hosting.Azure.ConnectorNamespace/README.md). + guide](/integrations/cloud/azure/azure-connector-namespace/). #### ☁️ Azure Container Apps Sandboxes -The experimental `Aspire.Hosting.Azure.Sandboxes` package adds Azure Container Apps Sandboxes as a deployment target. Add a sandbox group to your AppHost, and `aspire deploy` provisions the group, an Azure Container Registry, and the identities and role assignments the group needs. It then runs your project, container, and Dockerfile resources as isolated sandboxes. When the sandbox group is the only compute environment, Aspire assigns compute resources to it automatically. +The prerelease `Aspire.Hosting.Azure.Sandboxes` package adds Azure Container Apps Sandboxes as a deployment target. Add a sandbox group to your AppHost, and `aspire deploy` provisions the group, an Azure Container Registry, and the identities and role assignments the group needs. It then runs your project, container, and Dockerfile resources as isolated sandboxes. When the sandbox group is the only compute environment, Aspire assigns compute resources to it automatically. Use `PublishAsAzureSandbox` / `publishAsAzureSandbox` to choose one of five resource tiers and to configure auto-suspend and auto-delete: @@ -231,8 +246,6 @@ await builder.build().run(); ```csharp title="AppHost.cs" -#pragma warning disable ASPIREAZURE001 // Azure Container Apps Sandboxes APIs are experimental. - using Aspire.Hosting.Azure; var builder = DistributedApplication.CreateBuilder(args); @@ -258,10 +271,11 @@ builder.Build().Run(); Only endpoints marked external get a public HTTPS URL. Those URLs require Microsoft Entra ID authentication unless you opt in to anonymous access for a specific endpoint. Aspire resolves images to immutable Linux/amd64 digests and applies a deny-by-default egress policy. It also removes stale sandboxes and disk images on redeploy and on `aspire destroy`. For setup, identity, endpoint, and lifecycle details, see [Deploy to Azure Container Apps Sandboxes](/deployment/azure/sandboxes/). -