From 107cc3540416c6bfc4806ba9843672577cc1bbfe Mon Sep 17 00:00:00 2001 From: David Pine Date: Wed, 2 Sep 2026 11:02:42 -0500 Subject: [PATCH 01/29] Keep docs versions current and default to TypeScript AppHosts (#1600) * Keep docs versions current and default to TypeScript Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address TypeScript-first review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .agents/skills/doc-writer/SKILL.md | 118 +++++------ .agents/skills/whatsnew/SKILL.md | 2 +- .../whatsnew/references/01-draft-scaffold.md | 7 +- .../skills/whatsnew/references/02-research.md | 4 +- .../skills/whatsnew/references/03-critique.md | 2 +- .../skills/whatsnew/references/05-polish.md | 2 +- .../references/whats-new-template.mdx | 3 +- .../whatsnew/references/writing-guidelines.md | 3 +- ...ty-toolkit-integration-doc-writer.agent.md | 4 +- .github/agents/release-verifier.agent.md | 35 +++- src/frontend/astro.config.mjs | 3 +- ...spire-version-placeholders-integration.mjs | 19 +- src/frontend/config/aspire-versions.mjs | 4 +- .../remark-typescript-first-apphost-tabs.mjs | 121 +++++++++++ src/frontend/package.json | 1 + src/frontend/pnpm-lock.yaml | 3 + .../src/components/ContainerImages.astro | 8 +- .../src/components/IntegrationCard.astro | 16 +- .../src/components/PivotSelector.astro | 10 +- .../src/components/SimpleAppHostCode.astro | 26 +-- .../src/components/starlight/Head.astro | 9 +- .../src/content/docs/app-host/eventing.mdx | 4 +- .../docs/community/contributor-guide.mdx | 34 +-- .../docs/get-started/aspire-sdk-templates.mdx | 4 +- .../azure-ai-foundry-host.mdx | 2 +- .../cloud/azure/azure-data-explorer.mdx | 2 +- .../hosting-integrations.mdx | 4 +- .../databases/efcore/migrations.mdx | 2 +- .../integrations/devtools/browser-logs.mdx | 2 +- .../reference/cli/commands/aspire-add.mdx | 2 +- .../reference/cli/commands/aspire-doctor.mdx | 6 +- .../reference/cli/commands/aspire-new.mdx | 4 +- .../docs/reference/cli/commands/aspire-ps.mdx | 4 +- .../tests/e2e/integrations-gallery.spec.ts | 13 +- src/frontend/tests/e2e/pivot-selector.spec.ts | 28 +-- ...aspire-version-placeholders.vitest.test.ts | 193 +++++++++++++++++- .../unit/custom-components.vitest.test.ts | 50 ++++- ...pescript-first-apphost-tabs.vitest.test.ts | 84 ++++++++ 38 files changed, 653 insertions(+), 185 deletions(-) create mode 100644 src/frontend/config/remark-typescript-first-apphost-tabs.mjs create mode 100644 src/frontend/tests/unit/typescript-first-apphost-tabs.vitest.test.ts diff --git a/.agents/skills/doc-writer/SKILL.md b/.agents/skills/doc-writer/SKILL.md index 214fe49c2..2c3392ab8 100644 --- a/.agents/skills/doc-writer/SKILL.md +++ b/.agents/skills/doc-writer/SKILL.md @@ -290,17 +290,17 @@ When a page shows the **On this page** table of contents (the default behavior u If your opening section is truly introductory, keep it as body copy without an `Overview` heading. If that section has a more specific purpose, use a descriptive heading such as `Key concepts`, `Prerequisites`, or another topic-specific label. -For Aspire AppHost code examples, use synced `Tabs` / `TabItem` blocks with `syncKey='aspire-lang'` at each code snippet. Do **not** add a page-level `PivotSelector` just to switch AppHost code samples between C# and TypeScript. Readers should be able to switch the language at the specific snippet they are reading. +For Aspire AppHost code examples, use synced `Tabs` / `TabItem` blocks with `syncKey='aspire-lang'` at each code snippet. List TypeScript first so `apphost.mts` is the default experience for readers without a saved preference. Do **not** add a page-level `PivotSelector` just to switch AppHost code samples between TypeScript and C#. Readers should be able to switch the language at the specific snippet they are reading. ```mdx - -C# example content here. - - TypeScript example content here. + + +C# example content here. + ``` @@ -445,40 +445,26 @@ For client/library packages: ``` -## AppHost Language Parity (C# and TypeScript) +## AppHost Language Parity (TypeScript and C#) -Aspire supports both **C# AppHosts** (`AppHost.cs`) and **TypeScript AppHosts** (`apphost.mts`). Documentation must treat both languages as first-class citizens. **Always show both C# and TypeScript code samples for AppHost code unless the feature is genuinely language-specific or TypeScript support does not exist yet.** Never write AppHost or hosting-integration documentation with a C#-only bias. +Aspire supports both **TypeScript AppHosts** (`apphost.mts`) and **C# AppHosts** (`AppHost.cs`). Documentation must treat both languages as first-class citizens. **Always show both TypeScript and C# code samples for AppHost code unless the feature is genuinely language-specific or TypeScript support does not exist yet.** Never write AppHost or hosting-integration documentation with a C#-only bias. ### Core Principles -1. **Always show both languages**: Every AppHost-focused example, walkthrough, and AppHost code sample must include both C# and TypeScript variants unless the feature is genuinely language-specific. +1. **Always show both languages**: Every AppHost-focused example, walkthrough, and AppHost code sample must include both TypeScript and C# variants unless the feature is genuinely language-specific. 2. **Show implementations, not availability notes**: When a TypeScript AppHost API exists, demonstrate it in a complete TypeScript tab beside the C# example. A note or callout that only names the available TypeScript methods does not satisfy language parity. 3. **Use neutral framing**: Write prose that applies to both languages. Say "In your AppHost" not "In your C# project". Say "Add a Redis resource" not "Call `builder.AddRedis()`". -4. **Neither language is the default**: Don't present C# first as the "real" example and TypeScript as an afterthought. Both tabs are equal peers. +4. **Default to TypeScript**: Put the TypeScript tab first so `apphost.mts` is on the left and selected for readers without a saved preference. Keep C# as an equal peer and preserve the reader's explicit language selection. 5. **Verify TypeScript APIs exist**: Before writing a TypeScript example, confirm the API exists in the TypeScript AppHost SDK. Do not invent TypeScript samples — if you are unsure whether an API is available, flag it for review. ### AppHost tabs pattern for AppHost content -Use synced `Tabs` for AppHost-specific content that changes between C# and TypeScript. Each AppHost code snippet should provide its own language tabs and use `syncKey='aspire-lang'` so the user's language choice stays synchronized across snippets on the page. +Use synced `Tabs` for AppHost-specific content that changes between TypeScript and C#. Each AppHost code snippet should provide its own language tabs, list TypeScript first, and use `syncKey='aspire-lang'` so the user's language choice stays synchronized across snippets on the page. ````mdx import { Tabs, TabItem } from "@astrojs/starlight/components"; - - -```csharp title="AppHost.cs" -var builder = DistributedApplication.CreateBuilder(args); - -var cache = builder.AddRedis("cache"); - -builder.AddProject("api") - .WithReference(cache); - -builder.Build().Run(); -``` - - ```typescript title="apphost.mts" @@ -494,6 +480,20 @@ await api.withReference(cache); await builder.build().run(); ``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache"); + +builder.AddProject("api") + .WithReference(cache); + +builder.Build().Run(); +``` + ```` @@ -506,15 +506,15 @@ If a section heading should appear in the **On this page** table of contents, ke ### Conventions -| Aspect | C# | TypeScript | -| ---------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -| File title | `title="AppHost.cs"` | `title="apphost.mts"` | -| Tab wrapper | Shared `` container | Shared `` container | -| Tab item | `` | `` | -| Builder creation | `DistributedApplication.CreateBuilder(args)` | `import { createBuilder } from './.aspire/modules/aspire.mjs';` then newline for space followed by `await createBuilder();` | -| Method casing | PascalCase (`AddRedis`) | camelCase (`addRedis`) | -| Async pattern | Synchronous fluent calls | `await` each builder call | -| Build & run | `builder.Build().Run()` | `await builder.build().run()` | +| Aspect | TypeScript | C# | +| ---------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| File title | `title="apphost.mts"` | `title="AppHost.cs"` | +| Tab wrapper | Shared `` container | Shared `` container | +| Tab item | `` | `` | +| Builder creation | `import { createBuilder } from './.aspire/modules/aspire.mjs';` then newline for space followed by `await createBuilder();` | `DistributedApplication.CreateBuilder(args)` | +| Method casing | camelCase (`addRedis`) | PascalCase (`AddRedis`) | +| Async pattern | `await` each builder call | Synchronous fluent calls | +| Build & run | `await builder.build().run()` | `builder.Build().Run()` | ### Prose Guidelines @@ -595,18 +595,6 @@ Brief description of the technology and what the integration enables. ### Add [Technology] resource - - -```csharp title="AppHost.cs" -var builder = DistributedApplication.CreateBuilder(args); - -var tech = builder.AddTechnology("tech"); - -// After adding all resources, run the app... -builder.Build().Run(); -``` - - ```typescript title="apphost.mts" @@ -619,6 +607,18 @@ const tech = await builder.addTechnology("tech"); await builder.build().run(); ``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var tech = builder.AddTechnology("tech"); + +// After adding all resources, run the app... +builder.Build().Run(); +``` + @@ -644,20 +644,6 @@ Include both hosting and client sections: ### Add [Technology] resource - - -```csharp title="AppHost.cs" -var builder = DistributedApplication.CreateBuilder(args); - -var tech = builder.AddTechnology("tech"); - -builder.AddProject("api") - .WithReference(tech); - -builder.Build().Run(); -``` - - ```typescript title="apphost.mts" @@ -673,6 +659,20 @@ await api.withReference(tech); await builder.build().run(); ``` + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var tech = builder.AddTechnology("tech"); + +builder.AddProject("api") + .WithReference(tech); + +builder.Build().Run(); +``` + diff --git a/.agents/skills/whatsnew/SKILL.md b/.agents/skills/whatsnew/SKILL.md index 002287079..d50d41087 100644 --- a/.agents/skills/whatsnew/SKILL.md +++ b/.agents/skills/whatsnew/SKILL.md @@ -77,7 +77,7 @@ infer from context — e.g. a fresh release with no page → `draft`). | What | Path | |------|------| | What's-new pages | `src/frontend/src/content/docs/whats-new/aspire-N-N.mdx` (JA under `.../ja/whats-new/`) | -| Version constants | `src/frontend/config/aspire-versions.mjs` (`currentAspireMajorMinorVersion`, `currentAspireVersion`) | +| Version constants | `src/frontend/config/aspire-versions.mjs` (`currentAspireMajorMinorVersion`, `currentAspireVersion`, `currentAspirePreviewVersion`) | | Sidebar | `src/frontend/config/sidebar/docs.topics.ts` (What's-new `items`) | | Announcement banner | `banner:` frontmatter on `src/frontend/src/content/docs/index.mdx`, `src/frontend/src/content/docs/docs.mdx`, `src/frontend/src/content/docs/community/index.mdx`, and each `src/frontend/src/content/docs/{locale}/index.mdx` (+ `.../ja/docs.mdx`); rendered by `src/frontend/src/components/starlight/Banner.astro` | | Assets | `src/frontend/src/assets/whats-new/aspire-/` | diff --git a/.agents/skills/whatsnew/references/01-draft-scaffold.md b/.agents/skills/whatsnew/references/01-draft-scaffold.md index ee7692df0..9efe95cd3 100644 --- a/.agents/skills/whatsnew/references/01-draft-scaffold.md +++ b/.agents/skills/whatsnew/references/01-draft-scaffold.md @@ -35,8 +35,11 @@ duplicating. dedicated **"New integrations"** and **"Default container image updates"** sections. If the file already exists, reconcile structure without clobbering existing content. 3. **Version constants.** Update `src/frontend/config/aspire-versions.mjs`: - `currentAspireMajorMinorVersion = 'N.N'` and `currentAspireVersion = 'N.N.0'` (only - when N.N is the new current release). This drives the `%ASPIRE_VERSION%` remark + `currentAspireMajorMinorVersion = 'N.N'`, `currentAspireVersion` to the latest + stable `N.N.PATCH`, and `currentAspirePreviewVersion` to the matching full + `N.N.PATCH-preview.*` package version. Set both package versions to the initial + release patch when N.N becomes current, then keep them aligned with the site + AppHost during servicing updates. These drive the Aspire version remark placeholders site-wide. 4. **Site-wide announcement banner.** The banner is **per-page frontmatter**, not a global config. Update the `banner.content` string **and its link** to point at diff --git a/.agents/skills/whatsnew/references/02-research.md b/.agents/skills/whatsnew/references/02-research.md index 1ec421858..b39a82d90 100644 --- a/.agents/skills/whatsnew/references/02-research.md +++ b/.agents/skills/whatsnew/references/02-research.md @@ -47,8 +47,8 @@ This is the phase that turns the skeleton into a real, reviewable page. the section (next step). 7. **Author the draft.** Populate the scaffolded MDX from the dossier: write the lede, the "This release introduces" bullets (1:1 with the `##` sections, same order), and - each section body with impact-first prose, `LearnMore` deep-links, and C#/TypeScript - `` where a feature spans AppHost languages. Credit each + each section body with impact-first prose, `LearnMore` deep-links, and TypeScript/C# + `` with TypeScript first where a feature spans AppHost languages. Credit each merged community PR by `@handle`. **Only include sections that apply** — delete any standard section with no content. In particular, when the release has **no breaking changes**, remove the "⚠️ Breaking changes" section *and* the breaking-changes diff --git a/.agents/skills/whatsnew/references/03-critique.md b/.agents/skills/whatsnew/references/03-critique.md index 85dd7392e..b945bb0f7 100644 --- a/.agents/skills/whatsnew/references/03-critique.md +++ b/.agents/skills/whatsnew/references/03-critique.md @@ -28,7 +28,7 @@ actionable, severity-ranked findings report. **Makes no edits** — {polish} act - ` -### Manual Relationships — No Inference +## Manual Relationships — No Inference Aspire **does not infer** parent-child relationships automatically based on names, dependencies, or network links. @@ -52,7 +52,7 @@ You must **explicitly declare** relationships by either: This explicitness ensures developers have full control over resource containment and presentation. -### Real-world scenarios +## Real-world scenarios The following scenarios illustrate how Aspire models parent-child relationships: diff --git a/src/frontend/src/content/docs/architecture/resource-publishing.mdx b/src/frontend/src/content/docs/architecture/resource-publishing.mdx index 85be16cd3..eece9edb0 100644 --- a/src/frontend/src/content/docs/architecture/resource-publishing.mdx +++ b/src/frontend/src/content/docs/architecture/resource-publishing.mdx @@ -20,7 +20,7 @@ Custom resources that publish JSON manifest entries must: Resources can opt-out of being included in the publishing manifest entirely by calling the `ExcludeFromManifest()` extension method on the `IResourceBuilder`. Resources marked this way will be omitted when generating publishing assets like Docker Compose files or Kubernetes manifests. -### Registering the callback +## Registering the callback Consider the following example of a custom Azure Bicep resource that publishes its parameters to a manifest: @@ -34,7 +34,7 @@ public class AzureBicepResource : Resource, IAzureResource } ``` -### Writing to the manifest +## Writing to the manifest As an example, the `WriteToManifest` method serializes the resource's parameters into a JSON object. This method is invoked during the manifest publishing phase: @@ -56,7 +56,7 @@ public virtual void WriteToManifest(ManifestPublishingContext context) } ``` -### Summary table +## Summary table The following table summarizes the key steps and conventions for publishing resources: diff --git a/src/frontend/src/content/docs/community/thanks.mdx b/src/frontend/src/content/docs/community/thanks.mdx index 64f1fc0a7..9a633520c 100644 --- a/src/frontend/src/content/docs/community/thanks.mdx +++ b/src/frontend/src/content/docs/community/thanks.mdx @@ -122,7 +122,7 @@ import asciinemaIcon from '@assets/icons/asciinema-icon.svg';

Thank you, open source

-
+
Standing on the
shoulders of giants diff --git a/src/frontend/src/content/docs/deployment/app-lifecycle.mdx b/src/frontend/src/content/docs/deployment/app-lifecycle.mdx index d1500e328..5874e7709 100644 --- a/src/frontend/src/content/docs/deployment/app-lifecycle.mdx +++ b/src/frontend/src/content/docs/deployment/app-lifecycle.mdx @@ -296,7 +296,7 @@ In [this example](https://github.com/BethMassi/VolumeMount/blob/main/.github/wor -#### Step 1: Setup Environment +### Step 1: Setup Environment ```yaml # Required for C# AppHost projects @@ -306,7 +306,7 @@ In [this example](https://github.com/BethMassi/VolumeMount/blob/main/.github/wor dotnet-version: '10.0.x' ``` -#### Step 2: Install Aspire CLI +### Step 2: Install Aspire CLI ```yaml - name: Install Aspire CLI @@ -316,7 +316,7 @@ In [this example](https://github.com/BethMassi/VolumeMount/blob/main/.github/wor echo "$HOME/.aspire/bin" >> $GITHUB_PATH ``` -#### Step 3. Build App, Create & Push Image to GHCR +### Step 3. Build App, Create & Push Image to GHCR ```yaml - name: Login to GHCR @@ -352,7 +352,7 @@ The `aspire do push` command does the following: [Command reference: `aspire do`](/reference/cli/commands/aspire-do/) -#### Step 4: Publish Docker Compose Artifacts +### Step 4: Publish Docker Compose Artifacts ```yaml - name: Prepare Docker Compose with Aspire @@ -384,7 +384,7 @@ The `aspire publish` command does the following: [Command reference: `aspire publish`](/reference/cli/commands/aspire-publish/) -#### Step 5: Upload Deployment Artifacts +### Step 5: Upload Deployment Artifacts ```yaml - name: Upload Aspire artifacts diff --git a/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx b/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx index bb868e8fd..642d63e12 100644 --- a/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx @@ -12,7 +12,7 @@ import { Badge } from '@astrojs/starlight/components'; This diagnostic warns when using the experimental `IInteractionService` interface and related interaction APIs. These APIs provide the ability to prompt users for input, request confirmation, and display messages in the Aspire dashboard or CLI during publish and deploy operations. -### Example generating diagnostic +## Example generating diagnostic ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); 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 fd066c3c2..97cc405a8 100644 --- a/src/frontend/src/content/docs/get-started/aspire-skills.mdx +++ b/src/frontend/src/content/docs/get-started/aspire-skills.mdx @@ -152,7 +152,7 @@ Before you install, make sure you have: Install the `microsoft/aspire-skills` marketplace through the GitHub Copilot app: -1. Click [this link](https://github.com/copilot/app/launch?entry_point=aspire_skills_docs&open=ghapp%3A%2F%2Fplugins%2Fmarketplace%2Fadd%3Fsource%3Dmicrosoft%2Faspire-skills) to automatically open the **Settings** > **Plugins** window in the GitHub Copilot app. +1. Open the [`aspire-skills` marketplace install link](https://github.com/copilot/app/launch?entry_point=aspire_skills_docs&open=ghapp%3A%2F%2Fplugins%2Fmarketplace%2Fadd%3Fsource%3Dmicrosoft%2Faspire-skills) to automatically open the **Settings** > **Plugins** window in the GitHub Copilot app. 2. In the **Add plugin marketplace?** dialog, select **Allow**. 3. The **Plugins** window opens with the `microsoft/aspire-skills` marketplace. Select **Add marketplace**. 4. Expand the `aspire-skills` entry and select **Install** on the `aspire` plugin. diff --git a/src/frontend/src/content/docs/get-started/prerequisites.mdx b/src/frontend/src/content/docs/get-started/prerequisites.mdx index 1caa76790..eec49d904 100644 --- a/src/frontend/src/content/docs/get-started/prerequisites.mdx +++ b/src/frontend/src/content/docs/get-started/prerequisites.mdx @@ -17,7 +17,7 @@ Ready to dive into Aspire? Before you begin, make sure your development environm -1. #### Install your language runtime +1. ## Install your language runtime @@ -54,7 +54,7 @@ Ready to dive into Aspire? Before you begin, make sure your development environm -1. #### Install an OCI-compliant container runtime +1. ## Install an OCI-compliant container runtime -#### Consider alternatives to local installation (Optional) +## Consider alternatives to local installation (Optional) If you prefer not to install the prerequisites on your local machine, you can develop Aspire solutions using cloud-based options like [GitHub Codespaces](/get-started/github-codespaces/) or [Dev Containers](/get-started/dev-containers/). These options allow you to work in a cloud-based environment, eliminating the need for local installations, but may not provide the same performance as local installations. diff --git a/src/frontend/src/content/docs/integrations/ai/github-models/github-models-connect.mdx b/src/frontend/src/content/docs/integrations/ai/github-models/github-models-connect.mdx index 7b68bd694..a89bfa830 100644 --- a/src/frontend/src/content/docs/integrations/ai/github-models/github-models-connect.mdx +++ b/src/frontend/src/content/docs/integrations/ai/github-models/github-models-connect.mdx @@ -62,15 +62,15 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is one of the Aspire client integrations. GitHub Models is OpenAI-compatible, so you can use either `Aspire.Azure.AI.Inference` (for the Azure AI Inference SDK) or `Aspire.OpenAI` (for the OpenAI SDK). Both integrations register the client through dependency injection and, optionally, register an `IChatClient` from `Microsoft.Extensions.AI`. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Using Azure AI Inference +### Using Azure AI Inference -##### Install the client integration +#### Install the client integration Install the [📦 Aspire.Azure.AI.Inference](https://www.nuget.org/packages/Aspire.Azure.AI.Inference) NuGet package in the client-consuming project: -##### Add a ChatCompletionsClient +#### Add a ChatCompletionsClient In _Program.cs_, call `AddAzureChatCompletionsClient` on your `IHostApplicationBuilder` to register a `ChatCompletionsClient`: @@ -91,7 +91,7 @@ public class ExampleService(ChatCompletionsClient client) } ``` -##### Add a ChatCompletionsClient with IChatClient +#### Add a ChatCompletionsClient with IChatClient Call `AddChatClient` after `AddAzureChatCompletionsClient` to also register an `IChatClient` from `Microsoft.Extensions.AI`: @@ -113,17 +113,17 @@ public class ExampleService(IChatClient chatClient) } ``` -#### Using OpenAI client +### Using OpenAI client For models compatible with the OpenAI API (such as `openai/gpt-4o-mini`), you can use the OpenAI client. -##### Install the client integration +#### Install the client integration Install the [📦 Aspire.OpenAI](https://www.nuget.org/packages/Aspire.OpenAI) NuGet package in the client-consuming project: -##### Add an OpenAI client +#### Add an OpenAI client In _Program.cs_, call `AddOpenAIClient` to register an `OpenAIClient`: @@ -147,14 +147,14 @@ public class ChatService(OpenAIClient client, IConfiguration config) } ``` -##### Add an OpenAI client with IChatClient +#### Add an OpenAI client with IChatClient ```csharp title="Program.cs" builder.AddOpenAIClient("chat") .AddChatClient(); ``` -##### Configuration +#### Configuration The Aspire OpenAI client integration supports configuration through connection strings, `Microsoft.Extensions.Configuration`, and inline delegates. @@ -187,7 +187,7 @@ The Aspire OpenAI client integration supports configuration through connection s builder.AddOpenAIClient("chat", settings => settings.DisableTracing = true); ``` -##### Observability and telemetry +#### Observability and telemetry The Aspire OpenAI client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -197,7 +197,7 @@ The Aspire OpenAI client integration automatically configures logging, tracing, or the `OPENAI_EXPERIMENTAL_ENABLE_OPEN_TELEMETRY=true` environment variable. -##### Read environment variables in C\# +#### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection properties directly: diff --git a/src/frontend/src/content/docs/integrations/ai/ollama/ollama-connect.mdx b/src/frontend/src/content/docs/integrations/ai/ollama/ollama-connect.mdx index e1f70ab7e..4b34f4d0f 100644 --- a/src/frontend/src/content/docs/integrations/ai/ollama/ollama-connect.mdx +++ b/src/frontend/src/content/docs/integrations/ai/ollama/ollama-connect.mdx @@ -73,13 +73,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire OllamaSharp client integration. It registers an `IOllamaApiClient` through dependency injection and supports `Microsoft.Extensions.AI` abstractions (`IChatClient`, `IEmbeddingGenerator`). If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.OllamaSharp](https://www.nuget.org/packages/CommunityToolkit.Aspire.OllamaSharp) NuGet package in the client-consuming project: -#### Add the Ollama API client +### Add the Ollama API client In _Program.cs_, call `AddOllamaApiClient` on your `IHostApplicationBuilder` to register an `IOllamaApiClient`. When the resource provided in the AppHost is an `OllamaModelResource`, the model is set as the default model automatically: @@ -100,7 +100,7 @@ public class ExampleService(IOllamaApiClient ollama) } ``` -#### Add keyed Ollama clients +### Add keyed Ollama clients To register multiple `IOllamaApiClient` instances with different connection names, use `AddKeyedOllamaApiClient`: @@ -120,7 +120,7 @@ public class ExampleService( } ``` -#### Integration with Microsoft.Extensions.AI +### Integration with Microsoft.Extensions.AI The [📦 Microsoft.Extensions.AI](https://www.nuget.org/packages/Microsoft.Extensions.AI) package provides portable `IChatClient` and `IEmbeddingGenerator>` abstractions. OllamaSharp supports these interfaces and you can register them by chaining onto `AddOllamaApiClient`: @@ -143,7 +143,7 @@ public class ExampleService(IChatClient chatClient) } ``` -#### Add keyed Microsoft.Extensions.AI clients +### Add keyed Microsoft.Extensions.AI clients ```csharp title="Program.cs" builder.AddOllamaApiClient("chat") @@ -163,7 +163,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration **Connection strings.** When using a connection string from the `ConnectionStrings` configuration section, pass the connection name to `AddOllamaApiClient`: @@ -181,7 +181,7 @@ The connection string is resolved from the `ConnectionStrings` section: } ``` -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected environment variables directly and construct an `OllamaApiClient`: diff --git a/src/frontend/src/content/docs/integrations/ai/openai/openai-connect.mdx b/src/frontend/src/content/docs/integrations/ai/openai/openai-connect.mdx index 942a058c0..ea842cba2 100644 --- a/src/frontend/src/content/docs/integrations/ai/openai/openai-connect.mdx +++ b/src/frontend/src/content/docs/integrations/ai/openai/openai-connect.mdx @@ -66,13 +66,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire OpenAI client integration. It registers an [`OpenAIClient`](https://learn.microsoft.com/dotnet/api/azure.ai.openai.openaiclient) through dependency injection and, optionally, registers an [`IChatClient`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.ai.ichatclient) or [`IEmbeddingGenerator`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.ai.iembeddinggenerator-2) via `Microsoft.Extensions.AI`. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.OpenAI](https://www.nuget.org/packages/Aspire.OpenAI) NuGet package in the client-consuming project: -#### Add an OpenAI client +### Add an OpenAI client In _Program.cs_, call `AddOpenAIClient` on your `IHostApplicationBuilder` to register an `OpenAIClient`: @@ -93,7 +93,7 @@ public class ExampleService(OpenAIClient client) } ``` -#### Add a chat client +### Add a chat client Call `AddChatClient` after `AddOpenAIClient` to also register an `IChatClient` from `Microsoft.Extensions.AI`. The model name is inferred from the connection string's `Model` property: @@ -118,7 +118,7 @@ public class ExampleService(IChatClient chatClient) } ``` -#### Add keyed OpenAI clients +### Add keyed OpenAI clients To register multiple `OpenAIClient` instances with different connection names, use `AddKeyedOpenAIClient`: @@ -138,7 +138,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire OpenAI client integration offers multiple ways to provide configuration. @@ -182,11 +182,11 @@ builder.AddOpenAIClient("chat", settings => settings.DisableTracing = true); builder.AddOpenAIClient("chat", configureOptions: o => o.NetworkTimeout = TimeSpan.FromSeconds(30)); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The OpenAI client integration does not register a runtime health check on its own (health checks are opt-in per model at the hosting level — see [Add health check per model](../openai-host/#add-health-check-per-model)). -#### Observability and telemetry +### Observability and telemetry The Aspire OpenAI client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -209,7 +209,7 @@ The Aspire OpenAI client integration automatically configures logging, tracing, - `OpenAI.*` meter (when OpenTelemetry is enabled) -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection properties from the environment and construct an `OpenAIClient` directly: diff --git a/src/frontend/src/content/docs/integrations/caching/garnet/garnet-connect.mdx b/src/frontend/src/content/docs/integrations/caching/garnet/garnet-connect.mdx index ed8ebbbe6..359539b48 100644 --- a/src/frontend/src/content/docs/integrations/caching/garnet/garnet-connect.mdx +++ b/src/frontend/src/content/docs/integrations/caching/garnet/garnet-connect.mdx @@ -75,13 +75,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Redis client integration — Garnet is RESP-compatible, so the same client works. It registers an [`IConnectionMultiplexer`](https://stackexchange.github.io/StackExchange.Redis/Basics.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.StackExchange.Redis](https://www.nuget.org/packages/Aspire.StackExchange.Redis) NuGet package in the client-consuming project: -#### Add the Redis client +### Add the Redis client In _Program.cs_, call `AddRedisClient` on your `IHostApplicationBuilder` to register an `IConnectionMultiplexer`: @@ -102,7 +102,7 @@ public class ExampleService(IConnectionMultiplexer connectionMux) } ``` -#### Add keyed Redis clients +### Add keyed Redis clients To register multiple `IConnectionMultiplexer` instances with different connection names, use `AddKeyedRedisClient`: @@ -122,7 +122,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Redis client integration offers multiple ways to provide configuration. @@ -168,11 +168,11 @@ builder.AddRedisClient( static settings => settings.DisableTracing = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Redis client integration adds a health check that verifies the Garnet instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Redis client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -186,14 +186,14 @@ The Aspire Redis client integration automatically configures logging, tracing, a **Metrics** are emitted through OpenTelemetry. Any of these telemetry features can be disabled through the configuration options above. -#### Distributed caching and output caching +### Distributed caching and output caching Garnet also works with the Aspire distributed-caching and output-caching client integrations because they're built on top of the same Redis client. Install the respective packages and follow their guides: - [Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) — see [Get started with Redis distributed caching](/integrations/caching/redis-distributed/redis-distributed-get-started/). - [Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) — see [Get started with Redis output caching](/integrations/caching/redis-output/redis-output-get-started/). -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to [📦 StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) directly: diff --git a/src/frontend/src/content/docs/integrations/caching/redis-distributed/redis-distributed-connect.mdx b/src/frontend/src/content/docs/integrations/caching/redis-distributed/redis-distributed-connect.mdx index aeea3cdf4..8ca4661c2 100644 --- a/src/frontend/src/content/docs/integrations/caching/redis-distributed/redis-distributed-connect.mdx +++ b/src/frontend/src/content/docs/integrations/caching/redis-distributed/redis-distributed-connect.mdx @@ -47,13 +47,13 @@ The `Aspire.StackExchange.Redis.DistributedCaching` client integration reads the -#### Install the client integration +### Install the client integration Install the [📦 Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) NuGet package in the client-consuming project: -#### Add Redis distributed cache +### Add Redis distributed cache In _Program.cs_, call `AddRedisDistributedCache` on your `IHostApplicationBuilder` to register an `IDistributedCache` backed by Redis: @@ -74,7 +74,7 @@ public class ExampleService(IDistributedCache cache) } ``` -#### Add keyed Redis distributed cache +### Add keyed Redis distributed cache `IDistributedCache` is registered as a singleton, so only one instance can be registered in the normal DI container. If you need multiple Redis-backed `IDistributedCache` instances alongside an `IConnectionMultiplexer`, use `AddKeyedRedisDistributedCache`: @@ -95,7 +95,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The client integration supports three configuration approaches that can be combined. @@ -152,7 +152,7 @@ builder.AddRedisDistributedCache( static options => options.ConnectTimeout = 3_000); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Redis distributed caching client integration adds a health check that verifies the Redis instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint — all registered checks must pass before the app is considered ready to accept traffic. @@ -172,7 +172,7 @@ Disable health checks via configuration: } ``` -#### Observability and telemetry +### Observability and telemetry The client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -186,7 +186,7 @@ The client integration automatically configures logging, tracing, and metrics th **Metrics** are emitted through OpenTelemetry. Any telemetry feature can be disabled through the configuration options above. -#### Use the client +### Use the client Inject `IDistributedCache` wherever you need it and use the standard ASP.NET Core caching API: diff --git a/src/frontend/src/content/docs/integrations/caching/redis-output/redis-output-connect.mdx b/src/frontend/src/content/docs/integrations/caching/redis-output/redis-output-connect.mdx index 534f8b8b7..7635a65ea 100644 --- a/src/frontend/src/content/docs/integrations/caching/redis-output/redis-output-connect.mdx +++ b/src/frontend/src/content/docs/integrations/caching/redis-output/redis-output-connect.mdx @@ -45,13 +45,13 @@ ASP.NET Core output caching is a C#-only feature — only the C# client integrat -#### Install the client integration +### Install the client integration Install the [📦 Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) NuGet package in the consuming project: -#### Register the output cache store +### Register the output cache store In _Program.cs_, call `AddRedisOutputCache` to register `IOutputCacheStore` and add the output caching middleware: @@ -71,7 +71,7 @@ var app = builder.Build(); app.UseOutputCache(); ``` -#### Use `[OutputCache]` on endpoints +### Use `[OutputCache]` on endpoints For minimal API endpoints, use the `CacheOutput()` extension method or the `[OutputCache]` attribute: @@ -101,7 +101,7 @@ public class WeatherController : ControllerBase } ``` -#### Configuration +### Configuration The client integration offers three ways to supply configuration. @@ -155,11 +155,11 @@ builder.AddRedisOutputCache( configureOptions: options => options.ConnectTimeout = 3000); ``` -#### Client integration health checks +### Client integration health checks By default, Aspire integrations enable health checks. The Redis output caching integration adds a health check that verifies the Redis instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint — all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Redis output caching integration automatically configures logging, tracing, and metrics through OpenTelemetry. diff --git a/src/frontend/src/content/docs/integrations/caching/redis/redis-connect.mdx b/src/frontend/src/content/docs/integrations/caching/redis/redis-connect.mdx index faa159b3d..df72e4414 100644 --- a/src/frontend/src/content/docs/integrations/caching/redis/redis-connect.mdx +++ b/src/frontend/src/content/docs/integrations/caching/redis/redis-connect.mdx @@ -75,13 +75,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Redis client integration. It registers an [`IConnectionMultiplexer`](https://stackexchange.github.io/StackExchange.Redis/Basics.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables in C#](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.StackExchange.Redis](https://www.nuget.org/packages/Aspire.StackExchange.Redis) NuGet package in the client-consuming project: -#### Add the Redis client +### Add the Redis client In _Program.cs_, call `AddRedisClient` on your `IHostApplicationBuilder` to register an `IConnectionMultiplexer`: @@ -102,7 +102,7 @@ public class ExampleService(IConnectionMultiplexer connectionMux) } ``` -#### Add keyed Redis clients +### Add keyed Redis clients To register multiple `IConnectionMultiplexer` instances with different connection names, use `AddKeyedRedisClient`: @@ -124,7 +124,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Redis client integration offers multiple ways to provide configuration. @@ -170,7 +170,7 @@ builder.AddRedisClient( static settings => settings.DisableTracing = true); ``` -#### Redis client builder pattern +### Redis client builder pattern Use `AddRedisClientBuilder` to configure Redis clients with a fluent API, which is especially useful when combining Redis with distributed caching or Azure authentication: @@ -193,7 +193,7 @@ builder.AddRedisClientBuilder("cache") }); ``` -#### Auto activation +### Auto activation Redis client connections support auto activation to prevent startup deadlocks and improve application reliability. Auto activation is disabled by default but can be enabled using the `DisableAutoActivation` option: @@ -205,11 +205,11 @@ builder.AddRedisClient("cache", c => c.DisableAutoActivation = false); In a future version of Aspire, auto activation is planned to be **enabled by default**. When this change occurs, you'll need to explicitly set `DisableAutoActivation = true` if you want to maintain the lazy initialization behavior. -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Redis client integration adds a health check that verifies the Redis instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Redis client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -223,14 +223,14 @@ The Aspire Redis client integration automatically configures logging, tracing, a **Metrics** are emitted through OpenTelemetry. Any of these telemetry features can be disabled through the configuration options above. -#### Distributed caching and output caching +### Distributed caching and output caching Redis also works with the Aspire distributed-caching and output-caching client integrations because they're built on top of the same Redis client. Install the respective packages and follow their guides: - [Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) — see [Get started with Redis distributed caching](/integrations/caching/redis-distributed/redis-distributed-get-started/). - [Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) — see [Get started with Redis output caching](/integrations/caching/redis-output/redis-output-get-started/). -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to [📦 StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) directly: diff --git a/src/frontend/src/content/docs/integrations/caching/valkey/valkey-connect.mdx b/src/frontend/src/content/docs/integrations/caching/valkey/valkey-connect.mdx index 6c02b4829..d729010bd 100644 --- a/src/frontend/src/content/docs/integrations/caching/valkey/valkey-connect.mdx +++ b/src/frontend/src/content/docs/integrations/caching/valkey/valkey-connect.mdx @@ -75,13 +75,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Redis client integration — Valkey is RESP-compatible, so the same client works. It registers an [`IConnectionMultiplexer`](https://stackexchange.github.io/StackExchange.Redis/Basics.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.StackExchange.Redis](https://www.nuget.org/packages/Aspire.StackExchange.Redis) NuGet package in the client-consuming project: -#### Add the Redis client +### Add the Redis client In _Program.cs_, call `AddRedisClient` on your `IHostApplicationBuilder` to register an `IConnectionMultiplexer`: @@ -102,7 +102,7 @@ public class ExampleService(IConnectionMultiplexer connectionMux) } ``` -#### Add keyed Redis clients +### Add keyed Redis clients To register multiple `IConnectionMultiplexer` instances with different connection names, use `AddKeyedRedisClient`: @@ -122,7 +122,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Redis client integration offers multiple ways to provide configuration. @@ -168,11 +168,11 @@ builder.AddRedisClient( static settings => settings.DisableTracing = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Redis client integration adds a health check that verifies the Valkey instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Redis client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -186,14 +186,14 @@ The Aspire Redis client integration automatically configures logging, tracing, a **Metrics** are emitted through OpenTelemetry. Any of these telemetry features can be disabled through the configuration options above. -#### Distributed caching and output caching +### Distributed caching and output caching Valkey also works with the Aspire distributed-caching and output-caching client integrations because they're built on top of the same Redis client. Install the respective packages and follow their guides: - [Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) — see [Get started with Redis distributed caching](/integrations/caching/redis-distributed/redis-distributed-get-started/). - [Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) — see [Get started with Redis output caching](/integrations/caching/redis-output/redis-output-get-started/). -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to [📦 StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) directly: 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 1d41612f2..528473e74 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 @@ -82,13 +82,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure AI Foundry client integration via the [📦 Aspire.Azure.AI.Inference](https://www.nuget.org/packages/Aspire.Azure.AI.Inference) NuGet package. It registers a `ChatCompletionsClient` through dependency injection and, optionally, registers an [`IChatClient`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.ai.ichatclient) via `Microsoft.Extensions.AI`. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.AI.Inference](https://www.nuget.org/packages/Aspire.Azure.AI.Inference) NuGet package in the client-consuming project: -#### Add a chat completions client +### Add a chat completions client In _Program.cs_, call `AddAzureAIInferenceChatClient` on your `IHostApplicationBuilder` to register a `ChatCompletionsClient`: @@ -109,7 +109,7 @@ public class ExampleService(ChatCompletionsClient client) } ``` -#### Add an IChatClient via Microsoft.Extensions.AI +### Add an IChatClient via Microsoft.Extensions.AI To also register an `IChatClient` from `Microsoft.Extensions.AI`, chain `AsIChatClient()`: @@ -131,7 +131,7 @@ public class ExampleService(IChatClient chatClient) } ``` -#### Add keyed clients +### Add keyed clients To register multiple `ChatCompletionsClient` instances with different connection names, use `AddKeyedAzureAIInferenceChatClient`: @@ -151,7 +151,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Azure AI Inference client integration supports multiple configuration approaches. @@ -188,11 +188,11 @@ The connection string is resolved from the `ConnectionStrings` section: } ``` -#### Client integration health checks +### Client integration health checks The Aspire Azure AI Inference client integration enables health checks by default, verifying that the endpoint is reachable. Integration with the `/health` HTTP endpoint ensures all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure AI Inference client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -208,7 +208,7 @@ The Aspire Azure AI Inference client integration automatically configures loggin - `Azure.AI.Inference.*` -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection properties from the environment and construct an `AzureAIInferenceClient` directly using the [📦 Azure.AI.Inference](https://www.nuget.org/packages/Azure.AI.Inference/) NuGet package: 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 5eef8a9d6..47be3bd88 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 @@ -59,13 +59,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure AI Inference client integration. It registers a `ChatCompletionsClient` through dependency injection and adds health checks and telemetry automatically. If you'd rather read the connection string directly, see the [Read the connection string](#read-the-connection-string-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.AI.Inference](https://www.nuget.org/packages/Aspire.Azure.AI.Inference) NuGet package in the client-consuming project: -#### Add a chat completions client +### Add a chat completions client In _Program.cs_, call `AddAzureChatCompletionsClient` on your `IHostApplicationBuilder` to register a `ChatCompletionsClient`: @@ -86,7 +86,7 @@ public class ExampleService(ChatCompletionsClient client) } ``` -#### Register an IChatClient +### Register an IChatClient Chain `AddChatClient` to also register an `IChatClient` from `Microsoft.Extensions.AI`: @@ -108,7 +108,7 @@ public class ExampleService(IChatClient chatClient) } ``` -#### Add an embeddings client +### Add an embeddings client Call `AddAzureEmbeddingsClient` to register an `EmbeddingsClient`: @@ -116,7 +116,7 @@ Call `AddAzureEmbeddingsClient` to register an `EmbeddingsClient`: builder.AddAzureEmbeddingsClient(connectionName: "ai-foundry"); ``` -#### Add keyed clients +### Add keyed clients To register multiple clients with different connection names, use the keyed variants: @@ -138,7 +138,7 @@ public class ExampleService( For more information, see [Keyed services in .NET](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure AI Inference client integration offers multiple ways to provide configuration. @@ -177,11 +177,11 @@ builder.AddAzureChatCompletionsClient( configureSettings: static settings => settings.DisableTracing = true); ``` -#### Client integration health checks +### Client integration health checks 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. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure AI Inference client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -198,7 +198,7 @@ The Aspire Azure AI Inference client integration automatically configures loggin Telemetry is only recorded by default when using the `IChatClient` interface from `Microsoft.Extensions.AI`. Raw `ChatCompletionsClient` calls do not automatically generate telemetry. -#### Read the connection string in C\# +### Read the connection string in C\# If you prefer not to use the Aspire client integration, install the [📦 Azure.AI.Inference](https://www.nuget.org/packages/Azure.AI.Inference/) NuGet package and read the connection string from `IConfiguration` directly: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-search/azure-ai-search-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-search/azure-ai-search-connect.mdx index 7baa225a4..8bd28a435 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-search/azure-ai-search-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-ai-search/azure-ai-search-connect.mdx @@ -58,13 +58,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure AI Search client integration. It registers a [`SearchIndexClient`](https://learn.microsoft.com/dotnet/api/azure.search.documents.indexes.searchindexclient) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Search.Documents](https://www.nuget.org/packages/Aspire.Azure.Search.Documents) NuGet package in the client-consuming project: -#### Add the Azure Search index client +### Add the Azure Search index client In _Program.cs_, call `AddAzureSearchClient` on your `IHostApplicationBuilder` to register a `SearchIndexClient`: @@ -104,7 +104,7 @@ public class ExampleService(SearchIndexClient indexClient) } ``` -#### Add keyed Azure Search index clients +### Add keyed Azure Search index clients To register multiple `SearchIndexClient` instances with different connection names, use `AddKeyedAzureSearchClient`: @@ -126,7 +126,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure AI Search client integration offers multiple ways to provide configuration. @@ -212,11 +212,11 @@ builder.AddAzureSearchClient( static options => options.Diagnostics.ApplicationId = "CLIENT_ID")); ``` -#### Client integration health checks +### Client integration health checks The Azure AI Search client integration adds a health check that calls `GetServiceStatisticsAsync` on the `SearchIndexClient` to verify that the service is available. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure AI Search client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -232,7 +232,7 @@ The Aspire Azure AI Search client integration automatically configures logging, Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected endpoint from the environment and use the [📦 Azure.Search.Documents](https://www.nuget.org/packages/Azure.Search.Documents/) package directly with `DefaultAzureCredential`: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-configuration/azure-app-configuration-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-configuration/azure-app-configuration-connect.mdx index 62f8b445e..82ec688c0 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-configuration/azure-app-configuration-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-configuration/azure-app-configuration-connect.mdx @@ -46,13 +46,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure App Configuration client integration. It registers an Azure App Configuration provider into the `IConfiguration` pipeline through dependency injection and supports feature flags. If you'd rather read the environment variable directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Microsoft.Extensions.Configuration.AzureAppConfiguration](https://www.nuget.org/packages/Aspire.Microsoft.Extensions.Configuration.AzureAppConfiguration) NuGet package in the client-consuming project: -#### Add the Azure App Configuration provider +### Add the Azure App Configuration provider In _Program.cs_, call `AddAzureAppConfiguration` on your `IHostApplicationBuilder` to register the Azure App Configuration provider and populate `IConfiguration`: @@ -73,7 +73,7 @@ public class ExampleService(IConfiguration configuration) } ``` -#### Configure the App Configuration provider +### Configure the App Configuration provider The `AddAzureAppConfiguration` method accepts an optional `Action` delegate. This follows the same pattern as the standard `Microsoft.Extensions.Configuration.AzureAppConfiguration` package, but Aspire automatically handles the connection — you don't need to call `options.Connect`: @@ -97,7 +97,7 @@ builder.AddAzureAppConfiguration( For more information on available options, see the [Azure App Configuration provider reference](https://learn.microsoft.com/azure/azure-app-configuration/reference-dotnet-provider). -#### Use feature flags +### Use feature flags To use feature flags, install the [📦 Microsoft.FeatureManagement](https://www.nuget.org/packages/Microsoft.FeatureManagement) NuGet package: @@ -129,7 +129,7 @@ app.MapGet("/", async (IFeatureManager featureManager) => For more information, see [.NET Feature Management](https://learn.microsoft.com/azure/azure-app-configuration/feature-management-dotnet-reference). -#### Configuration +### Configuration The Aspire Azure App Configuration client integration offers multiple ways to provide configuration. @@ -171,11 +171,11 @@ builder.AddAzureAppConfiguration( configureSettings: settings => settings.Endpoint = new Uri("https://YOUR_URI")); ``` -#### Client integration health checks +### Client integration health checks The Azure App Configuration client integration doesn't register a dedicated health check. App health is monitored through the standard ASP.NET Core health check endpoints. -#### Observability and telemetry +### Observability and telemetry **Logging** categories: @@ -185,7 +185,7 @@ The Azure App Configuration client integration doesn't register a dedicated heal **Metrics:** The Azure App Configuration client integration doesn't currently support metrics. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected endpoint from the environment and create a `ConfigurationClient` directly using the [📦 Azure.Data.AppConfiguration](https://www.nuget.org/packages/Azure.Data.AppConfiguration/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-cache-redis/azure-cache-redis-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-cache-redis/azure-cache-redis-connect.mdx index dbba2178f..c985bbbbc 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-cache-redis/azure-cache-redis-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-cache-redis/azure-cache-redis-connect.mdx @@ -50,13 +50,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Redis client integration. It registers an [`IConnectionMultiplexer`](https://stackexchange.github.io/StackExchange.Redis/Basics.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables in C#](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.StackExchange.Redis](https://www.nuget.org/packages/Aspire.StackExchange.Redis) NuGet package in the client-consuming project: -#### Add the Redis client +### Add the Redis client In _Program.cs_, call `AddRedisClient` on your `IHostApplicationBuilder` to register an `IConnectionMultiplexer`: @@ -77,7 +77,7 @@ public class ExampleService(IConnectionMultiplexer connectionMux) } ``` -#### Add keyed Redis clients +### Add keyed Redis clients To register multiple `IConnectionMultiplexer` instances with different connection names, use `AddKeyedRedisClient`: @@ -99,7 +99,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Azure Entra ID authentication +### Azure Entra ID authentication To enable Microsoft Entra ID (managed identity) authentication for Azure Cache for Redis in C#, install the [📦 Aspire.Microsoft.Azure.StackExchangeRedis](https://www.nuget.org/packages/Aspire.Microsoft.Azure.StackExchangeRedis) NuGet package and use the `AddRedisClientBuilder` API with `WithAzureAuthentication`: @@ -110,7 +110,7 @@ builder.AddRedisClientBuilder("cache") This configures the Redis client to obtain access tokens using the app's managed identity when running in Azure, without storing passwords in connection strings. -#### Configuration +### Configuration The Aspire Redis client integration offers multiple ways to provide configuration. @@ -156,11 +156,11 @@ builder.AddRedisClient( static settings => settings.DisableTracing = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Redis client integration adds a health check that verifies the Redis instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Redis client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -174,14 +174,14 @@ The Aspire Redis client integration automatically configures logging, tracing, a **Metrics** are emitted through OpenTelemetry. Any of these telemetry features can be disabled through the configuration options above. -#### Distributed caching and output caching +### Distributed caching and output caching Azure Cache for Redis also works with the Aspire distributed-caching and output-caching client integrations because they're built on top of the same Redis client. Install the respective packages and follow their guides: - [Aspire.StackExchange.Redis.DistributedCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.DistributedCaching) — see [Get started with Redis distributed caching](/integrations/caching/redis-distributed/redis-distributed-get-started/). - [Aspire.StackExchange.Redis.OutputCaching](https://www.nuget.org/packages/Aspire.StackExchange.Redis.OutputCaching) — see [Get started with Redis output caching](/integrations/caching/redis-output/redis-output-get-started/). -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection properties from the environment and configure [📦 StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) directly: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-connect.mdx index 5e29e0e29..752ed3bf9 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-connect.mdx @@ -92,13 +92,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Cosmos DB client integration. It registers a [`CosmosClient`](https://learn.microsoft.com/dotnet/api/microsoft.azure.cosmos.cosmosclient) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Microsoft.Azure.Cosmos](https://www.nuget.org/packages/Aspire.Microsoft.Azure.Cosmos) NuGet package in the client-consuming project: -#### Add the Cosmos DB client +### Add the Cosmos DB client In _Program.cs_, call `AddAzureCosmosClient` on your `IHostApplicationBuilder` to register a `CosmosClient`: @@ -119,7 +119,7 @@ public class ExampleService(CosmosClient cosmosClient) } ``` -#### Add keyed Cosmos DB clients +### Add keyed Cosmos DB clients To register multiple `CosmosClient` instances with different connection names, use `AddKeyedAzureCosmosClient`: @@ -139,7 +139,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Azure Cosmos DB client integration offers multiple ways to provide configuration. @@ -187,11 +187,11 @@ builder.AddAzureCosmosClient( static settings => settings.DisableTracing = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Cosmos DB client integration adds a health check that verifies the account is reachable. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Cosmos DB client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -205,11 +205,11 @@ The Aspire Azure Cosmos DB client integration automatically configures logging, **Metrics** are emitted through OpenTelemetry. Any of these telemetry features can be disabled through the configuration options above. -#### Entity Framework Core variant +### Entity Framework Core variant If you prefer Entity Framework Core over the direct `CosmosClient`, install the [📦 Aspire.Microsoft.EntityFrameworkCore.Cosmos](https://www.nuget.org/packages/Aspire.Microsoft.EntityFrameworkCore.Cosmos) package and call `AddCosmosDbContext` instead. For the full EF Core reference, see [Entity Framework Core — Azure Cosmos DB integration](/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-get-started/). -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection string from the environment and construct a `CosmosClient` directly: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-event-hubs/azure-event-hubs-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-event-hubs/azure-event-hubs-connect.mdx index 51588280f..273710d0c 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-event-hubs/azure-event-hubs-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-event-hubs/azure-event-hubs-connect.mdx @@ -75,13 +75,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Messaging Event Hubs client integration. It registers strongly-typed Event Hubs client instances through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Messaging.EventHubs](https://www.nuget.org/packages/Aspire.Azure.Messaging.EventHubs) NuGet package in the client-consuming project: -#### Supported client types +### Supported client types The following Event Hubs client types are supported, along with their corresponding options and settings classes: @@ -93,7 +93,7 @@ The following Event Hubs client types are supported, along with their correspond | `EventProcessorClient` | `EventProcessorClientOptions` | `AzureMessagingEventHubsProcessorSettings` | | `PartitionReceiver` | `PartitionReceiverOptions` | `AzureMessagingEventHubsPartitionReceiverSettings` | -#### Add an Event Hubs producer client +### Add an Event Hubs producer client In _Program.cs_, call `AddAzureEventHubProducerClient` to register an `EventHubProducerClient`: @@ -114,7 +114,7 @@ public class ExampleService(EventHubProducerClient producerClient) } ``` -#### Add an Event Hubs processor client +### Add an Event Hubs processor client To consume events, register an `EventProcessorClient`: @@ -131,7 +131,7 @@ public class ExampleService(EventProcessorClient processorClient) } ``` -#### All registration APIs +### All registration APIs When you need to register a different client type, use the corresponding API: @@ -143,7 +143,7 @@ When you need to register a different client type, use the corresponding API: | `EventProcessorClient` | `AddAzureEventProcessorClient` | | `PartitionReceiver` | `AddAzurePartitionReceiverClient` | -#### Add keyed Event Hubs clients +### Add keyed Event Hubs clients To register multiple client instances with different connection names, use the keyed APIs: @@ -175,7 +175,7 @@ The full set of keyed registration APIs: For more information, see [Keyed services in .NET](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure Messaging Event Hubs library supports multiple configuration approaches. Either a `FullyQualifiedNamespace` or a `ConnectionString` is required. @@ -265,11 +265,11 @@ builder.AddAzureEventProcessorClient( For the complete JSON schema, see [Aspire.Azure.Messaging.EventHubs/ConfigurationSchema.json](https://github.com/microsoft/aspire/blob/main/src/Components/Aspire.Azure.Messaging.EventHubs/ConfigurationSchema.json). -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Messaging Event Hubs client integration registers a health check that verifies connectivity to the namespace. The health check is wired into the `/health` HTTP endpoint. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Messaging Event Hubs client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -284,7 +284,7 @@ The Aspire Azure Messaging Event Hubs client integration automatically configure **Metrics:** The Azure Messaging Event Hubs client integration currently doesn't support metrics by default due to limitations with the Azure SDK for .NET. This section will be updated if that changes. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the connection URI from the environment and use the Azure SDK directly: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-functions/azure-functions-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-functions/azure-functions-connect.mdx index 72fe96ab7..b354da35e 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-functions/azure-functions-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-functions/azure-functions-connect.mdx @@ -51,7 +51,7 @@ Pick the language your Functions project is written in. The .NET isolated worker model starts the Functions host through a standard `HostBuilder`. You can read Aspire-injected values through `IConfiguration` (which maps environment variables automatically) or through `Environment.GetEnvironmentVariable`. -#### Read through IConfiguration +### Read through IConfiguration `IConfiguration` is available through dependency injection. Register a class that receives the configuration section you need: @@ -81,7 +81,7 @@ public class MyBlobService(IConfiguration config) } ``` -#### Read through Environment.GetEnvironmentVariable +### Read through Environment.GetEnvironmentVariable For one-off reads, use `Environment.GetEnvironmentVariable` directly in your function class: @@ -106,7 +106,7 @@ public class MyFunction } ``` -#### Use connection name attributes for triggers +### Use connection name attributes for triggers Azure Functions trigger attributes accept a `Connection` parameter that maps to the environment variable prefix Aspire injects. For a Service Bus queue trigger using the `servicebus` resource: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-key-vault/azure-key-vault-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-key-vault/azure-key-vault-connect.mdx index 68a9aae80..72c654157 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-key-vault/azure-key-vault-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-key-vault/azure-key-vault-connect.mdx @@ -47,13 +47,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Key Vault client integration. It registers an [`SecretClient`](https://learn.microsoft.com/dotnet/api/azure.security.keyvault.secrets.secretclient) through dependency injection and adds health checks and telemetry automatically. The integration also provides an optional configuration provider that surfaces vault secrets through the standard `IConfiguration` API. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Security.KeyVault](https://www.nuget.org/packages/Aspire.Azure.Security.KeyVault) NuGet package in the client-consuming project: -#### Add the Azure Key Vault client +### Add the Azure Key Vault client In _Program.cs_, call `AddAzureKeyVaultClient` on your `IHostApplicationBuilder` to register a `SecretClient`: @@ -78,7 +78,7 @@ public class ExampleService(SecretClient secretClient) } ``` -#### Add secrets to configuration +### Add secrets to configuration Alternatively, call `AddAzureKeyVaultSecrets` to surface vault secrets through the `IConfiguration` API. This is useful for reading secrets with the options pattern or `IConfiguration` directly: @@ -108,7 +108,7 @@ public class ExampleService(IOptions options) does not add new secrets to the vault. -#### Add keyed Azure Key Vault clients +### Add keyed Azure Key Vault clients To register multiple `SecretClient` instances with different vault names, use `AddKeyedAzureKeyVaultClient`: @@ -130,7 +130,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure Key Vault client integration offers multiple ways to provide configuration. @@ -180,14 +180,14 @@ builder.AddAzureKeyVaultClient( configureSettings: settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Key Vault client integration adds: - The `AzureKeyVaultSecretsHealthCheck`, which attempts to connect to and query the vault. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Key Vault client integration automatically configures logging and tracing through OpenTelemetry. diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-openai/azure-openai-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-openai/azure-openai-connect.mdx index e79f94031..ae2f561ec 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-openai/azure-openai-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-openai/azure-openai-connect.mdx @@ -72,13 +72,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure OpenAI client integration. It registers an [`AzureOpenAIClient`](https://learn.microsoft.com/dotnet/api/azure.ai.openai.azureopenaiclient) through dependency injection and, optionally, registers an [`IChatClient`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.ai.ichatclient) via `Microsoft.Extensions.AI`. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.AI.OpenAI](https://www.nuget.org/packages/Aspire.Azure.AI.OpenAI) NuGet package in the client-consuming project: -#### Add an Azure OpenAI client +### Add an Azure OpenAI client In _Program.cs_, call `AddAzureOpenAIClient` on your `IHostApplicationBuilder` to register an `AzureOpenAIClient`: @@ -99,7 +99,7 @@ public class ExampleService(AzureOpenAIClient client) } ``` -#### Add a chat client +### Add a chat client Call `AddChatClient` after `AddAzureOpenAIClient` to also register an `IChatClient` from `Microsoft.Extensions.AI`. The deployment name is passed as an argument: @@ -130,7 +130,7 @@ public class ExampleService(IChatClient chatClient) For more information on `IChatClient` and `Microsoft.Extensions.AI`, see [Unified AI Building Blocks for .NET](https://learn.microsoft.com/dotnet/core/extensions/artificial-intelligence). -#### Add keyed Azure OpenAI clients +### Add keyed Azure OpenAI clients To register multiple `AzureOpenAIClient` instances with different connection names, use `AddKeyedAzureOpenAIClient`: @@ -150,7 +150,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Azure OpenAI client integration offers multiple ways to provide configuration. @@ -220,7 +220,7 @@ builder.AddAzureOpenAIClient( }); ``` -#### Add Azure OpenAI client from configuration +### Add Azure OpenAI client from configuration Use `AddOpenAIClientFromConfiguration` to register an `OpenAIClient` or `AzureOpenAIClient` based on the connection string value: @@ -237,11 +237,11 @@ The method selects the client type according to these rules: | `Endpoint=https://{account}.openai.azure.com/;Key={key};IsAzure=false` | `OpenAIClient` | | `Endpoint=https://localhost:18889;Key={key}` | `OpenAIClient` | -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure OpenAI client integration participates in the standard Aspire health check pipeline. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure OpenAI client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -264,7 +264,7 @@ The Aspire Azure OpenAI integration currently does not emit metrics by default d Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected endpoint from the environment and construct an `AzureOpenAIClient` directly using `DefaultAzureCredential` for managed identity: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-connect.mdx index a121995f0..f75a57eca 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-connect.mdx @@ -78,13 +78,13 @@ For C# apps, the recommended approach is the Aspire PostgreSQL client integratio When targeting Azure with Entra ID (the default), use [📦 Aspire.Azure.Npgsql](https://www.nuget.org/packages/Aspire.Azure.Npgsql) instead of `Aspire.Npgsql`. It adds an Entra token provider so no password is needed. The examples below use `Aspire.Npgsql` which works for both local-container development and password-authenticated Azure deployments. See [Azure PostgreSQL client integration](/integrations/cloud/azure/azure-postgresql/azure-postgresql-connect/#use-the-azure-npgsql-integration-for-entra-id) below for the Entra ID variant. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Npgsql](https://www.nuget.org/packages/Aspire.Npgsql) NuGet package in the client-consuming project: -#### Add the Npgsql data source +### Add the Npgsql data source In _Program.cs_, call `AddNpgsqlDataSource` on your `IHostApplicationBuilder` to register an `NpgsqlDataSource`: @@ -105,7 +105,7 @@ public class ExampleService(NpgsqlDataSource dataSource) } ``` -#### Add keyed Npgsql clients +### Add keyed Npgsql clients To register multiple `NpgsqlDataSource` instances with different connection names, use `AddKeyedNpgsqlDataSource`: @@ -125,7 +125,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire PostgreSQL client integration offers multiple ways to provide configuration. @@ -168,14 +168,14 @@ builder.AddNpgsqlDataSource( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The PostgreSQL client integration adds: - The [`NpgSqlHealthCheck`](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/src/HealthChecks.NpgSql/NpgSqlHealthCheck.cs), which verifies that commands can be successfully executed against the underlying PostgreSQL database. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire PostgreSQL client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -207,7 +207,7 @@ The Aspire PostgreSQL client integration automatically configures logging, traci Any of these telemetry features can be disabled through the configuration options above. -#### Use the Azure Npgsql integration for Entra ID +### Use the Azure Npgsql integration for Entra ID When your app targets Azure and you want to use Entra ID (managed identity) authentication — the default for Azure Database for PostgreSQL — install [📦 Aspire.Azure.Npgsql](https://www.nuget.org/packages/Aspire.Azure.Npgsql) instead and call `AddAzureNpgsqlDataSource`: @@ -221,7 +221,7 @@ This registers an `NpgsqlDataSource` with an Entra token provider attached, so n For more information, see [PostgreSQL Entity Framework Core integrations](/integrations/databases/efcore/postgres/postgresql-get-started/) if you prefer an EF Core abstraction over raw `NpgsqlDataSource`. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to the [📦 Npgsql](https://www.nuget.org/packages/Npgsql/) NuGet package directly: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-service-bus/azure-service-bus-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-service-bus/azure-service-bus-connect.mdx index 253d2464f..c17711022 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-service-bus/azure-service-bus-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-service-bus/azure-service-bus-connect.mdx @@ -71,13 +71,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Service Bus client integration. It registers a [`ServiceBusClient`](https://learn.microsoft.com/dotnet/api/azure.messaging.servicebus.servicebusclient) through dependency injection and adds health checks and telemetry automatically. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Messaging.ServiceBus](https://www.nuget.org/packages/Aspire.Azure.Messaging.ServiceBus) NuGet package in the client-consuming project: -#### Add the Service Bus client +### Add the Service Bus client In _Program.cs_, call `AddAzureServiceBusClient` on your `IHostApplicationBuilder` to register a `ServiceBusClient`: @@ -98,7 +98,7 @@ public class ExampleService(ServiceBusClient client) } ``` -#### Add keyed Service Bus clients +### Add keyed Service Bus clients To register multiple `ServiceBusClient` instances with different connection names, use `AddKeyedAzureServiceBusClient`: @@ -120,7 +120,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure Service Bus client integration offers multiple ways to provide configuration. @@ -197,11 +197,11 @@ builder.AddAzureServiceBusClient( clientOptions => clientOptions.Identifier = "myapp"); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Service Bus client integration verifies that the Service Bus is reachable. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Service Bus client integration automatically configures logging, tracing, and metrics through OpenTelemetry. diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-signalr/azure-signalr-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-signalr/azure-signalr-connect.mdx index 39ccde409..808171ee5 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-signalr/azure-signalr-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-signalr/azure-signalr-connect.mdx @@ -59,7 +59,7 @@ Pick the language your consuming app is written in. Each example assumes your Ap The recommended approach for C# hub server apps is the `Microsoft.Azure.SignalR` package. It integrates Azure SignalR Service directly into ASP.NET Core's SignalR infrastructure and reads configuration injected by Aspire. -#### Default mode — hub server +### Default mode — hub server In _Default_ mode, your hub server project registers its hubs normally with Azure SignalR Service acting as the transport layer. Install the [📦 Microsoft.Azure.SignalR](https://www.nuget.org/packages/Microsoft.Azure.SignalR) NuGet package: @@ -86,7 +86,7 @@ The `AddNamedAzureSignalR` method reads the connection string from `ConnectionSt If you're using the Azure SignalR emulator, you cannot use `AddNamedAzureSignalR`. The emulator requires Serverless mode — see the [Serverless mode](#serverless-mode) section below. -#### Serverless mode +### Serverless mode In _Serverless_ mode, there is no hub server. Instead, apps communicate with Azure SignalR Service through the Management SDK. Install the [📦 Microsoft.Azure.SignalR.Management](https://www.nuget.org/packages/Microsoft.Azure.SignalR.Management) NuGet package: @@ -131,7 +131,7 @@ The `/negotiate` endpoint establishes a connection between the connecting client For more information, see [Use Azure SignalR Management SDK](https://learn.microsoft.com/azure/azure-signalr/signalr-howto-use-management-sdk). -#### Read environment variables in C\# +### Read environment variables in C\# To read the endpoint URI directly from the Aspire-injected environment variable: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database/azure-sql-database-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database/azure-sql-database-connect.mdx index a60cd01de..e86722002 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database/azure-sql-database-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database/azure-sql-database-connect.mdx @@ -79,13 +79,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire SQL Server client integration. It registers a [`SqlConnection`](https://learn.microsoft.com/dotnet/api/microsoft.data.sqlclient.sqlconnection) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Microsoft.Data.SqlClient](https://www.nuget.org/packages/Aspire.Microsoft.Data.SqlClient) NuGet package in the client-consuming project: -#### Add the SQL Server client +### Add the SQL Server client In _Program.cs_, call `AddSqlServerClient` on your `IHostApplicationBuilder` to register a `SqlConnection`: @@ -106,7 +106,7 @@ public class ExampleService(SqlConnection connection) } ``` -#### Add keyed SQL Server clients +### Add keyed SQL Server clients To register multiple `SqlConnection` instances with different connection names, use `AddKeyedSqlServerClient`: @@ -128,7 +128,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire SQL Server client integration offers multiple ways to provide configuration. @@ -176,14 +176,14 @@ builder.AddSqlServerClient( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The SQL Server client integration adds: - A health check that attempts to connect to the Azure SQL Database instance and execute a command. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire SQL Server client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -214,7 +214,7 @@ The Aspire SQL Server client integration automatically configures logging, traci Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and open a connection using [📦 Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/): diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs/azure-storage-blobs-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs/azure-storage-blobs-connect.mdx index 76916f004..008742ae0 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs/azure-storage-blobs-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs/azure-storage-blobs-connect.mdx @@ -65,13 +65,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Blob Storage client integration. It registers a [`BlobServiceClient`](https://learn.microsoft.com/dotnet/api/azure.storage.blobs.blobserviceclient) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Storage.Blobs](https://www.nuget.org/packages/Aspire.Azure.Storage.Blobs) NuGet package in the client-consuming project: -#### Add the Blob Storage client +### Add the Blob Storage client In _Program.cs_, call `AddAzureBlobServiceClient` on your `IHostApplicationBuilder` to register a `BlobServiceClient`: @@ -92,7 +92,7 @@ public class ExampleService(BlobServiceClient client) } ``` -#### Add keyed Blob Storage clients +### Add keyed Blob Storage clients To register multiple `BlobServiceClient` instances with different connection names, use `AddKeyedAzureBlobServiceClient`: @@ -114,7 +114,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure Blob Storage client integration offers multiple ways to provide configuration. @@ -186,14 +186,14 @@ builder.AddAzureBlobServiceClient( options => options.Diagnostics.ApplicationId = "myapp")); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Blob Storage client integration: - Adds the health check when `DisableHealthChecks` is `false`, which attempts to connect to the Azure Blob Storage service. - Integrates with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Blob Storage client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -208,7 +208,7 @@ The Aspire Azure Blob Storage client integration automatically configures loggin **Metrics** are not emitted by default due to limitations with the Azure SDK. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected blob endpoint from the environment and create a `BlobServiceClient` directly using the [📦 Azure.Storage.Blobs](https://www.nuget.org/packages/Azure.Storage.Blobs/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-queues/azure-storage-queues-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-queues/azure-storage-queues-connect.mdx index ab199c7e6..208008a60 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-queues/azure-storage-queues-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-queues/azure-storage-queues-connect.mdx @@ -64,13 +64,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Queue Storage client integration. It registers a [`QueueServiceClient`](https://learn.microsoft.com/dotnet/api/azure.storage.queues.queueserviceclient) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Storage.Queues](https://www.nuget.org/packages/Aspire.Azure.Storage.Queues) NuGet package in the client-consuming project: -#### Add the Queue Storage client +### Add the Queue Storage client In _Program.cs_, call `AddAzureQueueServiceClient` on your `IHostApplicationBuilder` to register a `QueueServiceClient`: @@ -91,7 +91,7 @@ public class ExampleService(QueueServiceClient client) } ``` -#### Add keyed Queue Storage clients +### Add keyed Queue Storage clients To register multiple `QueueServiceClient` instances with different connection names, use `AddKeyedAzureQueueServiceClient`: @@ -113,7 +113,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure Queue Storage client integration offers multiple ways to provide configuration. @@ -183,14 +183,14 @@ builder.AddAzureQueueServiceClient( options => options.Diagnostics.ApplicationId = "myapp")); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Queue Storage client integration: - Adds a health check when `DisableHealthChecks` is `false`, which verifies that a connection can be established to the queue service. - Integrates with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Queue Storage client integration automatically configures logging and tracing through OpenTelemetry. @@ -205,7 +205,7 @@ The Aspire Azure Queue Storage client integration automatically configures loggi **Metrics:** The Azure Queue Storage integration currently doesn't support metrics by default due to limitations in the Azure SDK. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected service URI from the environment and create a `QueueServiceClient` directly using [📦 Azure.Storage.Queues](https://www.nuget.org/packages/Azure.Storage.Queues/): diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-tables/azure-storage-tables-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-tables/azure-storage-tables-connect.mdx index 4eeaf29d7..75ef9023f 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-tables/azure-storage-tables-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-tables/azure-storage-tables-connect.mdx @@ -52,13 +52,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Data Tables client integration. It registers a [`TableServiceClient`](https://learn.microsoft.com/dotnet/api/azure.data.tables.tableserviceclient) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Data.Tables](https://www.nuget.org/packages/Aspire.Azure.Data.Tables) NuGet package in the client-consuming project: -#### Add the Table Storage client +### Add the Table Storage client In _Program.cs_, call `AddAzureTableServiceClient` on your `IHostApplicationBuilder` to register a `TableServiceClient`: @@ -79,7 +79,7 @@ public class ExampleService(TableServiceClient client) } ``` -#### Add keyed Table Storage clients +### Add keyed Table Storage clients To register multiple `TableServiceClient` instances with different connection names, use `AddKeyedAzureTableServiceClient`: @@ -101,7 +101,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Azure Data Tables client integration offers multiple ways to provide configuration. @@ -160,7 +160,7 @@ builder.AddAzureTableServiceClient( options => options.EnableTenantDiscovery = true)); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Data Tables client integration adds: @@ -169,7 +169,7 @@ Aspire client integrations enable health checks by default. The Azure Data Table To disable health checks, set `DisableHealthChecks` to `true` in the configuration. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Data Tables client integration automatically configures logging and tracing through OpenTelemetry. @@ -184,7 +184,7 @@ The Aspire Azure Data Tables client integration automatically configures logging **Metrics:** The Azure Data Tables integration currently doesn't support metrics by default due to limitations in the Azure SDK. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection string from the environment and construct a `TableServiceClient` directly using the [📦 Azure.Data.Tables](https://www.nuget.org/packages/Azure.Data.Tables/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-web-pubsub/azure-web-pubsub-connect.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-web-pubsub/azure-web-pubsub-connect.mdx index f317efdfd..2a3a03638 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-web-pubsub/azure-web-pubsub-connect.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-web-pubsub/azure-web-pubsub-connect.mdx @@ -69,13 +69,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Azure Web PubSub client integration. It registers a [`WebPubSubServiceClient`](https://learn.microsoft.com/dotnet/api/azure.messaging.webpubsub.webpubsubserviceclient) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Messaging.WebPubSub](https://www.nuget.org/packages/Aspire.Azure.Messaging.WebPubSub) NuGet package in the client-consuming project: -#### Add the Web PubSub service client +### Add the Web PubSub service client In _Program.cs_, call `AddAzureWebPubSubServiceClient` on your `IHostApplicationBuilder` to register a `WebPubSubServiceClient`: @@ -98,7 +98,7 @@ public class ExampleService(WebPubSubServiceClient client) } ``` -#### Add keyed Web PubSub clients +### Add keyed Web PubSub clients To register multiple `WebPubSubServiceClient` instances for different hubs, use `AddKeyedAzureWebPubSubServiceClient`: @@ -123,7 +123,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Azure Web PubSub client integration offers multiple ways to provide configuration. @@ -174,11 +174,11 @@ builder.AddAzureWebPubSubServiceClient( settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure Web PubSub client integration registers a health check that verifies the service is reachable. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure Web PubSub client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -195,7 +195,7 @@ The Aspire Azure Web PubSub client integration automatically configures logging, **Metrics:** The Azure Web PubSub integration currently doesn't support metrics by default due to limitations in the Azure SDK for .NET. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected endpoint URI from the environment and create a `WebPubSubServiceClient` directly: diff --git a/src/frontend/src/content/docs/integrations/databases/clickhouse/clickhouse-connect.mdx b/src/frontend/src/content/docs/integrations/databases/clickhouse/clickhouse-connect.mdx index 1e3ed1906..c2c9f0b24 100644 --- a/src/frontend/src/content/docs/integrations/databases/clickhouse/clickhouse-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/clickhouse/clickhouse-connect.mdx @@ -66,13 +66,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire ClickHouse client integration. It registers an `IClickHouseClient` and a `ClickHouseDataSource` through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.ClickHouse.Driver](https://www.nuget.org/packages/Aspire.ClickHouse.Driver) NuGet package in the client-consuming project: -#### Add the ClickHouse data source +### Add the ClickHouse data source In _Program.cs_, call `AddClickHouseDataSource` on your `IHostApplicationBuilder` to register both `IClickHouseClient` and `ClickHouseDataSource`: @@ -102,7 +102,7 @@ public class ExampleService(ClickHouseDataSource dataSource) } ``` -#### Add keyed ClickHouse data sources +### Add keyed ClickHouse data sources To register multiple `ClickHouseDataSource` instances with different connection names, use `AddKeyedClickHouseDataSource`: @@ -124,7 +124,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire ClickHouse client integration offers multiple ways to provide configuration. @@ -170,14 +170,14 @@ builder.AddClickHouseDataSource( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The ClickHouse client integration adds: - A health check that calls `PingAsync` on the configured `ClickHouseDataSource`. If the ping succeeds, the health check is considered healthy. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire ClickHouse client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -198,7 +198,7 @@ The Aspire ClickHouse client integration automatically configures logging, traci Any logging or tracing features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection string from the environment and use it with the `ClickHouse.Driver` package directly: diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-connect.mdx index 920b21c6f..4add08988 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-connect.mdx @@ -30,13 +30,13 @@ Add the Aspire EF Core Azure Cosmos DB client integration to your C# consuming a -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Microsoft.EntityFrameworkCore.Cosmos](https://www.nuget.org/packages/Aspire.Microsoft.EntityFrameworkCore.Cosmos) NuGet package in the client-consuming project: -#### Add Cosmos DB context +### Add Cosmos DB context In _Program.cs_, call `AddCosmosDbContext` on your `IHostApplicationBuilder` to register a `DbContext` for use via the dependency injection container: @@ -65,7 +65,7 @@ public class ExampleService(MyDbContext context) For more information on using Entity Framework Core with Azure Cosmos DB, see the [EF Core Azure Cosmos DB provider documentation](https://learn.microsoft.com/ef/core/providers/cosmos/?tabs=dotnet-core-cli). -#### Add keyed Cosmos DB contexts +### Add keyed Cosmos DB contexts To register multiple `DbContext` instances with different connection names, use `AddKeyedCosmosDbContext`: @@ -85,18 +85,18 @@ public class ExampleService( } ``` -#### Connection properties +### Connection properties Aspire exposes each Cosmos DB resource property as an environment variable named `[RESOURCE]_[PROPERTY]`. The EF Core client integration reads these automatically from the resource name you pass to `AddCosmosDbContext`. -##### Cosmos DB account +#### Cosmos DB account | Property Name | Environment Variable | Description | | ------------------ | ---------------------------- | ----------- | | `ConnectionString` | `[RESOURCE]_CONNECTIONSTRING` | The account endpoint URI. When access key authentication is enabled, also includes `AccountKey={key};`. | | `AccountKey` | `[RESOURCE]_ACCOUNTKEY` | The account key (only available when running the emulator or when access key authentication is enabled). | -##### Cosmos DB database +#### Cosmos DB database Inherits Cosmos DB account properties, plus: @@ -104,7 +104,7 @@ Inherits Cosmos DB account properties, plus: | -------------- | ------------------------- | ----------- | | `DatabaseName` | `[RESOURCE]_DATABASENAME` | The name of the database. | -##### Cosmos DB container +#### Cosmos DB container Inherits Cosmos DB database properties, plus: @@ -112,11 +112,11 @@ Inherits Cosmos DB database properties, plus: | --------------- | -------------------------- | ----------- | | `ContainerName` | `[RESOURCE]_CONTAINERNAME` | The name of the container. | -#### Configuration +### Configuration The Aspire EF Core Azure Cosmos DB integration offers multiple ways to provide configuration. -##### Use a connection string +#### Use a connection string When using a connection string from the `ConnectionStrings` configuration section, pass the connection name to `AddCosmosDbContext`: @@ -136,7 +136,7 @@ The connection string is resolved from the `ConnectionStrings` section: For more information, see the [ConnectionString documentation](https://learn.microsoft.com/azure/cosmos-db/nosql/how-to-dotnet-get-started#connect-with-a-connection-string). -##### Use configuration providers +#### Use configuration providers The integration supports `Microsoft.Extensions.Configuration`. It loads `EntityFrameworkCoreCosmosSettings` from _appsettings.json_ (or any other configuration source) by using the `Aspire:Microsoft:EntityFrameworkCore:Cosmos` key: @@ -156,7 +156,7 @@ The integration supports `Microsoft.Extensions.Configuration`. It loads `EntityF For the complete JSON schema, see [Aspire.Microsoft.EntityFrameworkCore.Cosmos/ConfigurationSchema.json](https://github.com/microsoft/aspire/blob/main/src/Components/Aspire.Microsoft.EntityFrameworkCore.Cosmos/ConfigurationSchema.json). -##### Use inline delegates +#### Use inline delegates Pass an `Action` to configure settings inline, for example to disable tracing: @@ -166,15 +166,15 @@ builder.AddCosmosDbContext( settings => settings.DisableTracing = true); ``` -#### Client integration health checks +### Client integration health checks The Aspire EF Core Azure Cosmos DB integration currently doesn't implement health checks, though this may change in future releases. -#### Observability and telemetry +### Observability and telemetry The Aspire EF Core Azure Cosmos DB integration automatically configures logging, tracing, and metrics through OpenTelemetry. -##### Logging +#### Logging Log categories: @@ -184,14 +184,14 @@ Log categories: - `Microsoft.EntityFrameworkCore.Infrastructure` - `Microsoft.EntityFrameworkCore.Query` -##### Tracing +#### Tracing Tracing activities: - `Azure.Cosmos.Operation` - `OpenTelemetry.Instrumentation.EntityFrameworkCore` -##### Metrics +#### Metrics Metrics emitted through OpenTelemetry: diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-connect.mdx index 6f5a261f3..a245de4dd 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-connect.mdx @@ -61,13 +61,13 @@ The recommended approach for C# apps is the Aspire Azure PostgreSQL EF Core clie -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Azure.Npgsql.EntityFrameworkCore.PostgreSQL](https://www.nuget.org/packages/Aspire.Azure.Npgsql.EntityFrameworkCore.PostgreSQL/) NuGet package in the client-consuming project: -#### Add the DbContext +### Add the DbContext In _Program.cs_, call `AddAzureNpgsqlDbContext` on your `IHostApplicationBuilder` to register a pooled `DbContext` that uses Azure authentication ([Microsoft Entra ID](https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-azure-ad-authentication)) by default: @@ -94,11 +94,11 @@ public class ExampleService(YourDbContext context) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -#### Add keyed DbContext instances +### Add keyed DbContext instances To register multiple `DbContext` instances with different connection names, use the keyed service pattern by configuring separate named sections. See [Configure multiple DbContext classes](#configure-multiple-dbcontext-classes) for details. -#### Enrich a manually registered DbContext +### Enrich a manually registered DbContext If you need more control over `DbContext` registration — for example, to reuse existing configuration code, use EF Core interceptors, or opt out of context pooling — register the `DbContext` manually and call `EnrichAzureNpgsqlDbContext` to add Aspire health checks, retries, logging, and telemetry: @@ -117,7 +117,7 @@ builder.EnrichAzureNpgsqlDbContext( The `settings` parameter is an instance of `AzureNpgsqlEntityFrameworkCorePostgreSQLSettings`. -#### Configuration +### Configuration The client integration supports multiple ways to provide configuration. @@ -179,7 +179,7 @@ builder.Services.AddDbContextPool( builder.EnrichAzureNpgsqlDbContext(); ``` -#### Configure multiple DbContext classes +### Configure multiple DbContext classes To register more than one `DbContext` with different configuration, use the `$"Aspire:Npgsql:EntityFrameworkCore:PostgreSQL:{typeof(TContext).Name}"` configuration section name: @@ -209,14 +209,14 @@ Call `AddAzureNpgsqlDbContext` with the `AnotherDbContext` type parameter to loa builder.AddAzureNpgsqlDbContext(); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Azure PostgreSQL EF Core client integration adds: - The [`DbContextHealthCheck`](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/src/HealthChecks.NpgSql/NpgSqlHealthCheck.cs), which calls EF Core's `CanConnectAsync` method. The name of the health check is the name of the `TContext` type. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Azure PostgreSQL EF Core client integration automatically configures logging, tracing, and metrics through OpenTelemetry. diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-connect.mdx index 5157c5b46..16b1b7c0d 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-connect.mdx @@ -73,13 +73,13 @@ Add the Aspire EF Core Azure SQL client integration to your C# consuming app to -#### Install the EF Core client integration +### Install the EF Core client integration Install the [📦 Aspire.Microsoft.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Aspire.Microsoft.EntityFrameworkCore.SqlServer) NuGet package in the client-consuming project: -#### Add SQL Server database context +### Add SQL Server database context In _Program.cs_, call `AddSqlServerDbContext` on your `IHostApplicationBuilder` to register a `Microsoft.EntityFrameworkCore.DbContext` for use via the dependency injection container. The method takes a connection name parameter: @@ -107,7 +107,7 @@ public class ExampleService(ExampleDbContext context) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -#### Enrich a SQL Server database context +### Enrich a SQL Server database context You may prefer to use the standard Entity Framework method to obtain a database context and add it to the dependency injection container: @@ -140,11 +140,11 @@ builder.EnrichSqlServerDbContext( The `settings` parameter is an instance of the `MicrosoftEntityFrameworkCoreSqlServerSettings` class. -#### Configuration +### Configuration The Aspire SQL Server Entity Framework Core integration provides multiple configuration approaches to meet the requirements and conventions of your project. -##### Use connection string +#### Use connection string When using a connection string from the `ConnectionStrings` configuration section, provide the name of the connection string when calling `AddSqlServerDbContext()`: @@ -166,7 +166,7 @@ The `EnrichSqlServerDbContext` won't make use of the `ConnectionStrings` configu For more information, see [ConnectionString](https://learn.microsoft.com/dotnet/api/system.data.sqlclient.sqlconnection.connectionstring#remarks). -##### Use configuration providers +#### Use configuration providers The Aspire SQL Server Entity Framework Core integration supports `Microsoft.Extensions.Configuration`. It loads `MicrosoftEntityFrameworkCoreSqlServerSettings` from _appsettings.json_ (or any other configuration source) by using the `Aspire:Microsoft:EntityFrameworkCore:SqlServer` key: @@ -188,7 +188,7 @@ The Aspire SQL Server Entity Framework Core integration supports `Microsoft.Exte } ``` -##### Use inline configurations +#### Use inline configurations Pass an `Action` delegate to set up options inline, for example to disable metrics: @@ -199,7 +199,7 @@ builder.AddSqlServerDbContext( settings.DisableMetrics = true); ``` -##### Configure multiple DbContext connections +#### Configure multiple DbContext connections If you want to register more than one `DbContext` with different configuration, use the `$"Aspire.Microsoft.EntityFrameworkCore.SqlServer:{typeof(TContext).Name}"` configuration section name: @@ -231,7 +231,7 @@ Then calling `AddSqlServerDbContext` with the `AnotherDbContext` type parameter builder.AddSqlServerDbContext("another-sql"); ``` -##### Configuration options +#### Configuration options Here are the configurable options with corresponding default values: @@ -245,18 +245,18 @@ Here are the configurable options with corresponding default values: | `DisableMetrics` | A boolean value that indicates whether the OpenTelemetry metrics are disabled or not. | | `Timeout` | The time in seconds to wait for the command to execute. | -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The SQL Server EF Core client integration adds: - The [`DbContextHealthCheck`](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/src/HealthChecks.NpgSql/NpgSqlHealthCheck.cs), which calls EF Core's `CanConnectAsync` method. The name of the health check is the name of the `TContext` type. - Integration with the `/health` HTTP endpoint, which specifies all registered health checks must pass for the app to be considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry Aspire integrations automatically set up Logging, Tracing, and Metrics configurations. -##### Logging +#### Logging The Aspire SQL Server Entity Framework Core integration uses the following log categories: @@ -271,13 +271,13 @@ The Aspire SQL Server Entity Framework Core integration uses the following log c - `Microsoft.EntityFrameworkCore.Query` - `Microsoft.EntityFrameworkCore.Update` -##### Tracing +#### Tracing The Aspire SQL Server Entity Framework Core integration emits the following tracing activities using OpenTelemetry: - `OpenTelemetry.Instrumentation.EntityFrameworkCore` -##### Metrics +#### Metrics The Aspire SQL Server Entity Framework Core integration emits the following metrics using OpenTelemetry: diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-connect.mdx index eddbb5b48..3d225a1d3 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-connect.mdx @@ -30,7 +30,7 @@ Add the Aspire MongoDB EF Core client integration to your C# consuming app to re -#### Add MongoDB database context +### Add MongoDB database context In the `Program.cs` file of your client-consuming project, call the `AddMongoDbContext` extension method on any `IHostApplicationBuilder` to register your `Microsoft.EntityFrameworkCore.DbContext` subclass for use via the dependency injection container. The method takes a connection name parameter, and optionally a database name. @@ -54,7 +54,7 @@ public class ExampleService(MyDbContext context) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -##### Specify database name +#### Specify database name MongoDB connection strings don't always include a database name, so you may need to provide one. The database name is resolved in the following order: @@ -70,7 +70,7 @@ builder.AddMongoDbContext("mongodb", "mydb"); When using `AddDatabase` in the AppHost, the database name is included in the generated connection string, so you typically don't need to specify it separately. -#### Enrich a MongoDB database context +### Enrich a MongoDB database context You may prefer to use the standard EF Core method to obtain a database context and add it to the dependency injection container: @@ -104,11 +104,11 @@ builder.EnrichMongoDbContext( The `settings` parameter is an instance of the `MongoDBEntityFrameworkCoreSettings` class. -#### Configuration +### Configuration The Aspire MongoDB EF Core integration provides multiple configuration approaches and options to meet the requirements and conventions of your project. -##### Use a connection string +#### Use a connection string When using a connection string from the `ConnectionStrings` configuration section, you provide the name of the connection string when calling the `AddMongoDbContext` method: @@ -136,7 +136,7 @@ The `EnrichMongoDbContext` won't make use of the `ConnectionStrings` configurati For more information, see the [MongoDB connection string documentation](https://www.mongodb.com/docs/v3.0/reference/connection-string/). -##### Use configuration providers +#### Use configuration providers The Aspire MongoDB EF Core integration supports `Microsoft.Extensions.Configuration`. It loads the `MongoDBEntityFrameworkCoreSettings` from configuration files such as `appsettings.json` by using the `Aspire:MongoDB:EntityFrameworkCore` key. If you have set up your configurations in the `Aspire:MongoDB:EntityFrameworkCore` section you can just call the method without passing any parameter. @@ -159,7 +159,7 @@ The following example shows an `appsettings.json` file that configures some of t For the complete MongoDB EF Core client integration JSON schema, see [Aspire.MongoDB.EntityFrameworkCore/ConfigurationSchema.json](https://github.com/microsoft/aspire/blob/main/src/Components/Aspire.MongoDB.EntityFrameworkCore/ConfigurationSchema.json). -##### Use inline delegates +#### Use inline delegates You can also pass the `Action` delegate to set up some or all the options inline, for example to disable health checks from code: @@ -177,7 +177,7 @@ builder.EnrichMongoDbContext( settings => settings.DisableHealthChecks = true); ``` -##### Configure multiple DbContext classes +#### Configure multiple DbContext classes If you want to register more than one `DbContext` with different configuration, you can use `$"Aspire:MongoDB:EntityFrameworkCore:{typeof(TContext).Name}"` configuration section name. The json configuration would look like: @@ -206,7 +206,7 @@ Then calling the `AddMongoDbContext` method with `AnotherDbContext` type paramet builder.AddMongoDbContext("mongodb"); ``` -#### MongoDB Driver integration vs. EF Core integration +### MongoDB Driver integration vs. EF Core integration The Aspire MongoDB integration comes in two flavors: @@ -215,14 +215,14 @@ The Aspire MongoDB integration comes in two flavors: Both integrations use the same hosting integration ([Aspire.Hosting.MongoDB](/integrations/databases/mongodb/mongodb-host/)) in the AppHost. -#### Health checks and observability +### Health checks and observability By default, the Aspire MongoDB EF Core integration handles the following: - Adds the `DbContextHealthCheck`, which calls EF Core's `CanConnectAsync` method. The name of the health check is the name of the `TContext` type. - Integrates with the `/health` HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic. -##### Logging +#### Logging The Aspire MongoDB Entity Framework Core integration uses the following log categories: @@ -237,13 +237,13 @@ The Aspire MongoDB Entity Framework Core integration uses the following log cate - `Microsoft.EntityFrameworkCore.Query` - `Microsoft.EntityFrameworkCore.Update` -##### Tracing +#### Tracing The Aspire MongoDB EF Core integration will emit the following tracing activities using OpenTelemetry: - `MongoDB.Driver.Core.Extensions.DiagnosticSources` -##### Metrics +#### Metrics The Aspire MongoDB EF Core integration will emit the following metrics using OpenTelemetry: diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-connect.mdx index 4f552bde7..0c44f52ef 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-connect.mdx @@ -29,7 +29,7 @@ Add the Aspire Pomelo MySQL EF Core client integration to your C# consuming app -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Aspire.Pomelo.EntityFrameworkCore.MySql) NuGet package in the client-consuming project: @@ -37,7 +37,7 @@ Install the [📦 Aspire.Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org For an introduction to the MySQL EF Core integration, see [Get started with the MySQL EF Core integration](/integrations/databases/efcore/mysql/mysql-get-started/). -#### Add MySQL database context +### Add MySQL database context In the `Program.cs` file of your client-consuming project, call the `AddMySqlDbContext` extension method on any `IHostApplicationBuilder` to register a `DbContext` for use via the dependency injection container. The method takes a connection name parameter. @@ -60,7 +60,7 @@ public class ExampleService(MyDbContext context) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -#### Enrich MySQL database context +### Enrich MySQL database context You may prefer to use the standard Entity Framework method to obtain a database context and add it to the dependency injection container: @@ -93,11 +93,11 @@ builder.EnrichMySqlDbContext( The `settings` parameter is an instance of the `MySqlEntityFrameworkCoreSettings` class. -#### Connection properties +### Connection properties When you use the `WithReference` method to pass a MySQL server or database resource from the AppHost project to a consuming project, Aspire exposes each property as an environment variable named `[RESOURCE]_[PROPERTY]`. For instance, the `ConnectionString` property of a resource called `mysqldb` becomes `MYSQLDB_CONNECTIONSTRING`. -##### MySQL server +#### MySQL server The MySQL server resource exposes the following connection properties: @@ -117,7 +117,7 @@ Username: root Password: ``` -##### MySQL database +#### MySQL database The MySQL database resource inherits all properties from its parent `MySqlServerResource` and adds: @@ -132,11 +132,11 @@ The MySQL database resource inherits all properties from its parent `MySqlServer Server=localhost;Port=3306;User ID=root;Password=;Database=mysqldb ``` -#### Configuration +### Configuration The Aspire MySQL Pomelo EF Core integration provides multiple configuration approaches and options to meet the requirements and conventions of your project. -##### Use a connection string +#### Use a connection string When using a connection string from the `ConnectionStrings` configuration section, you provide the name of the connection string when calling `builder.AddMySqlDbContext()`: @@ -156,7 +156,7 @@ The connection string is retrieved from the `ConnectionStrings` configuration se For more information on how to format this connection string, see [MySqlConnector: ConnectionString documentation](https://mysqlconnector.net/connection-options/). -##### Use configuration providers +#### Use configuration providers The Aspire MySQL EF Core integration supports `Microsoft.Extensions.Configuration` from configuration files such as `appsettings.json` by using the `Aspire:Pomelo:EntityFrameworkCore:MySql` key: @@ -176,7 +176,7 @@ The Aspire MySQL EF Core integration supports `Microsoft.Extensions.Configuratio } ``` -##### Use inline delegates +#### Use inline delegates You can also pass the `Action` delegate to set up some or all the options inline, for example to disable health checks from code: @@ -186,7 +186,7 @@ builder.AddMySqlDbContext( static settings => settings.DisableHealthChecks = true); ``` -##### Configuration options +#### Configuration options Here are the configurable options with corresponding default values: @@ -196,7 +196,7 @@ Here are the configurable options with corresponding default values: | `DisableHealthChecks` | A boolean value that indicates whether the database health check is disabled or not | | `DisableTracing` | A boolean value that indicates whether the OpenTelemetry tracing is disabled or not | -#### Health checks +### Health checks By default, Aspire integrations enable [health checks](/fundamentals/health-checks/) for all services. For more information, see [Aspire integrations overview](/integrations/overview/). @@ -205,11 +205,11 @@ The Aspire MySQL EF Core integration handles the following: - Adds the health check when `MySqlEntityFrameworkCoreSettings.DisableHealthChecks` is `false`, which verifies that a connection can be made and commands can be run against the MySQL database. - Integrates with the `/health` HTTP endpoint, which specifies all registered health checks must pass for the app to be considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry Aspire integrations automatically set up logging, tracing, and metrics configurations, which are sometimes known as *the pillars of observability*. Telemetry features can be disabled using the techniques presented in the [Configuration](#configuration) section. -##### Logging +#### Logging The Aspire MySQL EF Core client integration uses the following log categories: @@ -224,13 +224,13 @@ The Aspire MySQL EF Core client integration uses the following log categories: - `Microsoft.EntityFrameworkCore.Query` - `Microsoft.EntityFrameworkCore.Update` -##### Tracing +#### Tracing The Aspire MySQL EF Core client integration emits the following tracing activities using OpenTelemetry: - `MySqlConnector` -##### Metrics +#### Metrics The Aspire MySQL EF Core integration emits the following metrics using OpenTelemetry: diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-connect.mdx index 9eb6ed13a..d8cf911e1 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-connect.mdx @@ -69,13 +69,13 @@ Add the Aspire Oracle EF Core client integration to your C# consuming app to reg -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Oracle.EntityFrameworkCore](https://www.nuget.org/packages/Aspire.Oracle.EntityFrameworkCore) NuGet package in the client-consuming project: -#### Add Oracle database context +### Add Oracle database context In `Program.cs`, call `AddOracleDatabaseDbContext` on your `IHostApplicationBuilder` to register a `DbContext` for use via the dependency injection container: @@ -98,7 +98,7 @@ public class ExampleService(ExampleDbContext context) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -#### Enrich Oracle database context +### Enrich Oracle database context You may prefer to use the standard Entity Framework Core method to register a database context and then enhance it with Aspire features. Register the context first: @@ -131,11 +131,11 @@ builder.EnrichOracleDatabaseDbContext( The `settings` parameter is an instance of `OracleEntityFrameworkCoreSettings`. -#### Configuration +### Configuration The Aspire Oracle Entity Framework Core integration provides multiple configuration approaches to meet the requirements and conventions of your project. -##### Use a connection string +#### Use a connection string When using a connection string from the `ConnectionStrings` configuration section, pass the connection name to `AddOracleDatabaseDbContext`: @@ -157,7 +157,7 @@ The `EnrichOracleDatabaseDbContext` method won't use the `ConnectionStrings` con For more information, see the [ODP.NET documentation](https://www.oracle.com/database/technologies/appdev/dotnet/odp.html). -##### Use configuration providers +#### Use configuration providers The integration supports `Microsoft.Extensions.Configuration` from configuration files such as `appsettings.json` by using the `Aspire:Oracle:EntityFrameworkCore` key: @@ -180,7 +180,7 @@ The integration supports `Microsoft.Extensions.Configuration` from configuration The `CommandTimeout` property is in seconds. When set as shown in the preceding example, the timeout is 30 seconds. -##### Use inline delegates +#### Use inline delegates Pass an `Action` to configure settings inline, for example to disable health checks: @@ -197,7 +197,7 @@ builder.EnrichOracleDatabaseDbContext( static settings => settings.DisableHealthChecks = true); ``` -##### Configuration options +#### Configuration options Here are the configurable options with corresponding default values: @@ -209,7 +209,7 @@ Here are the configurable options with corresponding default values: | `DisableRetry` | A boolean value that indicates whether command retries should be disabled or not. | | `CommandTimeout` | The time in seconds to wait for the command to execute. | -#### Client integration health checks +### Client integration health checks By default, Aspire integrations enable [health checks](/fundamentals/health-checks/) for all services. For more information, see [Aspire integrations overview](/integrations/overview/). @@ -218,11 +218,11 @@ By default, the Aspire Oracle Entity Framework Core integration handles the foll - Checks if `OracleEntityFrameworkCoreSettings.DisableHealthChecks` is `true`. - If so, adds the `DbContextHealthCheck`, which calls EF Core's `CanConnectAsync` method. The name of the health check is the name of the `TContext` type. -#### Observability and telemetry +### Observability and telemetry Aspire integrations automatically set up logging, tracing, and metrics configurations, which are sometimes known as *the pillars of observability*. Telemetry features can be disabled using the techniques presented in the [Configuration](#configuration) section. -##### Logging +#### Logging The Aspire Oracle Entity Framework Core integration uses the following log categories: @@ -237,13 +237,13 @@ The Aspire Oracle Entity Framework Core integration uses the following log categ - `Microsoft.EntityFrameworkCore.Query` - `Microsoft.EntityFrameworkCore.Update` -##### Tracing +#### Tracing The Aspire Oracle Entity Framework Core integration emits the following tracing activities using OpenTelemetry: - `OpenTelemetry.Instrumentation.EntityFrameworkCore` -##### Metrics +#### Metrics The Aspire Oracle Entity Framework Core integration currently supports the following metrics: diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-connect.mdx index 88d08be3f..36f6d1ac3 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-connect.mdx @@ -50,13 +50,13 @@ EF Core is .NET-only. The steps below apply to any .NET consuming app that refer -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Npgsql.EntityFrameworkCore.PostgreSQL](https://www.nuget.org/packages/Aspire.Npgsql.EntityFrameworkCore.PostgreSQL) NuGet package in the client-consuming project: -#### Add the Npgsql DbContext +### Add the Npgsql DbContext In _Program.cs_, call `AddNpgsqlDbContext` on your `IHostApplicationBuilder` to register your `DbContext` subclass in the dependency injection container: @@ -77,7 +77,7 @@ public class ExampleService(YourDbContext context) } ``` -#### Add keyed DbContext instances +### Add keyed DbContext instances To register more than one `DbContext` targeting different databases, use the keyed services overload: @@ -97,7 +97,7 @@ public class ExampleService( } ``` -#### Enrich an existing DbContext +### Enrich an existing DbContext If you already register your `DbContext` using the standard EF Core approach, you can enhance it with Aspire-style retries, health checks, logging, and telemetry by calling `EnrichNpgsqlDbContext`: @@ -114,7 +114,7 @@ builder.EnrichNpgsqlDbContext( }); ``` -#### Configuration providers +### Configuration providers The client integration loads `NpgsqlEntityFrameworkCorePostgreSQLSettings` from configuration files such as _appsettings.json_ using the `Aspire:Npgsql:EntityFrameworkCore:PostgreSQL` key: @@ -165,11 +165,11 @@ builder.AddNpgsqlDbContext( static settings => settings.DisableHealthChecks = true); ``` -#### Health checks +### Health checks By default, the integration registers a [`DbContextHealthCheck`](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/src/HealthChecks.NpgSql/NpgSqlHealthCheck.cs) that calls EF Core's `CanConnectAsync` method. The health check name is the name of the `TContext` type. It integrates with the `/health` HTTP endpoint so all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The integration automatically configures logging, tracing, and metrics through OpenTelemetry. diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-connect.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-connect.mdx index ab6853bef..5a850e2a5 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-connect.mdx @@ -67,7 +67,7 @@ Add the Aspire EF Core SQL Server client integration to your C# consuming app to -#### Add SQL Server database context +### Add SQL Server database context In the `Program.cs` file of your client-consuming project, call the `AddSqlServerDbContext` extension method on any `IHostApplicationBuilder` to register a `Microsoft.EntityFrameworkCore.DbContext` for use via the dependency injection container. The method takes a connection name parameter. @@ -90,7 +90,7 @@ public class ExampleService(ExampleDbContext context) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -#### Enrich a SQL Server database context +### Enrich a SQL Server database context You may prefer to use the standard EF Core method to obtain a database context and add it to the dependency injection container: @@ -123,11 +123,11 @@ builder.EnrichSqlServerDbContext( The `settings` parameter is an instance of the `MicrosoftEntityFrameworkCoreSqlServerSettings` class. -#### Configuration +### Configuration The Aspire SQL Server Entity Framework Core integration provides multiple configuration approaches and options to meet the requirements and conventions of your project. -##### Use connection string +#### Use connection string When using a connection string from the `ConnectionStrings` configuration section, you provide the name of the connection string when calling `builder.AddSqlServerDbContext()`: @@ -149,7 +149,7 @@ The `EnrichSqlServerDbContext` won't make use of the `ConnectionStrings` configu For more information, see the [ConnectionString](https://learn.microsoft.com/dotnet/api/system.data.sqlclient.sqlconnection.connectionstring#remarks). -##### Use configuration providers +#### Use configuration providers The Aspire SQL Server EF Core integration supports [Microsoft.Extensions.Configuration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration). It loads the `MicrosoftEntityFrameworkCoreSqlServerSettings` from configuration files such as `appsettings.json` by using the `Aspire:Microsoft:EntityFrameworkCore:SqlServer` key. If you have set up your configurations in the `Aspire:Microsoft:EntityFrameworkCore:SqlServer` section you can just call the method without passing any parameter. @@ -173,7 +173,7 @@ The following is an example of an `appsettings.json` file that configures some o } ``` -##### Use inline configurations +#### Use inline configurations You can also pass the `Action` delegate to set up some or all the options inline, for example to turn off the metrics: @@ -184,7 +184,7 @@ builder.AddSqlServerDbContext( settings.DisableMetrics = true); ``` -##### Configure multiple DbContext connections +#### Configure multiple DbContext connections If you want to register more than one `DbContext` with different configuration, you can use `$"Aspire.Microsoft.EntityFrameworkCore.SqlServer:{typeof(TContext).Name}"` configuration section name. The json configuration would look like: @@ -216,7 +216,7 @@ Then calling the `AddSqlServerDbContext` method with `AnotherDbContext` type par builder.AddSqlServerDbContext("another-sql"); ``` -##### Configuration options +#### Configuration options Here are the configurable options with corresponding default values: @@ -230,16 +230,16 @@ Here are the configurable options with corresponding default values: | `DisableMetrics` | A boolean value that indicates whether the OpenTelemetry metrics are disabled or not. | | `Timeout` | The time in seconds to wait for the command to execute. | -#### Health checks +### Health checks By default, the Aspire SQL Server Entity Framework Core integration handles the following: - Adds the [`DbContextHealthCheck`](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/src/HealthChecks.SqlServer/SqlServerHealthCheck.cs), which calls EF Core's `CanConnectAsync` method. The name of the health check is the name of the `TContext` type. - Integrates with the `/health` HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic. -#### Observability +### Observability -##### Logging +#### Logging The Aspire SQL Server Entity Framework Core integration uses the following log categories: @@ -254,13 +254,13 @@ The Aspire SQL Server Entity Framework Core integration uses the following log c - `Microsoft.EntityFrameworkCore.Query` - `Microsoft.EntityFrameworkCore.Update` -##### Tracing +#### Tracing The Aspire SQL Server Entity Framework Core integration will emit the following tracing activities using OpenTelemetry: - `OpenTelemetry.Instrumentation.EntityFrameworkCore` -##### Metrics +#### Metrics The Aspire SQL Server Entity Framework Core integration will emit the following metrics using OpenTelemetry: diff --git a/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-connect.mdx b/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-connect.mdx index 2d212cf98..65af33f09 100644 --- a/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-connect.mdx @@ -69,13 +69,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Elasticsearch client integration. It registers an [`ElasticsearchClient`](https://github.com/elastic/elasticsearch-net) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Elastic.Clients.Elasticsearch](https://www.nuget.org/packages/Aspire.Elastic.Clients.Elasticsearch) NuGet package in the client-consuming project: -#### Add the Elasticsearch client +### Add the Elasticsearch client In _Program.cs_, call `AddElasticsearchClient` on your `IHostApplicationBuilder` to register an `ElasticsearchClient`: @@ -96,7 +96,7 @@ public class ExampleService(ElasticsearchClient client) } ``` -#### Add keyed Elasticsearch clients +### Add keyed Elasticsearch clients To register multiple `ElasticsearchClient` instances with different connection names, use `AddKeyedElasticsearchClient`: @@ -118,7 +118,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Elasticsearch client integration offers multiple ways to provide configuration. @@ -197,11 +197,11 @@ Or via configuration providers: } ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Elasticsearch client integration uses the configured client to perform a `PingAsync`. If the result is HTTP 200 OK, the health check is considered healthy; otherwise it's unhealthy. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Elasticsearch client integration automatically configures tracing through OpenTelemetry. @@ -211,7 +211,7 @@ The Aspire Elasticsearch client integration automatically configures tracing thr Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to the [📦 Elastic.Clients.Elasticsearch](https://www.nuget.org/packages/Elastic.Clients.Elasticsearch/) NuGet package directly: diff --git a/src/frontend/src/content/docs/integrations/databases/kurrentdb/kurrentdb-connect.mdx b/src/frontend/src/content/docs/integrations/databases/kurrentdb/kurrentdb-connect.mdx index d142fc122..a7cae39b9 100644 --- a/src/frontend/src/content/docs/integrations/databases/kurrentdb/kurrentdb-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/kurrentdb/kurrentdb-connect.mdx @@ -53,13 +53,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire KurrentDB client integration. It registers a [`KurrentDBClient`](https://github.com/kurrent-io/KurrentDB-Client-Dotnet) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.KurrentDB](https://nuget.org/packages/CommunityToolkit.Aspire.KurrentDB) NuGet package in the client-consuming project: -#### Add the KurrentDB client +### Add the KurrentDB client In _Program.cs_, call `AddKurrentDBClient` on your `IHostApplicationBuilder` to register a `KurrentDBClient`: @@ -80,7 +80,7 @@ public class ExampleService(KurrentDBClient client) } ``` -#### Add keyed KurrentDB clients +### Add keyed KurrentDB clients To register multiple `KurrentDBClient` instances with different connection names, use `AddKeyedKurrentDBClient`: @@ -102,7 +102,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire KurrentDB client integration offers multiple ways to provide configuration. @@ -146,11 +146,11 @@ builder.AddKurrentDBClient( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The KurrentDB client integration adds a health check that verifies the KurrentDB instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire KurrentDB client integration automatically configures logging and tracing through OpenTelemetry. @@ -164,7 +164,7 @@ The Aspire KurrentDB client integration automatically configures logging and tra Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to the [📦 KurrentDB.Client](https://www.nuget.org/packages/KurrentDB.Client/) NuGet package directly: diff --git a/src/frontend/src/content/docs/integrations/databases/meilisearch/meilisearch-connect.mdx b/src/frontend/src/content/docs/integrations/databases/meilisearch/meilisearch-connect.mdx index 1cfc6648f..82d14ec8f 100644 --- a/src/frontend/src/content/docs/integrations/databases/meilisearch/meilisearch-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/meilisearch/meilisearch-connect.mdx @@ -55,13 +55,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Meilisearch client integration. It registers a `MeilisearchClient` through dependency injection and adds health checks automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.Meilisearch](https://nuget.org/packages/CommunityToolkit.Aspire.Meilisearch) NuGet package in the client-consuming project: -#### Add the Meilisearch client +### Add the Meilisearch client In _Program.cs_, call `AddMeilisearchClient` on your `IHostApplicationBuilder` to register a `MeilisearchClient`: @@ -82,7 +82,7 @@ public class ExampleService(MeilisearchClient client) } ``` -#### Add keyed Meilisearch clients +### Add keyed Meilisearch clients To register multiple `MeilisearchClient` instances with different connection names, use `AddKeyedMeilisearchClient`: @@ -104,7 +104,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Meilisearch client integration offers multiple ways to provide configuration. @@ -139,11 +139,11 @@ The connection string is resolved from the `ConnectionStrings` section: } ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Meilisearch client integration adds a health check that verifies the Meilisearch instance is reachable and can respond to requests. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection properties from the environment and construct a `MeilisearchClient` directly using the [📦 MeiliSearch](https://www.nuget.org/packages/MeiliSearch/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/databases/milvus/milvus-connect.mdx b/src/frontend/src/content/docs/integrations/databases/milvus/milvus-connect.mdx index a0e5909c7..f4961cf0a 100644 --- a/src/frontend/src/content/docs/integrations/databases/milvus/milvus-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/milvus/milvus-connect.mdx @@ -61,7 +61,7 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Milvus client integration. It registers a [`MilvusClient`](https://github.com/milvus-io/milvus-sdk-csharp) through dependency injection and adds health checks automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Milvus.Client](https://www.nuget.org/packages/Aspire.Milvus.Client) NuGet package in the client-consuming project: @@ -69,7 +69,7 @@ Install the [📦 Aspire.Milvus.Client](https://www.nuget.org/packages/Aspire.Mi -#### Add the Milvus client +### Add the Milvus client In _Program.cs_, call `AddMilvusClient` on your `IHostApplicationBuilder` to register a `MilvusClient`: @@ -90,7 +90,7 @@ public class ExampleService(MilvusClient client) } ``` -#### Add keyed Milvus clients +### Add keyed Milvus clients To register multiple `MilvusClient` instances with different connection names, use `AddKeyedMilvusClient`: @@ -112,7 +112,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Milvus client integration offers multiple ways to provide configuration. @@ -157,7 +157,7 @@ builder.AddMilvusClient( static settings => settings.Key = "root:Non-default-P@ssw0rd"); ``` -#### Configuration options +### Configuration options The following options are available: @@ -168,11 +168,11 @@ The following options are available: | `Key` | The authentication key (format: `root:{password}`) | | `DisableHealthChecks` | Whether the health check is disabled | -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Milvus client integration adds a health check that verifies the Milvus server is reachable and a connection can be established. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Milvus client integration configures the following logging categories: @@ -180,7 +180,7 @@ The Aspire Milvus client integration configures the following logging categories The Milvus integration doesn't currently emit tracing activities or metrics because they are not supported by the underlying `Milvus.Client` library. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection properties from the environment and create a `MilvusClient` directly using the [📦 Milvus.Client](https://www.nuget.org/packages/Milvus.Client/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-connect.mdx b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-connect.mdx index 38b83dc44..ff11a1b0e 100644 --- a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-connect.mdx @@ -70,7 +70,7 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire MongoDB client integration. It registers an `IMongoClient` (and optionally an `IMongoDatabase`) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration The `Aspire.MongoDB.Driver` NuGet package depends on the `MongoDB.Driver` NuGet package. With the release of version 3.0.0 of `MongoDB.Driver`, a binary breaking change was introduced. @@ -89,7 +89,7 @@ or -#### Add the MongoDB client +### Add the MongoDB client In _Program.cs_, call `AddMongoDBClient` on your `IHostApplicationBuilder` to register an `IMongoClient`: @@ -119,7 +119,7 @@ public class ExampleService(IMongoDatabase database) } ``` -#### Add keyed MongoDB clients +### Add keyed MongoDB clients To register multiple `IMongoDatabase` instances with different connection names, use `AddKeyedMongoDBClient`: @@ -145,7 +145,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire MongoDB client integration offers multiple ways to provide configuration. @@ -236,14 +236,14 @@ builder.AddMongoDBClient( | `HealthCheckTimeout` | The MongoDB health check timeout in milliseconds (`int?`) | | `DisableTracing` | Whether OpenTelemetry tracing is disabled | -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The MongoDB client integration adds: - A health check that verifies that a connection can be made and commands can be run against the MongoDB database. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire MongoDB client integration automatically configures logging and tracing through OpenTelemetry. Metrics are not currently exposed. @@ -257,7 +257,7 @@ The Aspire MongoDB client integration automatically configures logging and traci **Metrics:** The Aspire MongoDB client integration doesn't currently expose any OpenTelemetry metrics. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to the [📦 MongoDB.Driver](https://www.nuget.org/packages/MongoDB.Driver/) NuGet package directly: diff --git a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-connect.mdx b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-connect.mdx index 9a34ac72f..fee48090b 100644 --- a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-connect.mdx @@ -76,13 +76,13 @@ For C# apps, the recommended approach is the Aspire MySQL client integration. It If you use Entity Framework Core (EF Core) to interact with MySQL, use the [Pomelo EF Core MySQL integration](/integrations/databases/efcore/mysql/mysql-get-started/) instead, which builds on top of the `Aspire.MySqlConnector` package. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.MySqlConnector](https://www.nuget.org/packages/Aspire.MySqlConnector) NuGet package in the client-consuming project: -#### Add the MySQL data source +### Add the MySQL data source In _Program.cs_, call `AddMySqlDataSource` on your `IHostApplicationBuilder` to register a `MySqlDataSource`: @@ -103,7 +103,7 @@ public class ExampleService(MySqlDataSource dataSource) } ``` -#### Add keyed MySQL data sources +### Add keyed MySQL data sources To register multiple `MySqlDataSource` instances with different connection names, use `AddKeyedMySqlDataSource`: @@ -125,7 +125,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire MySQL client integration offers multiple ways to provide configuration. @@ -172,14 +172,14 @@ builder.AddMySqlDataSource( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The MySQL client integration adds: - A health check that verifies a connection can be made and commands can be executed against the MySQL database. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire MySQL client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -209,7 +209,7 @@ The Aspire MySQL client integration automatically configures logging, tracing, a Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and connect using the [📦 MySqlConnector](https://www.nuget.org/packages/MySqlConnector/) NuGet package directly: diff --git a/src/frontend/src/content/docs/integrations/databases/postgres/postgres-connect.mdx b/src/frontend/src/content/docs/integrations/databases/postgres/postgres-connect.mdx index 7db186b0f..40151ba5e 100644 --- a/src/frontend/src/content/docs/integrations/databases/postgres/postgres-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/postgres/postgres-connect.mdx @@ -72,13 +72,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire PostgreSQL client integration. It registers an [`NpgsqlDataSource`](https://www.npgsql.org/doc/api/Npgsql.NpgsqlDataSource.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Npgsql](https://www.nuget.org/packages/Aspire.Npgsql) NuGet package in the client-consuming project: -#### Add the Npgsql data source +### Add the Npgsql data source In _Program.cs_, call `AddNpgsqlDataSource` on your `IHostApplicationBuilder` to register an `NpgsqlDataSource`: @@ -99,7 +99,7 @@ public class ExampleService(NpgsqlDataSource dataSource) } ``` -#### Add keyed Npgsql clients +### Add keyed Npgsql clients To register multiple `NpgsqlDataSource` instances with different connection names, use `AddKeyedNpgsqlDataSource`: @@ -119,7 +119,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire PostgreSQL client integration offers multiple ways to provide configuration. @@ -166,14 +166,14 @@ builder.AddNpgsqlDataSource( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The PostgreSQL client integration adds: - The [`NpgSqlHealthCheck`](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/src/HealthChecks.NpgSql/NpgSqlHealthCheck.cs), which verifies that commands can be successfully executed against the underlying PostgreSQL database. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire PostgreSQL client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -205,7 +205,7 @@ The Aspire PostgreSQL client integration automatically configures logging, traci Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it to the [📦 Npgsql](https://www.nuget.org/packages/Npgsql/) NuGet package to create an `NpgsqlDataSource` and open a connection: diff --git a/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-connect.mdx b/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-connect.mdx index 420968d65..bf43da741 100644 --- a/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-connect.mdx @@ -54,13 +54,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Qdrant client integration. It registers a [`QdrantClient`](https://github.com/qdrant/qdrant-dotnet/) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Qdrant.Client](https://www.nuget.org/packages/Aspire.Qdrant.Client) NuGet package in the client-consuming project: -#### Add the Qdrant client +### Add the Qdrant client In _Program.cs_, call `AddQdrantClient` on your `IHostApplicationBuilder` to register a `QdrantClient`: @@ -81,7 +81,7 @@ public class ExampleService(QdrantClient client) } ``` -#### Add keyed Qdrant clients +### Add keyed Qdrant clients To register multiple `QdrantClient` instances with different connection names, use `AddKeyedQdrantClient`: @@ -103,7 +103,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire Qdrant client integration offers multiple ways to provide configuration. @@ -148,11 +148,11 @@ builder.AddQdrantClient( settings => settings.Key = "your-api-key"); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Qdrant client integration adds a health check that verifies the Qdrant server is reachable. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Qdrant client integration automatically configures logging through OpenTelemetry. @@ -162,7 +162,7 @@ The Aspire Qdrant client integration automatically configures logging through Op The Qdrant integration doesn't currently emit tracing activities or metrics because they aren't supported by the `Qdrant.Client` library. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI and API key from the environment and create a `QdrantClient` directly using the [📦 Qdrant.Client](https://www.nuget.org/packages/Qdrant.Client/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/databases/ravendb/ravendb-connect.mdx b/src/frontend/src/content/docs/integrations/databases/ravendb/ravendb-connect.mdx index 7e3f2b629..5d6994152 100644 --- a/src/frontend/src/content/docs/integrations/databases/ravendb/ravendb-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/ravendb/ravendb-connect.mdx @@ -68,7 +68,7 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire RavenDB client integration. It registers an [`IDocumentStore`](https://ravendb.net/docs/article-page/6.2/csharp/client-api/what-is-a-document-store) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.RavenDB.Client](https://nuget.org/packages/CommunityToolkit.Aspire.RavenDB.Client) NuGet package in the client-consuming project: @@ -76,7 +76,7 @@ Install the [📦 CommunityToolkit.Aspire.RavenDB.Client](https://nuget.org/pack The RavenDB client integration registers an `IDocumentStore` instance, which serves as the entry point for interacting with the RavenDB server. If your AppHost includes RavenDB database resources, the associated `IDocumentSession` and `IAsyncDocumentSession` instances are also registered for dependency injection. -#### Add the RavenDB client +### Add the RavenDB client In _Program.cs_, call `AddRavenDBClient` on your `IHostApplicationBuilder` to register an `IDocumentStore`: @@ -97,7 +97,7 @@ public class ExampleService(IDocumentStore store) } ``` -#### Add RavenDB client using settings +### Add RavenDB client using settings The `AddRavenDBClient` method provides overloads that accept a `RavenDBClientSettings` object for connecting to an existing RavenDB instance without relying on the hosting integration: @@ -112,7 +112,7 @@ var settings = new RavenDBClientSettings builder.AddRavenDBClient(settings: settings); ``` -#### Add keyed RavenDB clients +### Add keyed RavenDB clients To register multiple `IDocumentStore` instances with different connection configurations, use `AddKeyedRavenDBClient`: @@ -132,7 +132,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire RavenDB client integration offers multiple ways to provide configuration. @@ -183,11 +183,11 @@ builder.AddRavenDBClient( }); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The RavenDB client integration adds a health check that verifies the RavenDB server or database is reachable. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected URI from the environment and connect directly using the [`RavenDB.Client`](https://www.nuget.org/packages/RavenDB.Client/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-connect.mdx b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-connect.mdx index 336f6ec47..ddcc97b52 100644 --- a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-connect.mdx @@ -72,13 +72,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire SQL Server client integration. It registers a [`SqlConnection`](https://learn.microsoft.com/dotnet/api/microsoft.data.sqlclient.sqlconnection) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Microsoft.Data.SqlClient](https://www.nuget.org/packages/Aspire.Microsoft.Data.SqlClient) NuGet package in the client-consuming project: -#### Add the SQL Server client +### Add the SQL Server client In _Program.cs_, call `AddSqlServerClient` on your `IHostApplicationBuilder` to register a `SqlConnection`: @@ -101,7 +101,7 @@ public class ExampleService(SqlConnection connection) For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). -#### Add keyed SQL Server clients +### Add keyed SQL Server clients To register multiple `SqlConnection` instances with different connection names, use `AddKeyedSqlServerClient`: @@ -123,7 +123,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire SQL Server client integration offers multiple ways to provide configuration. @@ -173,14 +173,14 @@ builder.AddSqlServerClient( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The SQL Server client integration adds: - A health check that attempts to connect to the SQL Server instance and execute a command. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire SQL Server client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -211,7 +211,7 @@ The Aspire SQL Server client integration automatically configures logging, traci Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and open a connection using [📦 Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/): diff --git a/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-connect.mdx b/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-connect.mdx index a527c5112..d8384a082 100644 --- a/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-connect.mdx @@ -50,13 +50,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire SQLite client integration (from the [Aspire Community Toolkit](https://github.com/CommunityToolkit/Aspire)). It registers a [`SqliteConnection`](https://learn.microsoft.com/dotnet/api/microsoft.data.sqlite.sqliteconnection) through dependency injection and adds health checks and telemetry automatically. If you'd rather read the environment variable directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.Microsoft.Data.Sqlite](https://www.nuget.org/packages/CommunityToolkit.Aspire.Microsoft.Data.Sqlite) NuGet package in the client-consuming project: -#### Add the SQLite connection +### Add the SQLite connection In _Program.cs_, call `AddSqliteConnection` on your `IHostApplicationBuilder` to register a `SqliteConnection`: @@ -77,7 +77,7 @@ public class ExampleService(SqliteConnection connection) } ``` -#### Add keyed SQLite connections +### Add keyed SQLite connections To register multiple `SqliteConnection` instances with different connection names, use `AddKeyedSqliteConnection`: @@ -101,7 +101,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire SQLite client integration offers multiple ways to provide configuration. @@ -146,14 +146,14 @@ builder.AddSqliteConnection( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The SQLite client integration adds: - A health check that attempts to open a connection to the database file when `SqliteConnectionSettings.DisableHealthChecks` is `false`. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire SQLite client integration automatically configures logging, tracing, and metrics through OpenTelemetry. Because SQLite is an embedded database engine, telemetry support is more limited than server-based databases. @@ -165,7 +165,7 @@ The Aspire SQLite client integration automatically configures logging, tracing, Any of these telemetry features can be disabled through the [configuration options](#configuration) above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected data source path from the environment and open a connection directly: diff --git a/src/frontend/src/content/docs/integrations/databases/surrealdb/surrealdb-connect.mdx b/src/frontend/src/content/docs/integrations/databases/surrealdb/surrealdb-connect.mdx index c5c32ad48..3ce9d602b 100644 --- a/src/frontend/src/content/docs/integrations/databases/surrealdb/surrealdb-connect.mdx +++ b/src/frontend/src/content/docs/integrations/databases/surrealdb/surrealdb-connect.mdx @@ -58,13 +58,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire SurrealDB client integration. It registers a [`SurrealDbClient`](https://github.com/surrealdb/surrealdb.net) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.SurrealDb](https://nuget.org/packages/CommunityToolkit.Aspire.SurrealDb) NuGet package in the client-consuming project: -#### Add the SurrealDB client +### Add the SurrealDB client In _Program.cs_, call `AddSurrealClient` on your `IHostApplicationBuilder` to register a `SurrealDbClient`: @@ -85,7 +85,7 @@ public class ExampleService(SurrealDbClient client) } ``` -#### Add keyed SurrealDB clients +### Add keyed SurrealDB clients To register multiple `SurrealDbClient` instances with different connection names, use `AddKeyedSurrealClient`: @@ -107,7 +107,7 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire SurrealDB client integration offers multiple ways to provide configuration. @@ -150,11 +150,11 @@ builder.AddSurrealClient( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The SurrealDB client integration adds a health check that verifies the SurrealDB instance is reachable and can execute queries. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection string from the environment and use the [📦 SurrealDb.Net](https://www.nuget.org/packages/SurrealDb.Net/) NuGet package to construct a client directly: diff --git a/src/frontend/src/content/docs/integrations/devtools/flagd/flagd-connect.mdx b/src/frontend/src/content/docs/integrations/devtools/flagd/flagd-connect.mdx index 05529a58f..327034aed 100644 --- a/src/frontend/src/content/docs/integrations/devtools/flagd/flagd-connect.mdx +++ b/src/frontend/src/content/docs/integrations/devtools/flagd/flagd-connect.mdx @@ -91,7 +91,7 @@ var backgroundColor = await flagClient.GetStringValueAsync( defaultValue: "#000000"); ``` -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer to read the connection URI from environment variables directly rather than through `IConfiguration`: diff --git a/src/frontend/src/content/docs/integrations/devtools/goff/goff-connect.mdx b/src/frontend/src/content/docs/integrations/devtools/goff/goff-connect.mdx index d81647283..da4b9aee0 100644 --- a/src/frontend/src/content/docs/integrations/devtools/goff/goff-connect.mdx +++ b/src/frontend/src/content/docs/integrations/devtools/goff/goff-connect.mdx @@ -55,13 +55,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire GO Feature Flag client integration. It registers a [`GOFeatureFlagProvider`](https://github.com/open-feature/dotnet-sdk-contrib/tree/main/src/OpenFeature.Providers.GOFeatureFlag) through dependency injection and adds health checks automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 CommunityToolkit.Aspire.GoFeatureFlag](https://www.nuget.org/packages/CommunityToolkit.Aspire.GoFeatureFlag) NuGet package in the client-consuming project: -#### Add the GO Feature Flag client +### Add the GO Feature Flag client In _Program.cs_, call `AddGoFeatureFlagClient` on your `IHostApplicationBuilder` to register a `GOFeatureFlagProvider`: @@ -86,7 +86,7 @@ public class ExampleService(GOFeatureFlagProvider provider) } ``` -#### Add keyed GO Feature Flag clients +### Add keyed GO Feature Flag clients To register multiple `GOFeatureFlagProvider` instances with different connection names, use `AddKeyedGoFeatureFlagClient`: @@ -110,7 +110,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire GO Feature Flag client integration offers multiple ways to provide configuration. @@ -154,11 +154,11 @@ builder.AddGoFeatureFlagClient( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The GO Feature Flag client integration adds a health check that calls the relay proxy `/health` endpoint to verify it is reachable. The health check is wired into the `/health` HTTP endpoint of your app, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected URI from the environment and configure the OpenFeature `GOFeatureFlagProvider` directly: @@ -254,7 +254,7 @@ client = api.get_client("my-app") -#### Node.js (server-side) +### Node.js (server-side) Install the [OpenFeature server SDK](https://github.com/open-feature/js-sdk) and the [GO Feature Flag Node.js provider](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/go-feature-flag): @@ -278,7 +278,7 @@ const client = OpenFeature.getClient(); // Use client to evaluate feature flags... ``` -#### Browser (web) +### Browser (web) For browser-based apps, install the [OpenFeature web SDK](https://github.com/open-feature/js-sdk) and the [GO Feature Flag web provider](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/go-feature-flag-web): diff --git a/src/frontend/src/content/docs/integrations/devtools/mailpit/mailpit-connect.mdx b/src/frontend/src/content/docs/integrations/devtools/mailpit/mailpit-connect.mdx index 4916063e9..4c98a7de7 100644 --- a/src/frontend/src/content/docs/integrations/devtools/mailpit/mailpit-connect.mdx +++ b/src/frontend/src/content/docs/integrations/devtools/mailpit/mailpit-connect.mdx @@ -57,7 +57,7 @@ Pick the language your consuming app is written in. Each example assumes your Ap The toolkit's tested C# pattern reads the Aspire connection string and passes its `Endpoint` value to `System.Net.Mail.SmtpClient`. -#### Read the SMTP connection string +### Read the SMTP connection string ```csharp title="Program.cs" using System.Data.Common; @@ -77,7 +77,7 @@ var smtpEndpoint = new Uri( UriKind.Absolute); ``` -#### Send an email +### Send an email ```csharp title="Program.cs" using var client = new SmtpClient(smtpEndpoint.Host, smtpEndpoint.Port); @@ -90,7 +90,7 @@ using var message = new MailMessage( await client.SendMailAsync(message); ``` -#### Register as a service +### Register as a service Register an SMTP client factory when multiple services need to send email: diff --git a/src/frontend/src/content/docs/integrations/messaging/apache-kafka/apache-kafka-connect.mdx b/src/frontend/src/content/docs/integrations/messaging/apache-kafka/apache-kafka-connect.mdx index 67a7e3bfb..e6553956c 100644 --- a/src/frontend/src/content/docs/integrations/messaging/apache-kafka/apache-kafka-connect.mdx +++ b/src/frontend/src/content/docs/integrations/messaging/apache-kafka/apache-kafka-connect.mdx @@ -52,13 +52,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire Confluent Kafka client integration. It registers an [`IProducer`](https://docs.confluent.io/platform/current/clients/confluent-kafka-dotnet/_site/api/Confluent.Kafka.IProducer-2.html) and/or [`IConsumer`](https://docs.confluent.io/platform/current/clients/confluent-kafka-dotnet/_site/api/Confluent.Kafka.IConsumer-2.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, use the `ConnectionStrings` section value as the bootstrap server address. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Confluent.Kafka](https://www.nuget.org/packages/Aspire.Confluent.Kafka) NuGet package in the client-consuming project: -#### Add a Kafka producer +### Add a Kafka producer In _Program.cs_, call `AddKafkaProducer` on your `IHostApplicationBuilder` to register an `IProducer`: @@ -79,7 +79,7 @@ public class ExampleService(IProducer producer) } ``` -#### Add a Kafka consumer +### Add a Kafka consumer Call `AddKafkaConsumer` to register an `IConsumer`: @@ -100,7 +100,7 @@ public class ExampleService(IConsumer consumer) } ``` -#### Add keyed Kafka producers or consumers +### Add keyed Kafka producers or consumers To register multiple producer or consumer instances with different connection names, use the keyed variants: @@ -120,7 +120,7 @@ public class ExampleService( } ``` -#### Configuration +### Configuration The Aspire Confluent Kafka client integration offers multiple ways to provide configuration. @@ -209,7 +209,7 @@ builder.AddKafkaProducer( }); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The Confluent Kafka client integration adds: @@ -217,7 +217,7 @@ Aspire client integrations enable health checks by default. The Confluent Kafka - The `Aspire.Confluent.Kafka.Consumer` health check when `DisableHealthChecks` is `false`. - Integration with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire Confluent Kafka client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -238,7 +238,7 @@ The Aspire Confluent Kafka client integration automatically configures logging, - `messaging.receive.messages` - `messaging.kafka.message.received` -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected bootstrap server address from the environment and pass it directly to `Confluent.Kafka`: diff --git a/src/frontend/src/content/docs/integrations/messaging/nats/nats-connect.mdx b/src/frontend/src/content/docs/integrations/messaging/nats/nats-connect.mdx index 7b185f34e..795cf8efb 100644 --- a/src/frontend/src/content/docs/integrations/messaging/nats/nats-connect.mdx +++ b/src/frontend/src/content/docs/integrations/messaging/nats/nats-connect.mdx @@ -51,13 +51,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire NATS client integration. It registers an [`INatsConnection`](https://nats-io.github.io/nats.net.v2/api/NATS.Client.Core.INatsConnection.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.NATS.Net](https://www.nuget.org/packages/Aspire.NATS.Net) NuGet package in the client-consuming project: -#### Add the NATS client +### Add the NATS client In _Program.cs_, call `AddNatsClient` on your `IHostApplicationBuilder` to register an `INatsConnection`: @@ -78,7 +78,7 @@ public class ExampleService(INatsConnection connection) } ``` -#### Add keyed NATS clients +### Add keyed NATS clients To register multiple `INatsConnection` instances with different connection names, use `AddKeyedNatsClient`: @@ -100,7 +100,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire NATS client integration offers multiple ways to provide configuration. @@ -146,11 +146,11 @@ builder.AddNatsClient( static settings => settings.DisableHealthChecks = true); ``` -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The NATS client integration adds a health check that verifies the NATS instance is reachable and can execute commands. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire NATS client integration automatically configures tracing through OpenTelemetry. @@ -163,7 +163,7 @@ For more information about tracing activities, see [NATS .NET client library: Op Any of these telemetry features can be disabled through the configuration options above. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it directly to the [📦 NATS.Net](https://www.nuget.org/packages/NATS.Net/) NuGet package: diff --git a/src/frontend/src/content/docs/integrations/messaging/rabbitmq/rabbitmq-connect.mdx b/src/frontend/src/content/docs/integrations/messaging/rabbitmq/rabbitmq-connect.mdx index 7cf49f605..ad83f1c09 100644 --- a/src/frontend/src/content/docs/integrations/messaging/rabbitmq/rabbitmq-connect.mdx +++ b/src/frontend/src/content/docs/integrations/messaging/rabbitmq/rabbitmq-connect.mdx @@ -80,7 +80,7 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the Aspire RabbitMQ client integration. It registers an [`IConnection`](https://rabbitmq.github.io/rabbitmq-dotnet-client/api/RabbitMQ.Client.IConnection.html) through dependency injection and adds health checks and telemetry automatically. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.RabbitMQ.Client](https://www.nuget.org/packages/Aspire.RabbitMQ.Client) NuGet package in the client-consuming project: @@ -96,7 +96,7 @@ Install the [📦 Aspire.RabbitMQ.Client](https://www.nuget.org/packages/Aspire. 7.x](https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/main/v7-MIGRATION.md). -#### Add the RabbitMQ client +### Add the RabbitMQ client In _Program.cs_, call `AddRabbitMQClient` on your `IHostApplicationBuilder` to register an `IConnection`: @@ -119,7 +119,7 @@ public class ExampleService(IConnection connection) } ``` -#### Add keyed RabbitMQ clients +### Add keyed RabbitMQ clients To register multiple `IConnection` instances with different connection names, use `AddKeyedRabbitMQClient`: @@ -141,7 +141,7 @@ public class ExampleService( For more information, see [.NET dependency injection: Keyed services](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection#keyed-services). -#### Configuration +### Configuration The Aspire RabbitMQ client integration offers multiple ways to provide configuration. @@ -199,7 +199,7 @@ builder.AddRabbitMQClient( static factory => factory.ClientProvidedName = "MyApp"); ``` -#### Auto activation +### Auto activation Auto activation opens the RabbitMQ connection during startup rather than lazily on first use, ensuring that any connectivity issues are detected early. @@ -215,14 +215,14 @@ builder.AddRabbitMQClient("messaging", o => o.DisableAutoActivation = false); explicitly to keep the lazy initialization behavior. -#### Client integration health checks +### Client integration health checks Aspire client integrations enable health checks by default. The RabbitMQ client integration: - Adds a health check that attempts to connect to and create a channel on the RabbitMQ server when `DisableHealthChecks` is `false`. - Integrates with the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry The Aspire RabbitMQ client integration automatically configures logging, tracing, and metrics through OpenTelemetry. @@ -236,7 +236,7 @@ The Aspire RabbitMQ client integration automatically configures logging, tracing **Metrics**: The RabbitMQ client integration doesn't currently support metrics by default. -#### Use MassTransit +### Use MassTransit @@ -272,7 +272,7 @@ public sealed class OrderSubmittedConsumer : IConsumer The optional `configureOptions` delegate configures `MassTransitRabbitMqSettings`; set `DisableTelemetry` to `true` only when you don't want the integration to register its OpenTelemetry instrumentation. Use `AddMassTransitRabbitMq` for an additional MassTransit bus type. -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected connection URI from the environment and pass it directly to the [📦 RabbitMQ.Client](https://www.nuget.org/packages/RabbitMQ.Client/) library: diff --git a/src/frontend/src/content/docs/integrations/observability/seq/seq-connect.mdx b/src/frontend/src/content/docs/integrations/observability/seq/seq-connect.mdx index 50bd80419..1bd43db33 100644 --- a/src/frontend/src/content/docs/integrations/observability/seq/seq-connect.mdx +++ b/src/frontend/src/content/docs/integrations/observability/seq/seq-connect.mdx @@ -50,13 +50,13 @@ Pick the language your consuming app is written in. Each example assumes your Ap For C# apps, the recommended approach is the `Aspire.Seq` client integration. It registers OpenTelemetry Protocol (OTLP) exporters through dependency injection so that logs and traces are automatically forwarded to Seq. If you'd rather read environment variables directly, see the [Read environment variables](#read-environment-variables-in-c) section at the end of this tab. -#### Install the client integration +### Install the client integration Install the [📦 Aspire.Seq](https://www.nuget.org/packages/Aspire.Seq) NuGet package in the client-consuming project: -#### Register the Seq endpoint +### Register the Seq endpoint In _Program.cs_, call `AddSeqEndpoint` on your `IHostApplicationBuilder` to register OTLP exporters that send logs and traces to Seq: @@ -68,7 +68,7 @@ builder.AddSeqEndpoint(connectionName: "seq"); The `connectionName` must match the Seq resource name from the AppHost. For more information, see [Add Seq resource](../seq-host/#add-seq-resource). -#### Configuration +### Configuration The `Aspire.Seq` client integration offers multiple ways to provide configuration. @@ -121,11 +121,11 @@ builder.AddSeqEndpoint("seq", static settings => }); ``` -#### Client integration health checks +### Client integration health checks By default, Aspire client integrations enable health checks. The `Aspire.Seq` integration adds a health check that attempts to connect to the Seq server's `/health` endpoint when `DisableHealthChecks` is `false`. The health check is wired into the `/health` HTTP endpoint, where all registered health checks must pass before the app is considered ready to accept traffic. -#### Observability and telemetry +### Observability and telemetry Because Seq is a telemetry **sink**, the `Aspire.Seq` integration does not emit tracing activities or metrics of its own. It configures the following log category: @@ -133,7 +133,7 @@ Because Seq is a telemetry **sink**, the `Aspire.Seq` integration does not emit - `Seq` -#### Read environment variables in C\# +### Read environment variables in C\# If you prefer not to use the Aspire client integration, you can read the Aspire-injected URI directly from the environment and configure the OpenTelemetry OTLP exporter manually: diff --git a/src/frontend/src/content/docs/testing/manage-app-host.mdx b/src/frontend/src/content/docs/testing/manage-app-host.mdx index e43a5c9cc..7a9e9798d 100644 --- a/src/frontend/src/content/docs/testing/manage-app-host.mdx +++ b/src/frontend/src/content/docs/testing/manage-app-host.mdx @@ -22,7 +22,7 @@ When writing functional or integration tests with Aspire, managing the [AppHost] For writing tests with Aspire, you use the [Aspire.Hosting.Testing](https://www.nuget.org/packages/Aspire.Hosting.Testing) NuGet package which contains some helper classes to manage the AppHost instance in your tests. -### Use the `DistributedApplicationTestingBuilder` class +## Use the `DistributedApplicationTestingBuilder` class In the [tutorial on writing your first test](/testing/write-your-first-test/), you were introduced to the `DistributedApplicationTestingBuilder` class which can be used to create the AppHost instance: @@ -125,7 +125,7 @@ public class WebTests By capturing the AppHost in a field when the test run is started, you can access it in each test without the need to recreate it, decreasing the time it takes to run the tests. Then, when the test run completes, the AppHost is disposed, which cleans up any resources that were created during the test run, such as containers. -### Pass arguments to your AppHost +## Pass arguments to your AppHost You can access the arguments from your AppHost with the `args` parameter. Arguments are also passed to [.NET's configuration system](https://learn.microsoft.com/dotnet/core/extensions/configuration), so you can override many configuration settings this way. In the following example, you override the [environment](https://learn.microsoft.com/aspnet/core/fundamentals/environments) by specifying it as a command line option: @@ -168,7 +168,7 @@ public async Task DisableVolumesFromTest() } ``` -### Use the `DistributedApplicationFactory` class +## Use the `DistributedApplicationFactory` class While the `DistributedApplicationTestingBuilder` class is useful for many scenarios, there might be situations where you want more control over starting the AppHost, such as executing code before the builder is created or after the AppHost is built. In these cases, you implement your own version of the `DistributedApplicationFactory` class. This is what the `DistributedApplicationTestingBuilder` uses internally. @@ -182,7 +182,7 @@ public class TestingAspireAppHost() The constructor requires the type of the AppHost project reference as a parameter. Optionally, you can provide arguments to the underlying host application builder. These arguments control how the AppHost starts and provide values to the args variable used by the _AppHost.cs_ file to start the AppHost instance. -### Lifecycle methods +## Lifecycle methods The `DistributionApplicationFactory` class provides several lifecycle methods that can be overridden to provide custom behavior throughout the preparation and creation of the AppHost. The available methods are `OnBuilderCreating`, `OnBuilderCreated`, `OnBuilding`, and `OnBuilt`. diff --git a/src/frontend/src/content/docs/whats-new/aspire-13-3.mdx b/src/frontend/src/content/docs/whats-new/aspire-13-3.mdx index d0df288e7..3efe625eb 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-13-3.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-13-3.mdx @@ -1250,7 +1250,7 @@ Aspire is built in the open, and this release wouldn't be what it is without you | `dotnet new aspire-py-starter` removed | Use `aspire new aspire-py-starter` from the Aspire CLI. | | TypeScript AppHost per-kind `withEnvironment*` helper methods removed | Replace every per-kind helper call with the unified `withEnvironment(name, value)` API. | -#### In-dashboard GitHub Copilot UI replaced by agentic development +### In-dashboard GitHub Copilot UI replaced by agentic development
diff --git a/src/frontend/src/content/docs/whats-new/aspire-13-4.mdx b/src/frontend/src/content/docs/whats-new/aspire-13-4.mdx index e7c798eca..673dbc91b 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-13-4.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-13-4.mdx @@ -768,13 +768,13 @@ After migrating, `aspire run` behaves exactly the same as before — the CLI now Aspire 13.4 includes several breaking changes. Most are small renames or configuration moves, but a few affect deployment and the non-C# AppHost SDK layout. Review the subsections that apply to your app before upgrading. -#### `aspire exec` command removed +### `aspire exec` command removed The experimental `aspire exec` command — along with its AppHost backchannel and feature flag — has been removed. Remove scripts or workflows that call `aspire exec`. For resource-specific actions, use [`aspire resource`](/reference/cli/commands/aspire-resource/) when the resource exposes a command. -#### Generated TypeScript modules consolidated under `.aspire/modules/` +### Generated TypeScript modules consolidated under `.aspire/modules/` Generated non-C# SDK modules now live under a single `.aspire/modules/` directory instead of being split across `.modules/` and `.aspire/`. Generated language references — TypeScript imports, Go replace directives, Python editable paths, Java source lists, and Rust module paths — are updated automatically to point at the new location. @@ -785,55 +785,55 @@ Re-run `aspire run` (or your code-generation step) to regenerate references, and layout for compatibility; new projects use `.aspire/modules/`. -#### Persistent executable and project lifetimes +### Persistent executable and project lifetimes Support for persistent lifetimes on executables and projects updates the underlying DCP executable model (new `persistent`, `start`, and `stop` fields). Persistent executables and projects default to proxyless endpoints, require concrete ports for executables, don't support replicas, and aren't compatible with Aspire IDE debugging sessions. Persistent containers use proxied endpoints by default, matching session container behavior, so integrations that depend on endpoint allocation before startup work correctly without changes. If you adopt `WithPersistentLifetime()`, review endpoint and port configuration. Tooling pinned to the previous DCP executable schema may need to be updated. See [Configure resource lifetimes](/app-host/resource-lifetimes/). -#### Kubernetes `Ingress` `WithRoute(...)` renamed to `WithPath(...)` +### Kubernetes `Ingress` `WithRoute(...)` renamed to `WithPath(...)` The Kubernetes `Ingress` routing API has been renamed from `WithRoute(...)` to `WithPath(...)` to match Kubernetes Ingress path-rule terminology and disambiguate it from the Gateway API. The shared `IngressPathType` enum is also split into `KubernetesIngressPathType` (Ingress) and `KubernetesGatewayPathType` (Gateway API). Update `ingress.WithRoute(...)` calls to `ingress.WithPath(...)`, and switch any `IngressPathType` references to the appropriate split enum. The Gateway API `gateway.WithRoute(...)` is unchanged. -#### Kubernetes ingress and gateway routes require external endpoints +### Kubernetes ingress and gateway routes require external endpoints Routing a non-external endpoint through a Kubernetes ingress or gateway now throws an `InvalidOperationException` at publish time instead of generating routes that can't resolve. Call `WithExternalHttpEndpoints()` (or otherwise mark the endpoint external) on any resource whose endpoint you route through an ingress or gateway. -#### Kubernetes Helm configuration consolidated on `WithHelm(...)` +### Kubernetes Helm configuration consolidated on `WithHelm(...)` Helm chart name, version, description, release name, and namespace are now configured through the `WithHelm(...)` extension method, replacing the parallel property-based configuration surface on `KubernetesEnvironmentResource`. Move property assignments into the `WithHelm(...)` builder. See the [Kubernetes integration](/integrations/compute/kubernetes/#configure-helm-chart-options). -#### Azure Front Door uses Azure.Provisioning name generation +### Azure Front Door uses Azure.Provisioning name generation Azure Front Door CDN resources now use Azure.Provisioning's built-in name-generation algorithm instead of Aspire's custom logic. Upgrading an existing deployment can produce duplicate endpoint, origin group, or route names. Remove and re-add the affected resource, or set its `Name` explicitly with `ConfigureInfrastructure`, to avoid conflicts. -#### Foundry hosted agents: `WithComputeEnvironment` and `AddPromptAgent` +### Foundry hosted agents: `WithComputeEnvironment` and `AddPromptAgent` The Azure AI Foundry hosted-agent API has been aligned with the rest of the app model: `PublishAsHostedAgent` is renamed to `WithComputeEnvironment`, `AddPromptAgent` now takes the resource name as its first parameter (before the model), and the preview-only `AsHostedAgent` / `RunAsHostedAgent` methods were removed. Update hosted-agent registrations to call `WithComputeEnvironment` and pass the resource name first to `AddPromptAgent`. -#### `PublishAsNpmPackageScript` renamed to `PublishAsPackageScript` +### `PublishAsNpmPackageScript` renamed to `PublishAsPackageScript` The npm-specific publish helper has been generalized to support npm, pnpm, Yarn, and Bun. `PublishAsNpmPackageScript` is renamed to `PublishAsPackageScript`, and its `startScriptName` parameter is renamed to `scriptName`. Rename call sites from `PublishAsNpmPackageScript(...)` to `PublishAsPackageScript(...)` and update the parameter name. -#### Keycloak exposes an HTTPS primary endpoint +### Keycloak exposes an HTTPS primary endpoint The primary Keycloak endpoint is now HTTPS when the developer certificate is enabled, which fixes token invalidation on restart. Update references that assumed an HTTP primary endpoint to use the HTTPS endpoint. -#### PostgreSQL default image bumped to 18.3, breaking existing data volumes +### PostgreSQL default image bumped to 18.3, breaking existing data volumes The default PostgreSQL container image used by `AddPostgres` moved from 17.6 to 18.3. PostgreSQL 18 changed the on-disk data layout: the official `postgres` image now stores cluster files under a major-version-specific subdirectory of `/var/lib/postgresql` (for example, `/var/lib/postgresql/18/docker`), whereas PostgreSQL 17 and earlier stored data directly in `/var/lib/postgresql/data`. @@ -855,7 +855,7 @@ You have two ways to recover: For full guidance and the container path mapping, see [PostgreSQL 18 data directory change](/integrations/databases/postgres/postgres-host/#postgresql-18-data-directory-change). -#### Behavior changes to audit +### Behavior changes to audit - `aspire update` now requires `--yes` in non-interactive mode, matching `aspire destroy`. - Resource command arguments are named options in the CLI instead of positional values. @@ -865,7 +865,7 @@ For full guidance and the container path mapping, see [PostgreSQL 18 data direct - The default PostgreSQL container image moved from 17.6 to 18.3, which changes the on-disk data layout and breaks PostgreSQL 17 data persisted with `WithDataVolume()` or `WithDataBindMount()`. - `AddNatsClient` now also registers `INatsClient` and a default serializer registry; user-provided registries still take precedence. -#### Migration from Aspire 13.3 to 13.4 +### Migration from Aspire 13.3 to 13.4 diff --git a/src/frontend/src/content/docs/whats-new/aspire-9-3.mdx b/src/frontend/src/content/docs/whats-new/aspire-9-3.mdx index 7bf94d104..1c7f35117 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-9-3.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-9-3.mdx @@ -492,7 +492,7 @@ dotnet tool install --global aspire.cli --prerelease You must upgrade your project to Aspire 9.3+ in order to use the latest CLI features. -#### 🔍 Smarter AppHost discovery +### 🔍 Smarter AppHost discovery The CLI now **walks upward** from your current directory, **recursively searching each level** for the AppHost project. Once located, it caches the result in a `.aspire` folder to speed up future commands. @@ -505,7 +505,7 @@ cd src/frontend aspire run ``` -#### ⏳ Health-aware dashboard launch +### ⏳ Health-aware dashboard launch The CLI now **waits for the dashboard to become responsive** before printing its URL to the terminal. This ensures the link works immediately when opened—no more blank pages or retry loops. diff --git a/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx b/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx index 747610136..59e99f12b 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx @@ -208,7 +208,7 @@ internal static class DataSeedJobBuilderExtensions This custom deployment logic executes as follows from the `aspire deploy` command. -![aspire-deploy-whats-new](https://github.com/user-attachments/assets/15c6730d-8154-496a-be70-c67257ce5523) +![Terminal output showing the aspire deploy command running the custom deployment steps in sequence](https://github.com/user-attachments/assets/15c6730d-8154-496a-be70-c67257ce5523) Now, integration owners can create sophisticated `aspire deploy` workflows. This work also provides a foundation for advanced deployment automation scenarios. diff --git a/src/frontend/src/styles/api-reference.css b/src/frontend/src/styles/api-reference.css index 28f4a5f05..701388257 100644 --- a/src/frontend/src/styles/api-reference.css +++ b/src/frontend/src/styles/api-reference.css @@ -9,16 +9,16 @@ /* ----------------------------- Tokens ----------------------------- */ :root { /* Radius – three levels matching the site (CapabilityGrid, FeatureShowcase) */ - --api-radius-lg: 0.75rem; /* cards, containers, hero blocks */ - --api-radius-md: 0.5rem; /* code blocks, interactive elements */ - --api-radius-sm: 0.25rem; /* inline badges, small chips */ + --api-radius-lg: 0.75rem; /* cards, containers, hero blocks */ + --api-radius-md: 0.5rem; /* code blocks, interactive elements */ + --api-radius-sm: 0.25rem; /* inline badges, small chips */ /* Font scale – bumped for readability */ - --api-text-xs: 0.75rem; /* labels, tiny badges */ - --api-text-sm: 0.875rem; /* secondary text, descriptions */ - --api-text-base: 1rem; /* body text */ - --api-text-md: 1.05rem; /* member names, key text */ - --api-text-lg: 1.125rem; /* summaries */ + --api-text-xs: 0.75rem; /* labels, tiny badges */ + --api-text-sm: 0.875rem; /* secondary text, descriptions */ + --api-text-base: 1rem; /* body text */ + --api-text-md: 1.05rem; /* member names, key text */ + --api-text-lg: 1.125rem; /* summaries */ /* WCAG AA contrast-safe accent for text on dark surfaces. --sl-color-accent (#7455dd) only reaches 2.28:1 on gray-5 (#35383e). @@ -36,10 +36,10 @@ --api-kind-record-struct: #0a7d56; /* Parameter type colors — faded, themed hues assigned by type name hash */ - --api-param-type-0: hsl(300, 45%, 72%); /* soft magenta */ - --api-param-type-1: hsl(185, 50%, 65%); /* soft cyan */ - --api-param-type-2: hsl(35, 60%, 68%); /* soft amber */ - --api-param-type-3: hsl(145, 40%, 65%); /* soft green */ + --api-param-type-0: hsl(300, 45%, 72%); /* soft magenta */ + --api-param-type-1: hsl(185, 50%, 65%); /* soft cyan */ + --api-param-type-2: hsl(35, 60%, 68%); /* soft amber */ + --api-param-type-3: hsl(145, 40%, 65%); /* soft green */ /* Surfaces – using the same color-mix pattern as FeatureShowcase/CapabilityGrid */ --api-surface: color-mix(in srgb, var(--sl-color-gray-6) 50%, transparent); @@ -137,13 +137,27 @@ color: #fff; background: var(--api-kind-class); } -.api-kind-pill.kind-handle { background: var(--api-kind-class); } -.api-kind-pill.kind-interface { background: var(--api-kind-interface); } -.api-kind-pill.kind-enum { background: var(--api-kind-enum); } -.api-kind-pill.kind-struct { background: var(--api-kind-struct); } -.api-kind-pill.kind-record { background: var(--api-kind-record); } -.api-kind-pill.kind-delegate { background: var(--api-kind-delegate); } -.api-kind-pill.kind-record-struct { background: var(--api-kind-record-struct); } +.api-kind-pill.kind-handle { + background: var(--api-kind-class); +} +.api-kind-pill.kind-interface { + background: var(--api-kind-interface); +} +.api-kind-pill.kind-enum { + background: var(--api-kind-enum); +} +.api-kind-pill.kind-struct { + background: var(--api-kind-struct); +} +.api-kind-pill.kind-record { + background: var(--api-kind-record); +} +.api-kind-pill.kind-delegate { + background: var(--api-kind-delegate); +} +.api-kind-pill.kind-record-struct { + background: var(--api-kind-record-struct); +} /* Modifier badge (static, abstract, sealed…) */ .api-mod-badge { @@ -194,7 +208,11 @@ .api-count-badge { font-size: 0.65em; font-weight: 700; - background: color-mix(in srgb, var(--kind-tint, var(--sl-color-accent)) 18%, var(--sl-color-gray-5)); + background: color-mix( + in srgb, + var(--kind-tint, var(--sl-color-accent)) 18%, + var(--sl-color-gray-5) + ); color: var(--kind-tint, var(--api-accent-text)); padding: 0.15em 0.55em; border-radius: var(--api-radius-sm); @@ -443,10 +461,18 @@ a.api-chip:hover { font-size: inherit; color: inherit !important; } -.mcb .mc-param-type-0 { color: var(--api-param-type-0) !important; } -.mcb .mc-param-type-1 { color: var(--api-param-type-1) !important; } -.mcb .mc-param-type-2 { color: var(--api-param-type-2) !important; } -.mcb .mc-param-type-3 { color: var(--api-param-type-3) !important; } +.mcb .mc-param-type-0 { + color: var(--api-param-type-0) !important; +} +.mcb .mc-param-type-1 { + color: var(--api-param-type-1) !important; +} +.mcb .mc-param-type-2 { + color: var(--api-param-type-2) !important; +} +.mcb .mc-param-type-3 { + color: var(--api-param-type-3) !important; +} .mcb .mc-param-desc { font-size: var(--api-text-sm); color: var(--sl-color-gray-2); @@ -539,9 +565,15 @@ a.api-chip:hover { border-left: 3px solid var(--kind-tint, var(--api-border)); border-radius: 0 var(--api-radius-md) var(--api-radius-md) 0; } -.api-remarks p { margin: 0.5rem 0; } -.api-remarks p:first-child { margin-top: 0; } -.api-remarks p:last-child { margin-bottom: 0; } +.api-remarks p { + margin: 0.5rem 0; +} +.api-remarks p:first-child { + margin-top: 0; +} +.api-remarks p:last-child { + margin-bottom: 0; +} /* ----------------------------- Grid layouts ----------------------------- */ .api-kv-grid { @@ -744,7 +776,10 @@ a.api-chip:hover { border: 1px solid transparent; border-radius: 6px; text-decoration: none; - transition: border-color 0.15s, color 0.15s, background 0.15s; + transition: + border-color 0.15s, + color 0.15s, + background 0.15s; white-space: nowrap; } .api-source-link:hover { @@ -768,10 +803,10 @@ a.api-chip:hover { --api-kind-class: #5a3bb8; --api-kind-interface: #5a30b0; --api-kind-enum: #7d5200; - --api-kind-struct: #0a7d56; + --api-kind-struct: #065c3f; --api-kind-record: #035e6e; --api-kind-delegate: #9a2d55; - --api-kind-record-struct: #0a7d56; + --api-kind-record-struct: #065c3f; /* Section labels (Parameters, Remarks…) — #736e81 gives 4.91:1 on white */ --api-section-label-color: #736e81; @@ -779,7 +814,7 @@ a.api-chip:hover { /* Parameter type colors — darkened for light backgrounds */ --api-param-type-0: hsl(300, 50%, 40%); --api-param-type-1: hsl(185, 60%, 32%); - --api-param-type-2: hsl(35, 65%, 38%); + --api-param-type-2: hsl(35, 65%, 30%); --api-param-type-3: hsl(145, 50%, 30%); } From 61fe0a921ac72989b451d15aae7f009f2fcdd513 Mon Sep 17 00:00:00 2001 From: "aspire-repo-bot[bot]" <268009190+aspire-repo-bot[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2026 12:50:31 +0000 Subject: [PATCH 09/29] chore: Update integration data and GitHub stats (9/9/26) (#1640) * chore: Update integration data and GitHub stats (9/9/26) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix: keep integration documentation mappings synchronized Remove the stale Bun mapping, reconcile catalog-managed mappings during updates, and stage documentation-map changes in automated PRs. Validate structured data without Astro-generated asset side effects. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: aspire-repo-bot[bot] Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: David Pine --- .agents/skills/update-integrations/SKILL.md | 6 +- .github/workflows/update-integration-data.yml | 1 + src/frontend/package.json | 2 +- .../scripts/update-integration-data.ps1 | 11 +- src/frontend/scripts/update-integrations.ts | 31 ++ .../src/data/aspire-integrations.json | 391 +++++++++--------- src/frontend/src/data/github-stats.json | 4 +- src/frontend/src/data/integration-docs.json | 4 - ...nityToolkit.Aspire.Hosting.Bun.13.5.0.json | 390 ----------------- ...nityToolkit.Aspire.Hosting.Bun.13.5.0.json | 107 ----- src/frontend/src/data/twoslash/aspire.d.ts | 15 - .../unit/update-integrations.vitest.test.ts | 89 +++- src/frontend/vitest.structured-data.config.ts | 22 + 13 files changed, 346 insertions(+), 727 deletions(-) delete mode 100644 src/frontend/src/data/pkgs/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json delete mode 100644 src/frontend/src/data/ts-modules/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json create mode 100644 src/frontend/vitest.structured-data.config.ts diff --git a/.agents/skills/update-integrations/SKILL.md b/.agents/skills/update-integrations/SKILL.md index 30367c4e7..199eae2f8 100644 --- a/.agents/skills/update-integrations/SKILL.md +++ b/.agents/skills/update-integrations/SKILL.md @@ -11,6 +11,8 @@ This skill synchronizes the integration package catalog with documentation URL m ## Overview +The automated flow also reconciles documentation mappings and runs `pnpm test:unit:structured-data` before API regeneration or PR creation. This uses a data-only Vitest configuration so validation does not rewrite Astro's generated assets. Mapping changes are included in the generated PR. + The aspire.dev site maintains three key data locations: - **`src/frontend/src/data/aspire-integrations.json`** — Package metadata fetched from the configured package feeds (titles, descriptions, icons, versions, download counts). @@ -61,6 +63,8 @@ pnpm --dir ./src/frontend update:integrations This writes updated package metadata to `src/frontend/src/data/aspire-integrations.json`. The script queries the NuGet v3 API for packages matching `owner:aspire`, `Aspire.Hosting.`, and `CommunityToolkit.Aspire`, then filters out deprecated, unlisted, and excluded packages. +It also removes documentation mappings for Aspire and Community Toolkit packages absent from the updated catalog. Manually curated third-party mappings are preserved, and new documentation URLs still require manual resolution. + On `release/*` branches, the script queries the branch-specific official Aspire feed for `Aspire.*` packages and continues to query nuget.org for `CommunityToolkit.Aspire.*` packages. ### 2. Read the updated package data @@ -76,7 +80,7 @@ Load `src/frontend/src/data/integration-docs.json` and reconcile it with the pac - If an entry exists, verify the `href` is correct - If no entry exists, determine the appropriate documentation URL -- **Remove stale entries** from `integration-docs.json` that reference packages no longer in `aspire-integrations.json` +- **Remove stale entries** for catalog-managed Aspire and Community Toolkit packages no longer in `aspire-integrations.json`. Preserve mappings for third-party packages outside the catalog's sources. - **Preserve existing correct mappings** — do not change entries that are already accurate diff --git a/.github/workflows/update-integration-data.yml b/.github/workflows/update-integration-data.yml index f32a4782a..f5a34ea6a 100644 --- a/.github/workflows/update-integration-data.yml +++ b/.github/workflows/update-integration-data.yml @@ -124,6 +124,7 @@ jobs: # source, manifests, or docs. Directories with no changes are no-ops. git add -- \ src/frontend/src/data/aspire-integrations.json \ + src/frontend/src/data/integration-docs.json \ src/frontend/src/data/github-stats.json \ src/frontend/src/data/samples.json \ src/frontend/src/assets/samples \ diff --git a/src/frontend/package.json b/src/frontend/package.json index 9ea5b84b9..56fa69aed 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -39,7 +39,7 @@ "test:unit:contracts": "vitest run --config vitest.config.ts tests/unit/analytics-script-contracts.vitest.test.ts tests/unit/redirects.vitest.test.ts", "test:unit:components": "vitest run --config vitest.config.ts tests/unit/custom-components.vitest.test.ts tests/unit/site-tour.vitest.test.ts", "test:unit:docs": "vitest run --config vitest.config.ts tests/unit/filetree-format.vitest.test.ts", - "test:unit:structured-data": "vitest run --config vitest.config.ts tests/unit/structured-data.vitest.test.ts tests/unit/update-integrations.vitest.test.ts", + "test:unit:structured-data": "vitest run --config vitest.structured-data.config.ts", "test:unit:cli-config-schema": "vitest run --config vitest.config.ts tests/unit/cli-config-schema.vitest.test.ts", "test:unit:llms-small-whitespace": "vitest run --config vitest.config.ts tests/unit/llms-small-whitespace.vitest.test.ts", "test:unit:llms-txt": "vitest run --config vitest.config.ts tests/unit/llms-txt-twoslash.vitest.test.ts", diff --git a/src/frontend/scripts/update-integration-data.ps1 b/src/frontend/scripts/update-integration-data.ps1 index fa196d361..bfa1e6870 100644 --- a/src/frontend/scripts/update-integration-data.ps1 +++ b/src/frontend/scripts/update-integration-data.ps1 @@ -11,6 +11,7 @@ Phases: 1. `pnpm update:all` — integration metadata, GitHub stats, sample metadata. + Reconciles documentation mappings, then runs structured-data tests. 2. Version-change detection — compares the committed aspire-integrations.json against the freshly written one by package title -> version. Metadata-only changes (icons, descriptions, download @@ -27,7 +28,7 @@ Exit codes: 0 success (whether or not there were changes) - 1 a required phase failed (update:all, TS API regen, out-of-scope diff). + 1 a required phase failed (data update/validation, TS API regen, out-of-scope diff). The caller must NOT open a PR on a non-zero exit. Packages without a public API surface are reported as explicit skips. Any @@ -71,6 +72,7 @@ $PkgGenScript = Join-Path $RepoRoot 'src' 'tools' 'PackageJsonGenerator' 'genera # this set appearing in `git status` is treated as a scope violation. $AllowedPaths = @( 'src/frontend/src/data/aspire-integrations.json', + 'src/frontend/src/data/integration-docs.json', 'src/frontend/src/data/github-stats.json', 'src/frontend/src/data/samples.json', 'src/frontend/src/assets/samples/', @@ -261,6 +263,12 @@ try { Write-Error "pnpm update:all failed (exit $LASTEXITCODE). Aborting; no PR will be opened." exit 1 } + + & pnpm run test:unit:structured-data + if ($LASTEXITCODE -ne 0) { + Write-Error "Structured-data validation failed (exit $LASTEXITCODE). Aborting; no PR will be opened." + exit 1 + } } finally { Pop-Location @@ -559,6 +567,7 @@ $sb = [System.Text.StringBuilder]::new() [void]$sb.AppendLine("") [void]$sb.AppendLine("### What's updated") [void]$sb.AppendLine("- ``src/frontend/src/data/aspire-integrations.json`` — latest package information") +[void]$sb.AppendLine("- ``src/frontend/src/data/integration-docs.json`` — documentation mappings, when packages are removed") [void]$sb.AppendLine("- ``src/frontend/src/data/github-stats.json`` — repository statistics") [void]$sb.AppendLine("- ``src/frontend/src/data/samples.json`` — sample metadata, when changed") [void]$sb.AppendLine("- ``src/frontend/src/assets/samples/`` — sample thumbnails, when changed") diff --git a/src/frontend/scripts/update-integrations.ts b/src/frontend/scripts/update-integrations.ts index 056e1b1a0..f524a8812 100644 --- a/src/frontend/scripts/update-integrations.ts +++ b/src/frontend/scripts/update-integrations.ts @@ -28,6 +28,7 @@ const EXCLUDED_PACKAGES = [ 'CommunityToolkit.Aspire.EventStore', ]; const OUTPUT_PATH = './src/data/aspire-integrations.json'; +const DOCS_OUTPUT_PATH = './src/data/integration-docs.json'; export const DEFAULT_NUGET_ICON_URL = 'https://www.nuget.org/Content/gallery/img/default-package-icon.svg'; @@ -112,6 +113,11 @@ export interface IntegrationOutput { version?: string; } +interface IntegrationDoc { + match: string; + href: string; +} + type PrereleaseIdentifier = { n: number } | { s: string }; interface ParsedSemVer { @@ -270,6 +276,22 @@ export function getOfficialAspireDefaultIconPackages(output: IntegrationOutput[] .map((pkg) => `${pkg.title}@${pkg.version ?? 'unknown'}`); } +export function reconcileIntegrationDocs( + docs: IntegrationDoc[], + integrations: Pick[] +): IntegrationDoc[] { + const catalogPackages = new Set(integrations.map(({ title }) => title.toLowerCase())); + + return docs.filter(({ match }) => { + const packageId = match.toLowerCase(); + // Other publishers are curated manually, outside this updater's package sources. + if (!isOfficialAspirePackage(packageId) && !packageId.startsWith('communitytoolkit.aspire')) { + return true; + } + return catalogPackages.has(packageId); + }); +} + function filterAndTransform(pkgs: PackageRecord[]): IntegrationOutput[] { const excludedLower = EXCLUDED_PACKAGES.map((pkg) => pkg.toLowerCase()); @@ -732,8 +754,17 @@ export async function updateIntegrations(): Promise { `⚠️ Official Aspire packages resolved to the default NuGet icon: ${defaultIconPackages.join(', ')}` ); } + const docs = JSON.parse(fs.readFileSync(DOCS_OUTPUT_PATH, 'utf8')) as IntegrationDoc[]; + const reconciledDocs = reconcileIntegrationDocs(docs, output); + fs.writeFileSync(OUTPUT_PATH, JSON.stringify(output, null, 2)); console.log(`✅ Saved ${output.length} packages to ${OUTPUT_PATH}`); + if (reconciledDocs.length !== docs.length) { + fs.writeFileSync(DOCS_OUTPUT_PATH, `${JSON.stringify(reconciledDocs, null, 2)}\n`); + console.log( + `Removed ${docs.length - reconciledDocs.length} stale documentation mapping(s) from ${DOCS_OUTPUT_PATH}` + ); + } } const isMainModule = process.argv[1] diff --git a/src/frontend/src/data/aspire-integrations.json b/src/frontend/src/data/aspire-integrations.json index 9ea0513d1..2963f63ef 100644 --- a/src/frontend/src/data/aspire-integrations.json +++ b/src/frontend/src/data/aspire-integrations.json @@ -15,7 +15,7 @@ "inference", "ai-search" ], - "downloads": 136927, + "downloads": 137982, "version": "13.5.3-preview.1.26425.3" }, { @@ -33,7 +33,7 @@ "ai", "openai" ], - "downloads": 798095, + "downloads": 800525, "version": "13.5.3-preview.1.26425.3" }, { @@ -52,7 +52,7 @@ "table", "storage" ], - "downloads": 3953565, + "downloads": 3958134, "version": "13.5.3" }, { @@ -72,7 +72,7 @@ "messaging", "eventing" ], - "downloads": 743098, + "downloads": 746425, "version": "13.5.3" }, { @@ -92,7 +92,7 @@ "messaging", "eventing" ], - "downloads": 1840814, + "downloads": 1849912, "version": "13.5.3" }, { @@ -112,7 +112,7 @@ "pubsub", "messaging" ], - "downloads": 69889, + "downloads": 70115, "version": "13.5.3" }, { @@ -134,7 +134,7 @@ "database", "data" ], - "downloads": 154437, + "downloads": 155838, "version": "13.5.3" }, { @@ -161,7 +161,7 @@ "npgsql", "sql" ], - "downloads": 409567, + "downloads": 412380, "version": "13.5.3" }, { @@ -180,7 +180,7 @@ "ai", "ai-search" ], - "downloads": 450955, + "downloads": 452569, "version": "13.5.3" }, { @@ -199,7 +199,7 @@ "secrets", "security" ], - "downloads": 1600804, + "downloads": 1607529, "version": "13.5.3" }, { @@ -218,7 +218,7 @@ "blobs", "blob" ], - "downloads": 6905368, + "downloads": 6927679, "version": "13.5.3" }, { @@ -237,7 +237,7 @@ "files", "datalake" ], - "downloads": 5449, + "downloads": 5483, "version": "13.5.3-preview.1.26425.3" }, { @@ -257,7 +257,7 @@ "queues", "messaging" ], - "downloads": 1869770, + "downloads": 1874032, "version": "13.5.3" }, { @@ -275,7 +275,7 @@ "messaging", "eventing" ], - "downloads": 2651181, + "downloads": 2653124, "version": "13.5.3" }, { @@ -291,7 +291,7 @@ "cloud", "elasticsearch" ], - "downloads": 78063, + "downloads": 78216, "version": "13.3.0" }, { @@ -305,7 +305,7 @@ "orchestration", "polyglot" ], - "downloads": 35596036, + "downloads": 35787689, "version": "13.5.3" }, { @@ -322,7 +322,7 @@ "ai", "agents" ], - "downloads": 4129, + "downloads": 4166, "version": "1.20.0-preview.260831.1" }, { @@ -336,7 +336,7 @@ "hosting", "aws" ], - "downloads": 783560, + "downloads": 786885, "version": "13.7.2" }, { @@ -353,7 +353,7 @@ "orchestration", "polyglot" ], - "downloads": 8983929, + "downloads": 9037440, "version": "13.5.3" }, { @@ -370,7 +370,7 @@ "cloud", "polyglot" ], - "downloads": 594414, + "downloads": 597818, "version": "13.5.3" }, { @@ -388,7 +388,7 @@ "appcontainers", "polyglot" ], - "downloads": 1238133, + "downloads": 1245260, "version": "13.5.3" }, { @@ -407,7 +407,7 @@ "applicationinsights", "polyglot" ], - "downloads": 970263, + "downloads": 974813, "version": "13.5.3" }, { @@ -424,7 +424,7 @@ "appservice", "polyglot" ], - "downloads": 89668, + "downloads": 90326, "version": "13.5.3" }, { @@ -445,7 +445,7 @@ "cloud", "polyglot" ], - "downloads": 832635, + "downloads": 835357, "version": "13.5.3" }, { @@ -463,7 +463,7 @@ "cloud", "polyglot" ], - "downloads": 930219, + "downloads": 937777, "version": "13.5.3" }, { @@ -483,7 +483,7 @@ "nosql", "polyglot" ], - "downloads": 1600927, + "downloads": 1611140, "version": "13.5.3" }, { @@ -502,7 +502,7 @@ "cloud", "polyglot" ], - "downloads": 636369, + "downloads": 642418, "version": "13.5.3" }, { @@ -520,7 +520,7 @@ "cloud", "polyglot" ], - "downloads": 10265, + "downloads": 10333, "version": "13.5.3-preview.1.26425.3" }, { @@ -538,7 +538,7 @@ "cloud", "polyglot" ], - "downloads": 1742516, + "downloads": 1755004, "version": "13.5.3" }, { @@ -557,7 +557,7 @@ "cloud", "polyglot" ], - "downloads": 3322540, + "downloads": 3343255, "version": "13.5.3" }, { @@ -574,7 +574,7 @@ "aks", "polyglot" ], - "downloads": 2756, + "downloads": 2834, "version": "13.5.3-preview.1.26425.3" }, { @@ -593,7 +593,7 @@ "cloud", "polyglot" ], - "downloads": 9626, + "downloads": 9696, "version": "13.5.3-preview.1.26425.3" }, { @@ -615,7 +615,7 @@ "cloud", "polyglot" ], - "downloads": 419447, + "downloads": 425574, "version": "13.5.3" }, { @@ -633,7 +633,7 @@ "cloud", "polyglot" ], - "downloads": 1630754, + "downloads": 1639339, "version": "13.5.3" }, { @@ -652,7 +652,7 @@ "cloud", "polyglot" ], - "downloads": 808865, + "downloads": 813543, "version": "13.5.3" }, { @@ -671,7 +671,7 @@ "cloud", "polyglot" ], - "downloads": 626049, + "downloads": 628555, "version": "13.5.3" }, { @@ -690,7 +690,7 @@ "cloud", "polyglot" ], - "downloads": 308296, + "downloads": 309651, "version": "13.5.3" }, { @@ -709,7 +709,7 @@ "cloud", "polyglot" ], - "downloads": 2451164, + "downloads": 2470957, "version": "13.5.3" }, { @@ -727,7 +727,7 @@ "cloud", "polyglot" ], - "downloads": 328955, + "downloads": 331355, "version": "13.5.3" }, { @@ -746,7 +746,7 @@ "cloud", "polyglot" ], - "downloads": 944024, + "downloads": 950322, "version": "13.5.3" }, { @@ -766,7 +766,7 @@ "cloud", "polyglot" ], - "downloads": 6270875, + "downloads": 6312661, "version": "13.5.3" }, { @@ -786,7 +786,7 @@ "cloud", "polyglot" ], - "downloads": 38834, + "downloads": 38911, "version": "13.5.3" }, { @@ -803,7 +803,7 @@ "gateway", "polyglot" ], - "downloads": 4365, + "downloads": 4432, "version": "13.5.3-preview.1.26425.3" }, { @@ -821,7 +821,7 @@ "diagnostics", "polyglot" ], - "downloads": 158980, + "downloads": 160240, "version": "13.5.3-preview.1.26425.3" }, { @@ -837,7 +837,7 @@ "database", "data" ], - "downloads": 27882, + "downloads": 28364, "version": "13.5.3" }, { @@ -846,7 +846,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.go/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Go", "tags": [], - "downloads": 9961, + "downloads": 10127, "version": "13.5.3" }, { @@ -855,7 +855,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.java/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Java", "tags": [], - "downloads": 2833, + "downloads": 2836, "version": "13.5.3" }, { @@ -864,7 +864,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.python/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Python", "tags": [], - "downloads": 2785, + "downloads": 2787, "version": "13.5.3" }, { @@ -873,7 +873,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.rust/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Rust", "tags": [], - "downloads": 2727, + "downloads": 2730, "version": "13.5.3" }, { @@ -882,7 +882,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.typescript/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.TypeScript", "tags": [], - "downloads": 65802, + "downloads": 66257, "version": "13.5.3" }, { @@ -896,7 +896,7 @@ "devtunnels", "polyglot" ], - "downloads": 525885, + "downloads": 529892, "version": "13.5.3" }, { @@ -911,7 +911,7 @@ "docker-compose", "polyglot" ], - "downloads": 694151, + "downloads": 698706, "version": "13.5.3" }, { @@ -929,7 +929,7 @@ "azure", "database" ], - "downloads": 1219, + "downloads": 1228, "version": "0.116.0" }, { @@ -947,7 +947,7 @@ "runtime", "polyglot" ], - "downloads": 1030, + "downloads": 1072, "version": "13.5.3-preview.1.26425.3" }, { @@ -961,7 +961,7 @@ "hosting", "elasticsearch" ], - "downloads": 429487, + "downloads": 431165, "version": "13.3.0" }, { @@ -980,7 +980,7 @@ "database", "polyglot" ], - "downloads": 30011, + "downloads": 30415, "version": "13.5.3-preview.1.26425.3" }, { @@ -1001,7 +1001,7 @@ "cloud", "polyglot" ], - "downloads": 55403, + "downloads": 56134, "version": "13.5.3-preview.1.26425.3" }, { @@ -1018,7 +1018,7 @@ "caching", "polyglot" ], - "downloads": 112678, + "downloads": 113384, "version": "13.5.3" }, { @@ -1035,7 +1035,7 @@ "ai", "polyglot" ], - "downloads": 30383, + "downloads": 30481, "version": "13.5.3" }, { @@ -1053,7 +1053,7 @@ "runtime", "polyglot" ], - "downloads": 5334, + "downloads": 5594, "version": "13.5.3-preview.1.26425.3" }, { @@ -1067,7 +1067,7 @@ "analyzers", "ats" ], - "downloads": 5021, + "downloads": 5039, "version": "13.5.3-preview.1.26425.3" }, { @@ -1086,7 +1086,7 @@ "runtime", "polyglot" ], - "downloads": 3820074, + "downloads": 3861295, "version": "13.5.3" }, { @@ -1103,7 +1103,7 @@ "eventing", "polyglot" ], - "downloads": 1324192, + "downloads": 1333443, "version": "13.5.3" }, { @@ -1121,7 +1121,7 @@ "security", "polyglot" ], - "downloads": 876222, + "downloads": 881705, "version": "13.5.3-preview.1.26425.3" }, { @@ -1135,7 +1135,7 @@ "kubernetes", "polyglot" ], - "downloads": 239846, + "downloads": 242105, "version": "13.5.3-preview.1.26425.3" }, { @@ -1149,7 +1149,7 @@ "hosting", "polyglot" ], - "downloads": 40443, + "downloads": 40617, "version": "13.5.3-preview.1.26425.3" }, { @@ -1169,7 +1169,7 @@ "ai-search", "polyglot" ], - "downloads": 14495, + "downloads": 14502, "version": "13.5.3" }, { @@ -1186,7 +1186,7 @@ "data", "polyglot" ], - "downloads": 1023597, + "downloads": 1028931, "version": "13.5.3" }, { @@ -1203,7 +1203,7 @@ "data", "polyglot" ], - "downloads": 384914, + "downloads": 386300, "version": "13.5.3" }, { @@ -1220,7 +1220,7 @@ "eventing", "polyglot" ], - "downloads": 234503, + "downloads": 236504, "version": "13.5.3" }, { @@ -1236,7 +1236,7 @@ "ai", "polyglot" ], - "downloads": 45975, + "downloads": 46060, "version": "13.5.3" }, { @@ -1254,7 +1254,7 @@ "data", "polyglot" ], - "downloads": 96074, + "downloads": 96649, "version": "13.5.3" }, { @@ -1271,7 +1271,7 @@ "eventing", "polyglot" ], - "downloads": 363135, + "downloads": 364970, "version": "13.5.3" }, { @@ -1291,7 +1291,7 @@ "data", "polyglot" ], - "downloads": 7753554, + "downloads": 7802426, "version": "13.5.3" }, { @@ -1308,7 +1308,7 @@ "runtime", "polyglot" ], - "downloads": 373197, + "downloads": 375339, "version": "13.5.3" }, { @@ -1327,7 +1327,7 @@ "data", "polyglot" ], - "downloads": 149648, + "downloads": 149891, "version": "13.5.3" }, { @@ -1344,7 +1344,7 @@ "eventing", "polyglot" ], - "downloads": 3133643, + "downloads": 3154656, "version": "13.5.3" }, { @@ -1361,7 +1361,7 @@ "deployment", "polyglot" ], - "downloads": 246, + "downloads": 248, "version": "13.5.3-preview.1.26425.3" }, { @@ -1378,7 +1378,7 @@ "caching", "polyglot" ], - "downloads": 7620886, + "downloads": 7668777, "version": "13.5.3" }, { @@ -1395,7 +1395,7 @@ "logging", "polyglot" ], - "downloads": 547256, + "downloads": 550096, "version": "13.5.3" }, { @@ -1413,7 +1413,7 @@ "data", "polyglot" ], - "downloads": 7644971, + "downloads": 7691605, "version": "13.5.3" }, { @@ -1430,7 +1430,7 @@ "caching", "polyglot" ], - "downloads": 698762, + "downloads": 702714, "version": "13.5.3" }, { @@ -1447,7 +1447,7 @@ "api", "polyglot" ], - "downloads": 514097, + "downloads": 517666, "version": "13.5.3" }, { @@ -1466,7 +1466,7 @@ "identity", "security" ], - "downloads": 614380, + "downloads": 617596, "version": "13.5.3-preview.1.26425.3" }, { @@ -1488,7 +1488,7 @@ "db", "nosql" ], - "downloads": 1480945, + "downloads": 1489057, "version": "13.5.3" }, { @@ -1507,7 +1507,7 @@ "cache", "caching" ], - "downloads": 125648, + "downloads": 126675, "version": "13.5.3" }, { @@ -1526,7 +1526,7 @@ "sqlserver", "sql" ], - "downloads": 1932415, + "downloads": 1935946, "version": "13.5.3" }, { @@ -1553,7 +1553,7 @@ "cosmosdb", "nosql" ], - "downloads": 236186, + "downloads": 236926, "version": "13.5.3" }, { @@ -1578,7 +1578,7 @@ "sqlserver", "sql" ], - "downloads": 6045416, + "downloads": 6069704, "version": "13.5.3" }, { @@ -1596,7 +1596,7 @@ "configuration", "appconfiguration" ], - "downloads": 731530, + "downloads": 737340, "version": "13.5.3" }, { @@ -1616,7 +1616,7 @@ "search", "ai-search" ], - "downloads": 9401, + "downloads": 9403, "version": "13.5.3-preview.1.26425.3" }, { @@ -1634,7 +1634,7 @@ "database", "mongodb" ], - "downloads": 405669, + "downloads": 408327, "version": "13.5.3" }, { @@ -1652,7 +1652,7 @@ "database", "mongodb" ], - "downloads": 4950, + "downloads": 4954, "version": "13.5.3" }, { @@ -1676,7 +1676,7 @@ "o/rm", "mongodb" ], - "downloads": 6887, + "downloads": 6905, "version": "13.5.3" }, { @@ -1696,7 +1696,7 @@ "mysql", "sql" ], - "downloads": 2471031, + "downloads": 2471206, "version": "13.5.3" }, { @@ -1714,7 +1714,7 @@ "messaging", "eventing" ], - "downloads": 183890, + "downloads": 184862, "version": "13.5.3" }, { @@ -1735,7 +1735,7 @@ "npgsql", "sql" ], - "downloads": 3545995, + "downloads": 3553942, "version": "13.5.3" }, { @@ -1762,7 +1762,7 @@ "npgsql", "sql" ], - "downloads": 6951385, + "downloads": 6976305, "version": "13.5.3" }, { @@ -1779,7 +1779,7 @@ "ai", "openai" ], - "downloads": 725152, + "downloads": 727715, "version": "13.5.3-preview.1.26425.3" }, { @@ -1804,7 +1804,7 @@ "oracle", "sql" ], - "downloads": 249799, + "downloads": 250069, "version": "13.5.3" }, { @@ -1830,7 +1830,7 @@ "mysql", "sql" ], - "downloads": 419414, + "downloads": 419767, "version": "13.5.3" }, { @@ -1849,7 +1849,7 @@ "database", "ai-search" ], - "downloads": 123167, + "downloads": 123354, "version": "13.5.3" }, { @@ -1870,7 +1870,7 @@ "messaging", "eventing" ], - "downloads": 1187546, + "downloads": 1193500, "version": "13.5.3" }, { @@ -1891,7 +1891,7 @@ "messaging", "eventing" ], - "downloads": 5284, + "downloads": 5290, "version": "13.5.3" }, { @@ -1909,7 +1909,7 @@ "observability", "logging" ], - "downloads": 530964, + "downloads": 532318, "version": "13.5.3" }, { @@ -1927,7 +1927,7 @@ "caching", "redis" ], - "downloads": 11715045, + "downloads": 11743649, "version": "13.5.3" }, { @@ -1947,7 +1947,7 @@ "distributedcache", "redis" ], - "downloads": 3338821, + "downloads": 3354750, "version": "13.5.3" }, { @@ -1968,7 +1968,7 @@ "outputcache", "redis" ], - "downloads": 973870, + "downloads": 976392, "version": "13.5.3" }, { @@ -1982,7 +1982,7 @@ "typesystem", "polyglot" ], - "downloads": 75909, + "downloads": 76534, "version": "13.5.3" }, { @@ -2000,7 +2000,7 @@ "secret-manager", "client" ], - "downloads": 1432, + "downloads": 1519, "version": "13.5.0" }, { @@ -2019,7 +2019,7 @@ "olap", "ado.net" ], - "downloads": 1469, + "downloads": 1516, "version": "13.5.0" }, { @@ -2035,7 +2035,7 @@ "gofeatureflag", "client" ], - "downloads": 49981, + "downloads": 50041, "version": "13.5.0" }, { @@ -2052,7 +2052,7 @@ "activemq", "polyglot" ], - "downloads": 74019, + "downloads": 74235, "version": "13.5.0" }, { @@ -2069,7 +2069,7 @@ "adminer", "polyglot" ], - "downloads": 263315, + "downloads": 265130, "version": "13.5.0" }, { @@ -2087,7 +2087,7 @@ "azure", "polyglot" ], - "downloads": 90690, + "downloads": 90949, "version": "13.0.0" }, { @@ -2108,7 +2108,7 @@ "pubsub", "polyglot" ], - "downloads": 53664, + "downloads": 53760, "version": "13.0.0" }, { @@ -2126,7 +2126,7 @@ "hosting", "polyglot" ], - "downloads": 69036, + "downloads": 69095, "version": "13.5.0" }, { @@ -2144,7 +2144,7 @@ "extensions", "polyglot" ], - "downloads": 6233, + "downloads": 6295, "version": "13.5.0" }, { @@ -2163,26 +2163,7 @@ "secret-manager", "polyglot" ], - "downloads": 1225, - "version": "13.5.0" - }, - { - "title": "CommunityToolkit.Aspire.Hosting.Bun", - "description": "An Aspire integration for hosting Bun apps. DEPRECATED: Use Aspire.Hosting.JavaScript and builder.AddBunApp(...) instead. This package will be removed in a future release.", - "icon": "https://api.nuget.org/v3-flatcontainer/communitytoolkit.aspire.hosting.bun/13.5.0/icon", - "href": "https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Bun", - "tags": [ - "aspire", - "integration", - "communitytoolkit", - "dotnetcommunitytoolkit", - "hosting", - "bun", - "javascript", - "deprecated", - "polyglot" - ], - "downloads": 106469, + "downloads": 1292, "version": "13.5.0" }, { @@ -2199,7 +2180,7 @@ "dapr", "polyglot" ], - "downloads": 717410, + "downloads": 721004, "version": "13.0.0" }, { @@ -2213,7 +2194,7 @@ "communitytoolkit", "dotnetcommunitytoolkit" ], - "downloads": 4691, + "downloads": 4694, "version": "9.1.1-beta.197" }, { @@ -2230,7 +2211,7 @@ "dbgate", "polyglot" ], - "downloads": 319659, + "downloads": 321718, "version": "13.5.0" }, { @@ -2247,7 +2228,7 @@ "dbx", "polyglot" ], - "downloads": 8550, + "downloads": 9375, "version": "13.5.0" }, { @@ -2264,7 +2245,7 @@ "deno", "polyglot" ], - "downloads": 70687, + "downloads": 70835, "version": "13.5.0" }, { @@ -2283,7 +2264,7 @@ "olap", "polyglot" ], - "downloads": 1459, + "downloads": 1508, "version": "13.5.0" }, { @@ -2301,7 +2282,7 @@ "elasticvue", "polyglot" ], - "downloads": 7035, + "downloads": 7188, "version": "13.5.0" }, { @@ -2320,7 +2301,7 @@ "openfeature", "polyglot" ], - "downloads": 25416, + "downloads": 25613, "version": "13.5.0" }, { @@ -2345,7 +2326,7 @@ "tls", "polyglot" ], - "downloads": 568, + "downloads": 656, "version": "13.5.0" }, { @@ -2363,7 +2344,7 @@ "migration", "polyglot" ], - "downloads": 49772, + "downloads": 50262, "version": "13.5.0" }, { @@ -2380,7 +2361,7 @@ "gofeatureflag", "polyglot" ], - "downloads": 48312, + "downloads": 48368, "version": "13.5.0" }, { @@ -2397,7 +2378,7 @@ "java", "polyglot" ], - "downloads": 77818, + "downloads": 77912, "version": "13.5.0" }, { @@ -2418,7 +2399,7 @@ "npm", "polyglot" ], - "downloads": 165146, + "downloads": 166515, "version": "13.5.0" }, { @@ -2437,7 +2418,7 @@ "cluster", "polyglot" ], - "downloads": 1328, + "downloads": 1398, "version": "13.5.0" }, { @@ -2454,7 +2435,7 @@ "k6", "polyglot" ], - "downloads": 63274, + "downloads": 63425, "version": "13.5.0" }, { @@ -2473,7 +2454,7 @@ "extensions", "polyglot" ], - "downloads": 17508, + "downloads": 17685, "version": "13.5.1-beta.748" }, { @@ -2494,7 +2475,7 @@ "podman", "polyglot" ], - "downloads": 752, + "downloads": 799, "version": "13.5.1-beta.748" }, { @@ -2511,7 +2492,7 @@ "kurrentdb", "polyglot" ], - "downloads": 17300, + "downloads": 17407, "version": "13.5.0" }, { @@ -2528,7 +2509,7 @@ "lavinmq", "polyglot" ], - "downloads": 49153, + "downloads": 49346, "version": "13.5.0" }, { @@ -2548,7 +2529,7 @@ "marketing", "polyglot" ], - "downloads": 839, + "downloads": 890, "version": "13.5.0" }, { @@ -2568,7 +2549,7 @@ "extensions", "polyglot" ], - "downloads": 1341, + "downloads": 1391, "version": "13.5.0" }, { @@ -2586,7 +2567,7 @@ "hosting", "polyglot" ], - "downloads": 361423, + "downloads": 363748, "version": "13.5.0" }, { @@ -2605,7 +2586,7 @@ "hosting", "polyglot" ], - "downloads": 70658, + "downloads": 70999, "version": "13.5.0" }, { @@ -2622,7 +2603,7 @@ "meilisearch", "polyglot" ], - "downloads": 72818, + "downloads": 72928, "version": "13.5.0" }, { @@ -2642,7 +2623,7 @@ "deprecated", "polyglot" ], - "downloads": 182021, + "downloads": 183255, "version": "13.5.0" }, { @@ -2660,7 +2641,7 @@ "dbgate", "polyglot" ], - "downloads": 85172, + "downloads": 85358, "version": "13.5.0" }, { @@ -2679,7 +2660,7 @@ "messaging", "polyglot" ], - "downloads": 329, + "downloads": 377, "version": "13.5.0" }, { @@ -2697,7 +2678,7 @@ "dbgate", "polyglot" ], - "downloads": 46222, + "downloads": 46399, "version": "13.5.0" }, { @@ -2715,7 +2696,7 @@ "tunnels", "polyglot" ], - "downloads": 191586, + "downloads": 193802, "version": "13.5.0" }, { @@ -2733,7 +2714,7 @@ "ai", "polyglot" ], - "downloads": 384006, + "downloads": 385645, "version": "13.5.0" }, { @@ -2751,7 +2732,7 @@ "observability", "polyglot" ], - "downloads": 62126, + "downloads": 62679, "version": "13.5.0" }, { @@ -2769,7 +2750,7 @@ "hosting", "polyglot" ], - "downloads": 61808, + "downloads": 61910, "version": "13.5.0" }, { @@ -2786,7 +2767,7 @@ "perl", "polyglot" ], - "downloads": 1849, + "downloads": 1934, "version": "13.5.0" }, { @@ -2806,7 +2787,7 @@ "delivery", "polyglot" ], - "downloads": 352, + "downloads": 400, "version": "13.5.0" }, { @@ -2824,7 +2805,7 @@ "dbgate", "polyglot" ], - "downloads": 108067, + "downloads": 108470, "version": "13.5.0" }, { @@ -2844,7 +2825,7 @@ "hosting", "polyglot" ], - "downloads": 65452, + "downloads": 65736, "version": "13.5.0" }, { @@ -2862,7 +2843,7 @@ "python", "polyglot" ], - "downloads": 77562, + "downloads": 77637, "version": "13.5.0" }, { @@ -2879,7 +2860,7 @@ "ravendb", "polyglot" ], - "downloads": 71089, + "downloads": 71273, "version": "13.5.0" }, { @@ -2897,7 +2878,7 @@ "dbgate", "polyglot" ], - "downloads": 77696, + "downloads": 77971, "version": "13.5.0" }, { @@ -2917,7 +2898,7 @@ "messaging", "polyglot" ], - "downloads": 390, + "downloads": 442, "version": "13.5.0" }, { @@ -2934,7 +2915,7 @@ "rust", "polyglot" ], - "downloads": 70140, + "downloads": 70326, "version": "13.5.0" }, { @@ -2953,7 +2934,7 @@ "s3-compatible", "polyglot" ], - "downloads": 2386, + "downloads": 2467, "version": "13.5.0" }, { @@ -2973,7 +2954,7 @@ "s3", "polyglot" ], - "downloads": 1568, + "downloads": 1706, "version": "13.5.0" }, { @@ -2991,7 +2972,7 @@ "hosting", "polyglot" ], - "downloads": 9533, + "downloads": 9712, "version": "13.5.0" }, { @@ -3009,7 +2990,7 @@ "search", "polyglot" ], - "downloads": 14960, + "downloads": 15058, "version": "13.5.0" }, { @@ -3027,7 +3008,7 @@ "sqlproj", "polyglot" ], - "downloads": 340313, + "downloads": 342371, "version": "13.5.0" }, { @@ -3045,7 +3026,7 @@ "sqlite", "polyglot" ], - "downloads": 93171, + "downloads": 93354, "version": "13.5.0" }, { @@ -3063,7 +3044,7 @@ "dbgate", "polyglot" ], - "downloads": 214334, + "downloads": 215777, "version": "13.5.0" }, { @@ -3083,7 +3064,7 @@ "copilot", "polyglot" ], - "downloads": 1148, + "downloads": 1222, "version": "13.5.0" }, { @@ -3103,7 +3084,7 @@ "huggingface", "polyglot" ], - "downloads": 322, + "downloads": 370, "version": "13.5.0" }, { @@ -3122,7 +3103,7 @@ "webhooks", "polyglot" ], - "downloads": 12501, + "downloads": 12583, "version": "13.5.0" }, { @@ -3139,7 +3120,7 @@ "surrealdb", "polyglot" ], - "downloads": 21932, + "downloads": 22019, "version": "13.5.0" }, { @@ -3156,7 +3137,7 @@ "umami", "polyglot" ], - "downloads": 2300, + "downloads": 2367, "version": "13.5.0" }, { @@ -3178,7 +3159,7 @@ "oidc", "polyglot" ], - "downloads": 2319, + "downloads": 2384, "version": "13.5.0" }, { @@ -3194,7 +3175,7 @@ "kurrentdb", "client" ], - "downloads": 12581, + "downloads": 12636, "version": "13.5.0" }, { @@ -3213,7 +3194,7 @@ "oidc", "jwt" ], - "downloads": 1333, + "downloads": 1388, "version": "13.5.0" }, { @@ -3230,7 +3211,7 @@ "masstransit", "rabbitmq" ], - "downloads": 83319, + "downloads": 83500, "version": "13.5.0" }, { @@ -3246,7 +3227,7 @@ "meilisearch", "client" ], - "downloads": 83224, + "downloads": 83365, "version": "13.5.0" }, { @@ -3264,7 +3245,7 @@ "data", "ado.net" ], - "downloads": 56114, + "downloads": 56177, "version": "13.5.0" }, { @@ -3285,7 +3266,7 @@ "ef", "orm" ], - "downloads": 65710, + "downloads": 65782, "version": "9.7.2" }, { @@ -3304,7 +3285,7 @@ "storage", "deprecated" ], - "downloads": 85259, + "downloads": 85700, "version": "13.5.0" }, { @@ -3322,7 +3303,7 @@ "ollamasharp", "client" ], - "downloads": 472855, + "downloads": 474876, "version": "13.5.0" }, { @@ -3339,7 +3320,7 @@ "email", "client" ], - "downloads": 322, + "downloads": 369, "version": "13.5.0" }, { @@ -3355,7 +3336,7 @@ "client", "ravendb" ], - "downloads": 71437, + "downloads": 71525, "version": "13.5.0" }, { @@ -3374,7 +3355,7 @@ "storage", "s3" ], - "downloads": 1010, + "downloads": 1057, "version": "13.5.0" }, { @@ -3390,7 +3371,7 @@ "sftp", "client" ], - "downloads": 4508, + "downloads": 4570, "version": "13.5.0" }, { @@ -3406,7 +3387,7 @@ "surrealdb", "client" ], - "downloads": 21232, + "downloads": 21293, "version": "13.5.0" } ] \ No newline at end of file diff --git a/src/frontend/src/data/github-stats.json b/src/frontend/src/data/github-stats.json index 2e02bf7ac..ccf11abab 100644 --- a/src/frontend/src/data/github-stats.json +++ b/src/frontend/src/data/github-stats.json @@ -1,7 +1,7 @@ [ { "name": "microsoft/aspire", - "stars": 6292, + "stars": 6294, "description": "Aspire is the tool for code-first, extensible, observable dev and deploy.", "license": "https://github.com/microsoft/aspire/blob/main/LICENSE.TXT", "licenseName": "MIT License", @@ -9,7 +9,7 @@ }, { "name": "microsoft/aspire-samples", - "stars": 1189, + "stars": 1190, "description": "Browse the sample apps demonstrating Aspire integration across C#, JavaScript, TypeScript, Python, Go, containers, databases, cloud, AI, and observability scenarios.", "license": "https://github.com/microsoft/aspire-samples/blob/main/LICENSE", "licenseName": "MIT License", diff --git a/src/frontend/src/data/integration-docs.json b/src/frontend/src/data/integration-docs.json index f1247d023..c4d73cc05 100644 --- a/src/frontend/src/data/integration-docs.json +++ b/src/frontend/src/data/integration-docs.json @@ -387,10 +387,6 @@ "match": "CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder", "href": "/integrations/devtools/dab/dab-get-started/" }, - { - "match": "CommunityToolkit.Aspire.Hosting.Bun", - "href": "/integrations/frameworks/bun-apps/" - }, { "match": "CommunityToolkit.Aspire.Hosting.Dapr", "href": "/integrations/frameworks/dapr/dapr-get-started/" diff --git a/src/frontend/src/data/pkgs/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json b/src/frontend/src/data/pkgs/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json deleted file mode 100644 index cb60a78c9..000000000 --- a/src/frontend/src/data/pkgs/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json +++ /dev/null @@ -1,390 +0,0 @@ -{ - "package": { - "name": "CommunityToolkit.Aspire.Hosting.Bun", - "version": "13.5.0", - "targetFramework": "net10.0", - "sourceRepository": "https://github.com/CommunityToolkit/Aspire", - "sourceCommit": "4ff8268fbd97ddd23cb73dc8eff9cc92718156d1" - }, - "types": [ - { - "name": "BunAppExtensions", - "fullName": "Aspire.Hosting.BunAppExtensions", - "namespace": "Aspire.Hosting", - "kind": "class", - "accessibility": "public", - "isStatic": true, - "docs": { - "summary": [ - { - "kind": "text", - "text": " Extension methods for adding a Bun app to a " - }, - { - "kind": "cref", - "value": "T:Aspire.Hosting.IDistributedApplicationBuilder" - }, - { - "kind": "text", - "text": ". " - } - ] - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunAppExtensions.cs", - "sourceLines": "12-12", - "members": [ - { - "name": "AddBunApp", - "kind": "method", - "accessibility": "public", - "signature": "public static IResourceBuilder BunAppExtensions.AddBunApp(this IDistributedApplicationBuilder builder, string name, string? workingDirectory = null, string entryPoint = \"index.ts\", bool watch = false)", - "returnType": "Aspire.Hosting.ApplicationModel.IResourceBuilder", - "isStatic": true, - "isExtension": true, - "parameters": [ - { - "name": "builder", - "type": "Aspire.Hosting.IDistributedApplicationBuilder", - "modifier": "this" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "workingDirectory", - "type": "string?", - "isNullable": true, - "isOptional": true - }, - { - "name": "entryPoint", - "type": "string", - "isOptional": true, - "defaultValue": "index.ts" - }, - { - "name": "watch", - "type": "bool", - "isOptional": true, - "defaultValue": "False" - } - ], - "attributes": [ - { - "name": "Aspire.Hosting.AspireExportAttribute" - }, - { - "name": "System.ObsoleteAttribute", - "constructorArguments": [ - "CommunityToolkit.Aspire.Hosting.Bun is deprecated. Use Aspire.Hosting.JavaScript and builder.AddBunApp(...) instead. This package will be removed in a future release." - ] - } - ], - "docs": { - "summary": [ - { - "kind": "text", - "text": " Adds a Bun app to the builder. " - } - ], - "returns": [ - { - "kind": "text", - "text": "A reference to the " - }, - { - "kind": "cref", - "value": "T:Aspire.Hosting.ApplicationModel.IResourceBuilder`1" - }, - { - "kind": "text", - "text": "." - } - ], - "parameters": { - "builder": [ - { - "kind": "text", - "text": "The " - }, - { - "kind": "cref", - "value": "T:Aspire.Hosting.IDistributedApplicationBuilder" - }, - { - "kind": "text", - "text": " to add the resource to." - } - ], - "entryPoint": [ - { - "kind": "text", - "text": "The entry point, either a file or package.json script name." - } - ], - "name": [ - { - "kind": "text", - "text": "The name of the resource." - } - ], - "watch": [ - { - "kind": "text", - "text": "Whether to watch for changes." - } - ], - "workingDirectory": [ - { - "kind": "text", - "text": "The working directory." - } - ] - } - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunAppExtensions.cs", - "sourceLines": "34-46" - }, - { - "name": "WithBunPackageInstallation", - "kind": "method", - "accessibility": "public", - "signature": "public static IResourceBuilder BunAppExtensions.WithBunPackageInstallation(this IResourceBuilder resource, Action>? configureInstaller = null)", - "returnType": "Aspire.Hosting.ApplicationModel.IResourceBuilder", - "isStatic": true, - "isExtension": true, - "parameters": [ - { - "name": "resource", - "type": "Aspire.Hosting.ApplicationModel.IResourceBuilder", - "modifier": "this" - }, - { - "name": "configureInstaller", - "type": "System.Action>?", - "isNullable": true, - "isOptional": true - } - ], - "attributes": [ - { - "name": "Aspire.Hosting.AspireExportIgnoreAttribute", - "arguments": { - "Reason": "Action> is not ATS-compatible. Use the overload without configureInstaller instead." - } - }, - { - "name": "System.ObsoleteAttribute", - "constructorArguments": [ - "CommunityToolkit.Aspire.Hosting.Bun is deprecated. Use Aspire.Hosting.JavaScript and builder.AddBunApp(...) instead. This package will be removed in a future release." - ] - } - ], - "docs": { - "summary": [ - { - "kind": "text", - "text": " Ensures the Bun packages are installed before the application starts using Bun as the package manager. " - } - ], - "remarks": [ - { - "kind": "text", - "text": "This overload is not available in polyglot AppHosts. Use " - }, - { - "kind": "cref", - "value": "M:Aspire.Hosting.BunAppExtensions.WithBunPackageInstallation(Aspire.Hosting.ApplicationModel.IResourceBuilder{Aspire.Hosting.ApplicationModel.BunAppResource})" - }, - { - "kind": "text", - "text": " instead." - } - ], - "returns": [ - { - "kind": "text", - "text": "A reference to the " - }, - { - "kind": "cref", - "value": "T:Aspire.Hosting.ApplicationModel.IResourceBuilder`1" - }, - { - "kind": "text", - "text": "." - } - ], - "parameters": { - "configureInstaller": [ - { - "kind": "text", - "text": "Configure the Bun installer resource." - } - ], - "resource": [ - { - "kind": "text", - "text": "The Bun app resource." - } - ] - } - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunAppExtensions.cs", - "sourceLines": "59-59" - } - ] - }, - { - "name": "BunAppResource", - "fullName": "Aspire.Hosting.ApplicationModel.BunAppResource", - "namespace": "Aspire.Hosting.ApplicationModel", - "kind": "class", - "accessibility": "public", - "baseType": "Aspire.Hosting.ApplicationModel.ExecutableResource", - "docs": { - "summary": [ - { - "kind": "text", - "text": " Represents a Bun app resource. " - } - ], - "parameters": { - "name": [ - { - "kind": "text", - "text": "The name of the resource." - } - ], - "workingDirectory": [ - { - "kind": "text", - "text": "The working directory for the Bun app to launch from." - } - ] - } - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunAppResource.cs", - "sourceLines": "8-8", - "members": [ - { - "name": ".ctor", - "kind": "constructor", - "accessibility": "public", - "signature": "public BunAppResource.BunAppResource(string name, string workingDirectory)", - "returnType": "void", - "parameters": [ - { - "name": "name", - "type": "string" - }, - { - "name": "workingDirectory", - "type": "string" - } - ], - "docs": { - "summary": [ - { - "kind": "text", - "text": " Represents a Bun app resource. " - } - ], - "parameters": { - "name": [ - { - "kind": "text", - "text": "The name of the resource." - } - ], - "workingDirectory": [ - { - "kind": "text", - "text": "The working directory for the Bun app to launch from." - } - ] - } - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunAppResource.cs", - "sourceLines": "9-9" - } - ] - }, - { - "name": "BunInstallerResource", - "fullName": "Aspire.Hosting.ApplicationModel.BunInstallerResource", - "namespace": "Aspire.Hosting.ApplicationModel", - "kind": "class", - "accessibility": "public", - "baseType": "Aspire.Hosting.ApplicationModel.ExecutableResource", - "docs": { - "summary": [ - { - "kind": "text", - "text": " A resource that represents a Bun package installer. " - } - ], - "parameters": { - "name": [ - { - "kind": "text", - "text": "The name of the resource." - } - ], - "workingDirectory": [ - { - "kind": "text", - "text": "The working directory to use for the command." - } - ] - } - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunInstallerResource.cs", - "sourceLines": "8-8", - "members": [ - { - "name": ".ctor", - "kind": "constructor", - "accessibility": "public", - "signature": "public BunInstallerResource.BunInstallerResource(string name, string workingDirectory)", - "returnType": "void", - "parameters": [ - { - "name": "name", - "type": "string" - }, - { - "name": "workingDirectory", - "type": "string" - } - ], - "docs": { - "summary": [ - { - "kind": "text", - "text": " A resource that represents a Bun package installer. " - } - ], - "parameters": { - "name": [ - { - "kind": "text", - "text": "The name of the resource." - } - ], - "workingDirectory": [ - { - "kind": "text", - "text": "The working directory to use for the command." - } - ] - } - }, - "sourceFile": "src/CommunityToolkit.Aspire.Hosting.Bun/BunInstallerResource.cs", - "sourceLines": "9-9" - } - ] - } - ] -} \ No newline at end of file diff --git a/src/frontend/src/data/ts-modules/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json b/src/frontend/src/data/ts-modules/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json deleted file mode 100644 index 1899c549f..000000000 --- a/src/frontend/src/data/ts-modules/CommunityToolkit.Aspire.Hosting.Bun.13.5.0.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "package": { - "name": "CommunityToolkit.Aspire.Hosting.Bun", - "version": "13.5.0", - "language": "typescript", - "sourceRepository": "https://github.com/CommunityToolkit/Aspire", - "sourceCommit": "4ff8268fbd97ddd23cb73dc8eff9cc92718156d1" - }, - "functions": [ - { - "name": "addBunApp", - "capabilityId": "CommunityToolkit.Aspire.Hosting.Bun/addBunApp", - "qualifiedName": "addBunApp", - "description": "Adds a Bun app to the builder.", - "returns": "A reference to the `IResourceBuilder`1`.", - "kind": "Method", - "signature": "addBunApp(name: string, workingDirectory?: string, entryPoint?: string, watch?: boolean): BunAppResource", - "parameters": [ - { - "name": "name", - "type": "string", - "description": "The name of the resource." - }, - { - "name": "workingDirectory", - "type": "string", - "isOptional": true, - "description": "The working directory." - }, - { - "name": "entryPoint", - "type": "string", - "isOptional": true, - "defaultValue": "index.ts", - "description": "The entry point, either a file or package.json script name." - }, - { - "name": "watch", - "type": "boolean", - "isOptional": true, - "defaultValue": "False", - "description": "Whether to watch for changes." - } - ], - "returnType": "BunAppResource", - "returnsBuilder": true, - "targetTypeId": "Aspire.Hosting/Aspire.Hosting.IDistributedApplicationBuilder", - "expandedTargetTypes": [ - "Aspire.Hosting.IDistributedApplicationBuilder" - ] - }, - { - "name": "withBunPackageInstallation", - "capabilityId": "CommunityToolkit.Aspire.Hosting.Bun/withBunPackageInstallation", - "qualifiedName": "withBunPackageInstallation", - "description": "Ensures the Bun packages are installed before the application starts using Bun as the package manager.", - "kind": "Method", - "signature": "withBunPackageInstallation(): BunAppResource", - "parameters": [], - "returnType": "BunAppResource", - "returnsBuilder": true, - "targetTypeId": "CommunityToolkit.Aspire.Hosting.Bun/Aspire.Hosting.ApplicationModel.BunAppResource", - "expandedTargetTypes": [ - "Aspire.Hosting.ApplicationModel.BunAppResource" - ] - } - ], - "handleTypes": [ - { - "name": "BunAppResource", - "fullName": "Aspire.Hosting.ApplicationModel.BunAppResource", - "kind": "handle", - "implementedInterfaces": [ - "Aspire.Hosting.ApplicationModel.IComputeResource", - "Aspire.Hosting.ApplicationModel.IResource", - "Aspire.Hosting.ApplicationModel.IResourceWithArgs", - "Aspire.Hosting.ApplicationModel.IResourceWithEndpoints", - "Aspire.Hosting.ApplicationModel.IResourceWithEnvironment", - "Aspire.Hosting.ApplicationModel.IResourceWithProbes", - "Aspire.Hosting.ApplicationModel.IResourceWithWaitSupport" - ], - "baseTypeHierarchy": [ - "Aspire.Hosting.ApplicationModel.ExecutableResource", - "Aspire.Hosting.ApplicationModel.Resource" - ], - "capabilities": [ - { - "name": "withBunPackageInstallation", - "capabilityId": "CommunityToolkit.Aspire.Hosting.Bun/withBunPackageInstallation", - "qualifiedName": "withBunPackageInstallation", - "description": "Ensures the Bun packages are installed before the application starts using Bun as the package manager.", - "kind": "Method", - "signature": "withBunPackageInstallation(): BunAppResource", - "parameters": [], - "returnType": "BunAppResource", - "returnsBuilder": true, - "targetTypeId": "CommunityToolkit.Aspire.Hosting.Bun/Aspire.Hosting.ApplicationModel.BunAppResource", - "expandedTargetTypes": [ - "Aspire.Hosting.ApplicationModel.BunAppResource" - ] - } - ] - } - ], - "dtoTypes": [], - "enumTypes": [] -} \ No newline at end of file diff --git a/src/frontend/src/data/twoslash/aspire.d.ts b/src/frontend/src/data/twoslash/aspire.d.ts index 741c58ba4..3c0315019 100644 --- a/src/frontend/src/data/twoslash/aspire.d.ts +++ b/src/frontend/src/data/twoslash/aspire.d.ts @@ -15203,16 +15203,6 @@ export interface IDistributedApplicationBuilder { */ addBitwardenSecretManager(name: string, projectNameOrId: string | ParameterResource, organizationId: string | ParameterResource, accessToken: string | ParameterResource): BitwardenSecretManagerResource; - /** - * Adds a Bun app to the builder. - */ - - addBunApp(name: string, options?: { workingDirectory?: string; entryPoint?: string; watch?: boolean }): BunAppResource; - /** - * Adds a Bun app to the builder. - */ - - addBunApp(name: string, workingDirectory?: string, entryPoint?: string, watch?: boolean): BunAppResource; /** * Adds a DbGate container resource to the application. */ @@ -17260,11 +17250,6 @@ export interface BunAppResource { */ withYarn(install?: boolean, installArgs?: string[]): this; - /** - * Ensures the Bun packages are installed before the application starts using Bun as the package manager. - */ - - withBunPackageInstallation(): this; /** * Maps the endpoint port for the JavaScript app resource to the appropriate command line argument */ diff --git a/src/frontend/tests/unit/update-integrations.vitest.test.ts b/src/frontend/tests/unit/update-integrations.vitest.test.ts index 0491cb984..490e245da 100644 --- a/src/frontend/tests/unit/update-integrations.vitest.test.ts +++ b/src/frontend/tests/unit/update-integrations.vitest.test.ts @@ -1,4 +1,4 @@ -import { existsSync } from 'node:fs'; +import { existsSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -10,6 +10,7 @@ import integrationDocs from '@data/integration-docs.json'; import { DEFAULT_NUGET_ICON_URL, getOfficialAspireDefaultIconPackages, + reconcileIntegrationDocs, resolveIconUrl, } from '../../scripts/update-integrations'; @@ -109,6 +110,92 @@ describe('update-integrations icon handling', () => { }); }); +describe('integration documentation reconciliation', () => { + const official = { + match: 'Aspire.Hosting.Redis', + href: '/integrations/caching/redis/redis-get-started/', + }; + const community = { + match: 'CommunityToolkit.Aspire.Hosting.Dapr', + href: '/integrations/compute/dapr/', + }; + const thirdParty = { + match: 'Particular.Aspire.Hosting.ServicePlatform', + href: 'https://docs.particular.net/platform/aspire/', + }; + const catalog = [official, community].map(({ match }) => ({ title: match })); + + test('leaves the current documentation mappings unchanged', () => { + expect(reconcileIntegrationDocs(integrationDocs, aspireIntegrations)).toEqual( + integrationDocs + ); + }); + + test.each(['Aspire.Hosting.Removed', 'CommunityToolkit.Aspire.Hosting.Bun'])( + 'removes the stale mapping for %s without changing surviving links or order', + (match) => { + const docs = [official, { match, href: '/retired/' }, community, thirdParty]; + + expect(reconcileIntegrationDocs(docs, catalog)).toEqual([ + official, + community, + thirdParty, + ]); + expect(docs).toHaveLength(4); + } + ); + + test('matches catalog package IDs case-insensitively', () => { + const docs = [official, community]; + const lowercaseCatalog = catalog.map(({ title }) => ({ title: title.toLowerCase() })); + + expect(reconcileIntegrationDocs(docs, lowercaseCatalog)).toEqual(docs); + }); + + test('preserves third-party mappings outside the managed catalog', () => { + expect(reconcileIntegrationDocs([thirdParty], [])).toEqual([thirdParty]); + }); + + test('does not invent documentation links for newly discovered packages', () => { + expect( + reconcileIntegrationDocs([official], [ + ...catalog, + { title: 'Aspire.Hosting.NewIntegration' }, + ]) + ).toEqual([official]); + }); +}); + +describe('integration update automation', () => { + const frontendRoot = path.resolve(testsDir, '..', '..'); + const script = readFileSync( + path.join(frontendRoot, 'scripts', 'update-integration-data.ps1'), + 'utf8' + ); + const workflow = readFileSync( + path.resolve(frontendRoot, '..', '..', '.github', 'workflows', 'update-integration-data.yml'), + 'utf8' + ); + + test('allows and stages reconciled documentation mappings', () => { + const allowedPaths = script.match(/\$AllowedPaths = @\(([\s\S]*?)\)/)?.[1]; + const stagedPaths = workflow.match(/git add -- \\[\s\S]*?\r?\n\r?\n/)?.[0]; + + expect(allowedPaths).toContain("'src/frontend/src/data/integration-docs.json'"); + expect(stagedPaths).toContain('src/frontend/src/data/integration-docs.json'); + }); + + test('validates updated mappings before checking for changes or regenerating APIs', () => { + const validationIndex = script.indexOf('& pnpm run test:unit:structured-data'); + + expect(validationIndex).toBeGreaterThan(script.indexOf('& pnpm run update:all')); + expect(validationIndex).toBeLessThan(script.indexOf('if (-not $anyChanges)')); + expect(script.slice(validationIndex)).toMatch( + /test:unit:structured-data\s+if \(\$LASTEXITCODE -ne 0\) \{[^}]*exit 1/ + ); + }); +}); + describe('Community Toolkit documentation mappings', () => { test('maps each package at most once', () => { const seen = new Set(); diff --git a/src/frontend/vitest.structured-data.config.ts b/src/frontend/vitest.structured-data.config.ts new file mode 100644 index 000000000..50de945ee --- /dev/null +++ b/src/frontend/vitest.structured-data.config.ts @@ -0,0 +1,22 @@ +import { fileURLToPath } from 'node:url'; + +import { defineConfig } from 'vitest/config'; + +// Data validation must not initialize Astro integrations that rewrite tracked assets. +export default defineConfig({ + resolve: { + alias: { + '@data': fileURLToPath(new URL('./src/data', import.meta.url)), + '@utils': fileURLToPath(new URL('./src/utils', import.meta.url)), + }, + }, + test: { + pool: 'threads', + include: [ + 'tests/unit/structured-data.vitest.test.ts', + 'tests/unit/update-integrations.vitest.test.ts', + ], + environment: 'node', + testTimeout: 30000, + }, +}); From cd1e48dbc40c70d8cc0c1ae5ba2da41c1e1dfd76 Mon Sep 17 00:00:00 2001 From: David Pine Date: Fri, 11 Sep 2026 02:27:19 -0500 Subject: [PATCH 10/29] docs: restore Floci integration documentation (#1590) * docs: restore Floci integration documentation Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: address Floci review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../config/sidebar/integrations.topics.ts | 1 + .../src/assets/icons/floci-icon-light.svg | 41 + src/frontend/src/assets/icons/floci-icon.svg | 41 + .../docs/integrations/compute/floci.mdx | 748 ++++++++++++++++++ .../src/data/aspire-integrations.json | 24 + src/frontend/src/data/integration-docs.json | 4 + 6 files changed, 859 insertions(+) create mode 100644 src/frontend/src/assets/icons/floci-icon-light.svg create mode 100644 src/frontend/src/assets/icons/floci-icon.svg create mode 100644 src/frontend/src/content/docs/integrations/compute/floci.mdx diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index 902cd0800..6c1166232 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -868,6 +868,7 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { }, items: [ { label: 'Docker', slug: 'integrations/compute/docker' }, + { label: 'Floci', slug: 'integrations/compute/floci' }, { label: 'K3s', slug: 'integrations/compute/k3s' }, { label: 'Kubernetes', slug: 'integrations/compute/kubernetes' }, ], diff --git a/src/frontend/src/assets/icons/floci-icon-light.svg b/src/frontend/src/assets/icons/floci-icon-light.svg new file mode 100644 index 000000000..70762bd95 --- /dev/null +++ b/src/frontend/src/assets/icons/floci-icon-light.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/src/assets/icons/floci-icon.svg b/src/frontend/src/assets/icons/floci-icon.svg new file mode 100644 index 000000000..6d26ba35b --- /dev/null +++ b/src/frontend/src/assets/icons/floci-icon.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/src/content/docs/integrations/compute/floci.mdx b/src/frontend/src/content/docs/integrations/compute/floci.mdx new file mode 100644 index 000000000..f9801f8c3 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/compute/floci.mdx @@ -0,0 +1,748 @@ +--- +title: Floci integration +seoTitle: Aspire Floci integration for AWS, Azure, and GCP +description: Learn how to use the Aspire Floci hosting integration to emulate AWS, Azure, and GCP services locally in your development environment. +--- + +import { Aside, Badge, Tabs, TabItem } from '@astrojs/starlight/components'; +import ThemeImage from '@components/ThemeImage.astro'; +import flociIcon from '@assets/icons/floci-icon.svg'; +import flociLightIcon from '@assets/icons/floci-icon-light.svg'; + + + + + +The Aspire Floci hosting integration enables you to model [Floci](https://floci.io) — a family of high-performance local cloud emulators — as container resources in your Aspire application. Floci ships one image per cloud, each API-compatible with its respective provider: + +- **`floci/floci`** — AWS, 65+ services including Lambda, S3, DynamoDB, SQS, and SNS +- **`floci/floci-az`** — Azure, including Blob/Queue/Table Storage, Cosmos DB, Functions, Event Hubs, and Service Bus +- **`floci/floci-gcp`** — GCP, including Pub/Sub, Firestore, Datastore, Storage, Secret Manager, and Cloud Functions + +Every API is available in both C# and TypeScript AppHosts. The integration supports: + +- Running any combination of the AWS, Azure, and GCP emulators as container resources in the same Aspire application. +- Automatic environment variable injection for dependent services to connect to the emulated cloud. +- Customizable port and cloud-specific defaults (region, account ID, project ID). +- Data persistence with named volumes or bind mounts. +- Docker-socket access for container-backed services (Lambda, Azure Functions, Cloud Run/Cloud SQL). +- An optional [Floci UI](https://github.com/floci-io/floci-ui) web console, attachable to one or all three clouds at once. +- Custom Quarkus configuration files for the AWS emulator. +- HTTPS with Aspire-managed certificates for the AWS and Azure emulators. + +## Installation + +To start building an Aspire app that uses Floci, install the [📦 CommunityToolkit.Aspire.Hosting.Floci](https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Floci) NuGet package: + + + + +```bash title="Terminal" +aspire add communitytoolkit-floci +``` + +Or, choose a manual installation approach: + +```csharp title="AppHost.cs" +#:package CommunityToolkit.Aspire.Hosting.Floci@* +``` + +```xml title="AppHost.csproj" + +``` + + + + + +```bash title="Terminal" +aspire add communitytoolkit-floci +``` + +This updates your `aspire.config.json` with the Floci hosting integration package: + +```json title="aspire.config.json" ins={3} +{ + "packages": { + "CommunityToolkit.Aspire.Hosting.Floci": "*" + } +} +``` + + + + +### Add a Floci resource + +Each cloud has its own dedicated method — `AddFlociAws`/`addFlociAws`, `AddFlociAzure`/`addFlociAzure`, and `AddFlociGcp`/`addFlociGcp` — and each returns its own resource type. Add whichever clouds your app depends on; they can coexist in the same AppHost. + +#### Add a Floci resource for AWS + + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var aws = builder.AddFlociAws("floci-aws"); + +var api = builder.AddProject("api") + .WithReference(aws) + .WaitFor(aws); + +builder.Build().Run(); +``` + + + + + +```typescript title="apphost.mts" +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const aws = await builder.addFlociAws('floci-aws'); + +const api = await builder.addProject('api', '../Api/Api.csproj'); +await api.withFlociAwsReference(aws).waitFor(aws); + +await builder.build().run(); +``` + + + + +`WithReference(aws)`/`withFlociAwsReference(aws)` uses the standard Aspire connection string injection and automatically injects the AWS environment variables listed in [Environment variables](#environment-variables) into the dependent resource. + +#### Add a Floci resource for Azure + + + + +```csharp title="AppHost.cs" +var azure = builder.AddFlociAzure("floci-az"); + +builder.AddProject("api") + .WithReference(azure) + .WaitFor(azure); +``` + + + + + +```typescript title="apphost.mts" +const azure = await builder.addFlociAzure('floci-az'); + +const api = await builder.addProject('api', '../Api/Api.csproj'); +await api.withFlociAzureReference(azure).waitFor(azure); +``` + + + + +#### Add a Floci resource for GCP + + + + +```csharp title="AppHost.cs" +var gcp = builder.AddFlociGcp("floci-gcp", defaultProjectId: "my-project"); + +builder.AddProject("api") + .WithReference(gcp) + .WaitFor(gcp); +``` + + + + + +```typescript title="apphost.mts" +const gcp = await builder.addFlociGcp('floci-gcp', { + defaultProjectId: 'my-project', +}); + +const api = await builder.addProject('api', '../Api/Api.csproj'); +await api.withFlociGcpReference(gcp).waitFor(gcp); +``` + + + + + + +### Configure resource properties + +**AWS** accepts the following customizable properties: + +- **Port**: The host port Floci listens on (default: 4566) +- **Default Region**: AWS region for the emulator (default: `us-east-1`) +- **Default Account ID**: AWS account ID for the emulator (default: `000000000000`) + + + + +```csharp title="AppHost.cs" +var aws = builder.AddFlociAws("floci-aws", + defaultRegion: "eu-west-1", + defaultAccountId: "123456789012"); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws', { + defaultRegion: 'eu-west-1', + defaultAccountId: '123456789012', +}); +``` + + + + +**GCP** accepts the following customizable properties: + +- **Port**: The host port Floci listens on (default: 4588) +- **Default Project ID**: GCP project ID for the emulator (default: `floci-local`) + + + + +```csharp title="AppHost.cs" +var gcp = builder.AddFlociGcp("floci-gcp", + defaultProjectId: "my-project"); +``` + + + + + +```typescript title="apphost.mts" +const gcp = await builder.addFlociGcp('floci-gcp', { + defaultProjectId: 'my-project', +}); +``` + + + + +**Azure** only accepts a custom port; there's no region/account/project equivalent to configure. + +### Enable Lambda, Azure Functions, and container-backed services + +Each emulator needs access to the Docker socket to launch sibling containers for its container-backed services (AWS Lambda, Azure Functions, GCP Cloud Run/Cloud SQL). `WithDockerSocket`/`withDockerSocket` works the same way on all three clouds: + + + + +```csharp title="AppHost.cs" +var aws = builder.AddFlociAws("floci-aws") + .WithDockerSocket(); + +var azure = builder.AddFlociAzure("floci-az") + .WithDockerSocket(); + +var gcp = builder.AddFlociGcp("floci-gcp") + .WithDockerSocket(); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws'); +await aws.withDockerSocket(); + +const azure = await builder.addFlociAzure('floci-az'); +await azure.withDockerSocket(); + +const gcp = await builder.addFlociGcp('floci-gcp'); +await gcp.withDockerSocket(); +``` + + + + +On non-standard Docker installations (e.g., Podman, Rancher Desktop), pass the socket path explicitly: + + + + +```csharp title="AppHost.cs" +var aws = builder.AddFlociAws("floci-aws") + .WithDockerSocket("/run/user/1000/podman/podman.sock"); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws'); +await aws.withDockerSocket({ socketPath: '/run/user/1000/podman/podman.sock' }); +``` + + + + +### Add data persistence to Floci + +By default each emulator stores all state in memory. This information is lost when you restart the application. If you want state to persist across app restarts you can use either a data volume or a data bind mount. They are available on all three clouds. + + + +#### Data volume (recommended) + +Data volumes automatically switch Floci from in-memory to persistent mode: + + + + +```csharp title="AppHost.cs" +var aws = builder.AddFlociAws("floci-aws") + .WithDataVolume("floci-data"); + +var azure = builder.AddFlociAzure("floci-az") + .WithDataVolume("floci-az-data"); + +var gcp = builder.AddFlociGcp("floci-gcp") + .WithDataVolume("floci-gcp-data"); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws'); +await aws.withDataVolume('floci-data'); + +const azure = await builder.addFlociAzure('floci-az'); +await azure.withDataVolume('floci-az-data'); + +const gcp = await builder.addFlociGcp('floci-gcp'); +await gcp.withDataVolume('floci-gcp-data'); +``` + + + + +#### Bind mount + +Alternatively, use a host bind mount for directory-based storage: + + + + +```csharp title="AppHost.cs" +var aws = builder.AddFlociAws("floci-aws") + .WithDataBindMount("/path/to/data"); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws'); +await aws.withDataBindMount('/path/to/data'); +``` + + + + +Either approach persists resource state across container restarts and allows local inspection of the stored state. + +### Use the cloud SDKs to interact with Floci + +Once a Floci resource is running and referenced by your service, use the matching cloud SDK as you normally would. `WithReference` in C# or the cloud-specific `withFloci*Reference` method in TypeScript injects provider-specific settings into the dependent resource. + +AWS and GCP SDKs read their emulator endpoint and region or project settings from the injected environment variables. Azure Storage clients don't automatically read `AZURE_STORAGE_CONNECTION_STRING`; construct the client from the injected value: + +```csharp title="Program.cs" +using Azure.Storage.Blobs; + +var builder = WebApplication.CreateBuilder(args); + +var azureStorageConnectionString = + builder.Configuration["AZURE_STORAGE_CONNECTION_STRING"] + ?? throw new InvalidOperationException( + "AZURE_STORAGE_CONNECTION_STRING is not configured."); + +builder.Services.AddSingleton( + new BlobServiceClient(azureStorageConnectionString)); +``` + +After configuring the provider's SDK client, interact with Floci as you would with the corresponding cloud service. For example, against the AWS emulator: + +```csharp title="Service.cs" +using Amazon.S3; +using Amazon.S3.Model; + +public class StorageService +{ + private readonly IAmazonS3 _s3Client; + + public StorageService(IAmazonS3 s3Client) + { + _s3Client = s3Client; + } + + public async Task CreateBucketAsync(string bucketName) + { + await _s3Client.PutBucketAsync(new PutBucketRequest + { + BucketName = bucketName + }); + } + + public async Task UploadObjectAsync(string bucketName, string key, Stream stream) + { + await _s3Client.PutObjectAsync(new PutObjectRequest + { + BucketName = bucketName, + Key = key, + InputStream = stream + }); + } +} +``` + +### Floci UI web console + +Run the [Floci UI](https://github.com/floci-io/floci-ui) web console alongside an emulator to browse its hosted resources. `WithFlociUI`/`withFlociUI` is available on all three cloud resource types: + + + + +```csharp title="AppHost.cs" +var floci = builder.AddFlociAws("floci") + .WithFlociUI(); +``` + + + + + +```typescript title="apphost.mts" +const floci = await builder.addFlociAws('floci'); +await floci.withFlociUI(); +``` + + + + +Customize the container name or pin the host port: + + + + +```csharp title="AppHost.cs" +var floci = builder.AddFlociAws("floci") + .WithFlociUI(ui => ui.WithHostPort(14500), containerName: "my-floci-ui"); +``` + + + + + +```typescript title="apphost.mts" +const floci = await builder.addFlociAws('floci'); +await floci.withFlociUI({ + containerName: 'my-floci-ui', + configureContainer: async (ui) => { + await ui.withHostPort({ port: 14500 }); + }, +}); +``` + + + + + + +#### Attach all three clouds to one console + +A single UI console can attach to any combination of clouds. Call `WithFlociUI`/`withFlociUI` on whichever cloud creates the console, then attach the others with `WithReference` in C# or the provider-specific reference method in TypeScript: + + + + +```csharp title="AppHost.cs" +var aws = builder.AddFlociAws("floci-aws"); +var azure = builder.AddFlociAzure("floci-az"); +var gcp = builder.AddFlociGcp("floci-gcp"); + +aws.WithFlociUI(configureContainer: ui => +{ + ui.WithReference(azure); + ui.WithReference(gcp); +}); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws'); +const azure = await builder.addFlociAzure('floci-az'); +const gcp = await builder.addFlociGcp('floci-gcp'); + +await aws.withFlociUI({ + configureContainer: async (ui) => { + await ui.withAzureReference(azure); + await ui.withGcpReference(gcp); + }, +}); +``` + + + + +The UI container (`floci/floci-ui`) is added as a child resource of whichever cloud resource created it, wired to each attached cloud's endpoint over the container network (`FLOCI_ENDPOINT`/`FLOCI_AZURE_ENDPOINT`/`FLOCI_GCP_ENDPOINT`), and is excluded from the deployment manifest — it's a local development tool only. + + + +### Quarkus configuration file (AWS only) + +Mount a custom `application.yml` to tune any Floci setting that does not have a dedicated extension method. The file is injected read-only at `/deployments/config/application.yml` — the standard Quarkus Docker config override location. This is currently only available on the AWS emulator: + + + + +```csharp title="AppHost.cs" +var floci = builder.AddFlociAws("floci") + .WithConfigFile("./floci.yml"); +``` + + + + + +```typescript title="apphost.mts" +const floci = await builder.addFlociAws('floci'); +await floci.withConfigFile('./floci.yml'); +``` + + + + +Example `floci.yml` that enables debug logging and disables signature validation: + +```yaml title="floci.yml" +floci: + auth: + validate-signatures: false +quarkus: + log: + level: DEBUG +``` + +All Floci settings can also be set via `FLOCI_`-prefixed environment variables — `WithConfigFile`/`withConfigFile` is only needed for settings that don't have a dedicated extension method. + +### Configure TLS for AWS and Azure + +The AWS and Azure emulators serve HTTP and HTTPS on the same port. Configure a certificate with Aspire's certificate APIs and the integration maps the provisioned certificate paths to the matching Floci settings: + + + + + + +```csharp title="AppHost.cs" +#pragma warning disable ASPIRECERTIFICATES001 + +var aws = builder.AddFlociAws("floci-aws") + .WithHttpsDeveloperCertificate(); + +var azure = builder.AddFlociAzure("floci-az") + .WithHttpsDeveloperCertificate(); + +#pragma warning restore ASPIRECERTIFICATES001 + +builder.AddProject("api") + .WithReference(aws) + .WithReference(azure); +``` + + + + + +```typescript title="apphost.mts" +const aws = await builder.addFlociAws('floci-aws'); +await aws.withHttpsDeveloperCertificate(); + +const azure = await builder.addFlociAzure('floci-az'); +await azure.withHttpsDeveloperCertificate(); + +const api = await builder.addProject('api', '../Api/Api.csproj'); +await api.withFlociAwsReference(aws); +await api.withFlociAzureReference(azure); +``` + + + + +Host-process dependents can validate a trusted development certificate without extra client configuration. For container dependents, use `WithDeveloperCertificateTrust(true)` in C# or `withDeveloperCertificateTrust(true)` in TypeScript to install the trust bundle. + + + +### Connection string / endpoint properties + +Available on all three cloud resource types: + + + + +```csharp title="AppHost.cs" +var endpoint = floci.PrimaryEndpoint; +var host = floci.Host; +var port = floci.Port; +var connectionString = floci.ConnectionStringExpression; +``` + + + + + +```typescript title="apphost.mts" +const endpoint = await floci.primaryEndpoint(); +const host = await floci.host(); +const port = await floci.port(); +const connectionString = await floci.connectionStringExpression(); +``` + + + + +`connectionStringExpression` is an unresolved endpoint expression. Aspire resolves it for the network used by the dependent resource. + +### Endpoint resolution + +Every endpoint-bearing environment variable injected by the integration carries an Aspire endpoint expression rather than a hard-coded address: + +| Dependent resource | Resolved address | +| --------------------- | ----------------------------------------------------------- | +| Project or executable | `localhost:{hostPort}` | +| Sibling container | `{flociResourceName}:{targetPort}` on the container network | + +The scheme is `http` unless you [configure a certificate](#configure-tls-for-aws-and-azure), in which case AWS and Azure use `https` on the same port. + +## Environment variables + +When an app resource references Floci using `WithReference` in C# or a cloud-specific `withFloci*Reference` method in TypeScript, the integration injects the following environment variables: + +### AWS + +| Variable | Value | +| --------------------------- | ------------------------------------------------------------------- | +| `ConnectionStrings__{name}` | Emulator URL resolved for the dependent resource | +| `AWS_ENDPOINT_URL` | Emulator URL resolved for the dependent resource | +| `AWS_DEFAULT_REGION` | Region passed to `AddFlociAws`/`addFlociAws` (default: `us-east-1`) | +| `AWS_ACCESS_KEY_ID` | `test` | +| `AWS_SECRET_ACCESS_KEY` | `test` | + +### Azure + +| Variable | Value | +| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ConnectionStrings__{name}` | Emulator URL resolved for the dependent resource | +| `AZURE_STORAGE_CONNECTION_STRING` | Development storage connection string with Blob, Queue, and Table endpoints resolved for the dependent resource, using the well-known `devstoreaccount1` credentials | + +### GCP + +| Variable | Value | +| ------------------------------ | -------------------------------------------------------------------------- | +| `ConnectionStrings__{name}` | Emulator URL resolved for the dependent resource | +| `PUBSUB_EMULATOR_HOST` | Emulator host and port resolved for the dependent resource | +| `FIRESTORE_EMULATOR_HOST` | Emulator host and port resolved for the dependent resource | +| `DATASTORE_EMULATOR_HOST` | Emulator host and port resolved for the dependent resource | +| `STORAGE_EMULATOR_HOST` | Full emulator URL resolved for the dependent resource | +| `SECRET_MANAGER_EMULATOR_HOST` | Emulator host and port resolved for the dependent resource | +| `GOOGLE_CLOUD_PROJECT` | Project ID passed to `AddFlociGcp`/`addFlociGcp` (default: `floci-local`) | +| `CLOUDSDK_CORE_PROJECT` | Same project ID, for tools that read the `gcloud` CLI's config var instead | + +You can override any of these settings via standard Aspire environment variable configuration. All Floci-specific settings can also be set via `FLOCI_`-prefixed environment variables. + +## Integration testing + +Floci is ideal for integration testing cloud-dependent code without requiring real cloud credentials or incurring costs. Since each Floci resource is managed as a standard Aspire resource, you can use it in integration tests the same way you use other Aspire resources. + +## Supported services + +- **AWS** (`floci/floci`) — 65+ services including S3, DynamoDB, Lambda, EC2, SQS, SNS, Kinesis, RDS, CloudFormation, CloudWatch, IAM, and many more +- **Azure** (`floci/floci-az`) — Blob/Queue/Table Storage, Cosmos DB, Functions, Event Hubs, Service Bus +- **GCP** (`floci/floci-gcp`) — Pub/Sub, Firestore, Datastore, Storage, Secret Manager, Cloud Functions + +For a complete list of supported services per cloud, visit the [Floci documentation](https://floci.io). + +## Troubleshooting + +### Container fails to start + +- Ensure Docker is running and has sufficient resources. +- Check that the specified port isn't already in use. +- Verify the Floci container image is available locally or can be pulled from Docker Hub. + +### Connection refused errors + +- Verify the Floci container is running: `docker ps | grep floci` +- Check that the endpoint URL matches the configured port. +- Ensure the app resource has the correct `WithReference` or cloud-specific `withFloci*Reference` call. + +### Data persistence issues + +- Verify the bind mount directory has the correct permissions. +- Check that the host path exists before starting the container. +- Use absolute paths for bind mounts to avoid path resolution issues. + +## See also + +- [Floci documentation](https://floci.io) +- [Floci GitHub repository](https://github.com/floci-io/floci) +- [Floci UI GitHub repository](https://github.com/floci-io/floci-ui) +- [AWS SDK for .NET](https://docs.aws.amazon.com/sdk-for-net/) +- [Aspire Hosting documentation](/architecture/overview/) +- [CommunityToolkit.Aspire.Hosting.Floci GitHub](https://github.com/CommunityToolkit/Aspire) +- [CommunityToolkit.Aspire.Hosting.Floci NuGet package](https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Floci) diff --git a/src/frontend/src/data/aspire-integrations.json b/src/frontend/src/data/aspire-integrations.json index 2963f63ef..eced8958f 100644 --- a/src/frontend/src/data/aspire-integrations.json +++ b/src/frontend/src/data/aspire-integrations.json @@ -2329,6 +2329,30 @@ "downloads": 656, "version": "13.5.0" }, + { + "title": "CommunityToolkit.Aspire.Hosting.Floci", + "description": "An Aspire hosting integration for the Floci local cloud emulators: AddFlociAws (AWS), AddFlociAzure (Azure) and AddFlociGcp (GCP). Includes a WithFlociUI() extension for running the Floci UI web console alongside one or more emulators.", + "icon": "https://api.nuget.org/v3-flatcontainer/communitytoolkit.aspire.hosting.floci/13.5.0/icon", + "href": "https://www.nuget.org/packages/CommunityToolkit.Aspire.Hosting.Floci", + "tags": [ + "aspire", + "integration", + "communitytoolkit", + "dotnetcommunitytoolkit", + "floci", + "aws", + "azure", + "gcp", + "localstack", + "azurite", + "emulator", + "hosting", + "ui", + "tls" + ], + "downloads": 100, + "version": "13.5.0" + }, { "title": "CommunityToolkit.Aspire.Hosting.Flyway", "description": "An Aspire integration for Flyway database migration tool.", diff --git a/src/frontend/src/data/integration-docs.json b/src/frontend/src/data/integration-docs.json index c4d73cc05..b8b2d80ae 100644 --- a/src/frontend/src/data/integration-docs.json +++ b/src/frontend/src/data/integration-docs.json @@ -403,6 +403,10 @@ "match": "CommunityToolkit.Aspire.Hosting.Flagd", "href": "/integrations/devtools/flagd/flagd-get-started/" }, + { + "match": "CommunityToolkit.Aspire.Hosting.Floci", + "href": "/integrations/compute/floci/" + }, { "match": "CommunityToolkit.Aspire.Hosting.GoFeatureFlag", "href": "/integrations/devtools/goff/goff-get-started/" From d06e72f0d17d6f2f3f7909fd8a3bf05341c2861d Mon Sep 17 00:00:00 2001 From: "aspire-repo-bot[bot]" <268009190+aspire-repo-bot[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 06:38:24 -0500 Subject: [PATCH 11/29] chore: Update integration data and GitHub stats (9/10/26) (#1647) Co-authored-by: aspire-repo-bot[bot] Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/data/aspire-integrations.json | 370 +++++++++--------- src/frontend/src/data/github-stats.json | 4 +- 2 files changed, 187 insertions(+), 187 deletions(-) diff --git a/src/frontend/src/data/aspire-integrations.json b/src/frontend/src/data/aspire-integrations.json index eced8958f..e172056f7 100644 --- a/src/frontend/src/data/aspire-integrations.json +++ b/src/frontend/src/data/aspire-integrations.json @@ -15,7 +15,7 @@ "inference", "ai-search" ], - "downloads": 137982, + "downloads": 139282, "version": "13.5.3-preview.1.26425.3" }, { @@ -33,7 +33,7 @@ "ai", "openai" ], - "downloads": 800525, + "downloads": 802872, "version": "13.5.3-preview.1.26425.3" }, { @@ -52,7 +52,7 @@ "table", "storage" ], - "downloads": 3958134, + "downloads": 3963404, "version": "13.5.3" }, { @@ -72,7 +72,7 @@ "messaging", "eventing" ], - "downloads": 746425, + "downloads": 749351, "version": "13.5.3" }, { @@ -92,7 +92,7 @@ "messaging", "eventing" ], - "downloads": 1849912, + "downloads": 1860175, "version": "13.5.3" }, { @@ -112,7 +112,7 @@ "pubsub", "messaging" ], - "downloads": 70115, + "downloads": 70357, "version": "13.5.3" }, { @@ -134,7 +134,7 @@ "database", "data" ], - "downloads": 155838, + "downloads": 157050, "version": "13.5.3" }, { @@ -161,7 +161,7 @@ "npgsql", "sql" ], - "downloads": 412380, + "downloads": 416419, "version": "13.5.3" }, { @@ -180,7 +180,7 @@ "ai", "ai-search" ], - "downloads": 452569, + "downloads": 454187, "version": "13.5.3" }, { @@ -199,7 +199,7 @@ "secrets", "security" ], - "downloads": 1607529, + "downloads": 1615859, "version": "13.5.3" }, { @@ -218,7 +218,7 @@ "blobs", "blob" ], - "downloads": 6927679, + "downloads": 6952708, "version": "13.5.3" }, { @@ -237,7 +237,7 @@ "files", "datalake" ], - "downloads": 5483, + "downloads": 5535, "version": "13.5.3-preview.1.26425.3" }, { @@ -257,7 +257,7 @@ "queues", "messaging" ], - "downloads": 1874032, + "downloads": 1881083, "version": "13.5.3" }, { @@ -275,7 +275,7 @@ "messaging", "eventing" ], - "downloads": 2653124, + "downloads": 2655473, "version": "13.5.3" }, { @@ -291,7 +291,7 @@ "cloud", "elasticsearch" ], - "downloads": 78216, + "downloads": 78418, "version": "13.3.0" }, { @@ -305,7 +305,7 @@ "orchestration", "polyglot" ], - "downloads": 35787689, + "downloads": 36001184, "version": "13.5.3" }, { @@ -322,7 +322,7 @@ "ai", "agents" ], - "downloads": 4166, + "downloads": 4198, "version": "1.20.0-preview.260831.1" }, { @@ -336,7 +336,7 @@ "hosting", "aws" ], - "downloads": 786885, + "downloads": 792580, "version": "13.7.2" }, { @@ -353,7 +353,7 @@ "orchestration", "polyglot" ], - "downloads": 9037440, + "downloads": 9096397, "version": "13.5.3" }, { @@ -370,7 +370,7 @@ "cloud", "polyglot" ], - "downloads": 597818, + "downloads": 602245, "version": "13.5.3" }, { @@ -388,7 +388,7 @@ "appcontainers", "polyglot" ], - "downloads": 1245260, + "downloads": 1253759, "version": "13.5.3" }, { @@ -407,7 +407,7 @@ "applicationinsights", "polyglot" ], - "downloads": 974813, + "downloads": 980012, "version": "13.5.3" }, { @@ -424,7 +424,7 @@ "appservice", "polyglot" ], - "downloads": 90326, + "downloads": 90948, "version": "13.5.3" }, { @@ -445,7 +445,7 @@ "cloud", "polyglot" ], - "downloads": 835357, + "downloads": 838660, "version": "13.5.3" }, { @@ -463,7 +463,7 @@ "cloud", "polyglot" ], - "downloads": 937777, + "downloads": 946845, "version": "13.5.3" }, { @@ -483,7 +483,7 @@ "nosql", "polyglot" ], - "downloads": 1611140, + "downloads": 1622799, "version": "13.5.3" }, { @@ -502,7 +502,7 @@ "cloud", "polyglot" ], - "downloads": 642418, + "downloads": 649034, "version": "13.5.3" }, { @@ -520,7 +520,7 @@ "cloud", "polyglot" ], - "downloads": 10333, + "downloads": 10397, "version": "13.5.3-preview.1.26425.3" }, { @@ -538,7 +538,7 @@ "cloud", "polyglot" ], - "downloads": 1755004, + "downloads": 1768330, "version": "13.5.3" }, { @@ -557,7 +557,7 @@ "cloud", "polyglot" ], - "downloads": 3343255, + "downloads": 3367656, "version": "13.5.3" }, { @@ -574,7 +574,7 @@ "aks", "polyglot" ], - "downloads": 2834, + "downloads": 2965, "version": "13.5.3-preview.1.26425.3" }, { @@ -593,7 +593,7 @@ "cloud", "polyglot" ], - "downloads": 9696, + "downloads": 9733, "version": "13.5.3-preview.1.26425.3" }, { @@ -615,7 +615,7 @@ "cloud", "polyglot" ], - "downloads": 425574, + "downloads": 431775, "version": "13.5.3" }, { @@ -633,7 +633,7 @@ "cloud", "polyglot" ], - "downloads": 1639339, + "downloads": 1649509, "version": "13.5.3" }, { @@ -652,7 +652,7 @@ "cloud", "polyglot" ], - "downloads": 813543, + "downloads": 819355, "version": "13.5.3" }, { @@ -671,7 +671,7 @@ "cloud", "polyglot" ], - "downloads": 628555, + "downloads": 631617, "version": "13.5.3" }, { @@ -690,7 +690,7 @@ "cloud", "polyglot" ], - "downloads": 309651, + "downloads": 311340, "version": "13.5.3" }, { @@ -709,7 +709,7 @@ "cloud", "polyglot" ], - "downloads": 2470957, + "downloads": 2491268, "version": "13.5.3" }, { @@ -727,7 +727,7 @@ "cloud", "polyglot" ], - "downloads": 331355, + "downloads": 334276, "version": "13.5.3" }, { @@ -746,7 +746,7 @@ "cloud", "polyglot" ], - "downloads": 950322, + "downloads": 956555, "version": "13.5.3" }, { @@ -766,7 +766,7 @@ "cloud", "polyglot" ], - "downloads": 6312661, + "downloads": 6358311, "version": "13.5.3" }, { @@ -786,7 +786,7 @@ "cloud", "polyglot" ], - "downloads": 38911, + "downloads": 38999, "version": "13.5.3" }, { @@ -803,7 +803,7 @@ "gateway", "polyglot" ], - "downloads": 4432, + "downloads": 4532, "version": "13.5.3-preview.1.26425.3" }, { @@ -821,7 +821,7 @@ "diagnostics", "polyglot" ], - "downloads": 160240, + "downloads": 161971, "version": "13.5.3-preview.1.26425.3" }, { @@ -837,7 +837,7 @@ "database", "data" ], - "downloads": 28364, + "downloads": 28831, "version": "13.5.3" }, { @@ -846,7 +846,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.go/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Go", "tags": [], - "downloads": 10127, + "downloads": 10273, "version": "13.5.3" }, { @@ -855,7 +855,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.java/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Java", "tags": [], - "downloads": 2836, + "downloads": 2837, "version": "13.5.3" }, { @@ -864,7 +864,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.python/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.Python", "tags": [], - "downloads": 2787, + "downloads": 2791, "version": "13.5.3" }, { @@ -882,7 +882,7 @@ "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.codegeneration.typescript/13.5.3/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.CodeGeneration.TypeScript", "tags": [], - "downloads": 66257, + "downloads": 67160, "version": "13.5.3" }, { @@ -896,7 +896,7 @@ "devtunnels", "polyglot" ], - "downloads": 529892, + "downloads": 535138, "version": "13.5.3" }, { @@ -911,7 +911,7 @@ "docker-compose", "polyglot" ], - "downloads": 698706, + "downloads": 703236, "version": "13.5.3" }, { @@ -929,7 +929,7 @@ "azure", "database" ], - "downloads": 1228, + "downloads": 1231, "version": "0.116.0" }, { @@ -947,7 +947,7 @@ "runtime", "polyglot" ], - "downloads": 1072, + "downloads": 1145, "version": "13.5.3-preview.1.26425.3" }, { @@ -961,7 +961,7 @@ "hosting", "elasticsearch" ], - "downloads": 431165, + "downloads": 432899, "version": "13.3.0" }, { @@ -980,7 +980,7 @@ "database", "polyglot" ], - "downloads": 30415, + "downloads": 30918, "version": "13.5.3-preview.1.26425.3" }, { @@ -1001,7 +1001,7 @@ "cloud", "polyglot" ], - "downloads": 56134, + "downloads": 56945, "version": "13.5.3-preview.1.26425.3" }, { @@ -1018,7 +1018,7 @@ "caching", "polyglot" ], - "downloads": 113384, + "downloads": 114304, "version": "13.5.3" }, { @@ -1035,7 +1035,7 @@ "ai", "polyglot" ], - "downloads": 30481, + "downloads": 30569, "version": "13.5.3" }, { @@ -1053,7 +1053,7 @@ "runtime", "polyglot" ], - "downloads": 5594, + "downloads": 5850, "version": "13.5.3-preview.1.26425.3" }, { @@ -1067,7 +1067,7 @@ "analyzers", "ats" ], - "downloads": 5039, + "downloads": 5043, "version": "13.5.3-preview.1.26425.3" }, { @@ -1086,7 +1086,7 @@ "runtime", "polyglot" ], - "downloads": 3861295, + "downloads": 3904969, "version": "13.5.3" }, { @@ -1103,7 +1103,7 @@ "eventing", "polyglot" ], - "downloads": 1333443, + "downloads": 1342300, "version": "13.5.3" }, { @@ -1121,7 +1121,7 @@ "security", "polyglot" ], - "downloads": 881705, + "downloads": 887644, "version": "13.5.3-preview.1.26425.3" }, { @@ -1135,7 +1135,7 @@ "kubernetes", "polyglot" ], - "downloads": 242105, + "downloads": 244554, "version": "13.5.3-preview.1.26425.3" }, { @@ -1149,7 +1149,7 @@ "hosting", "polyglot" ], - "downloads": 40617, + "downloads": 40791, "version": "13.5.3-preview.1.26425.3" }, { @@ -1169,7 +1169,7 @@ "ai-search", "polyglot" ], - "downloads": 14502, + "downloads": 14529, "version": "13.5.3" }, { @@ -1186,7 +1186,7 @@ "data", "polyglot" ], - "downloads": 1028931, + "downloads": 1034533, "version": "13.5.3" }, { @@ -1203,7 +1203,7 @@ "data", "polyglot" ], - "downloads": 386300, + "downloads": 388172, "version": "13.5.3" }, { @@ -1220,7 +1220,7 @@ "eventing", "polyglot" ], - "downloads": 236504, + "downloads": 238337, "version": "13.5.3" }, { @@ -1236,7 +1236,7 @@ "ai", "polyglot" ], - "downloads": 46060, + "downloads": 46432, "version": "13.5.3" }, { @@ -1254,7 +1254,7 @@ "data", "polyglot" ], - "downloads": 96649, + "downloads": 97234, "version": "13.5.3" }, { @@ -1271,7 +1271,7 @@ "eventing", "polyglot" ], - "downloads": 364970, + "downloads": 367225, "version": "13.5.3" }, { @@ -1291,7 +1291,7 @@ "data", "polyglot" ], - "downloads": 7802426, + "downloads": 7858056, "version": "13.5.3" }, { @@ -1308,7 +1308,7 @@ "runtime", "polyglot" ], - "downloads": 375339, + "downloads": 377942, "version": "13.5.3" }, { @@ -1327,7 +1327,7 @@ "data", "polyglot" ], - "downloads": 149891, + "downloads": 150323, "version": "13.5.3" }, { @@ -1344,7 +1344,7 @@ "eventing", "polyglot" ], - "downloads": 3154656, + "downloads": 3178380, "version": "13.5.3" }, { @@ -1361,7 +1361,7 @@ "deployment", "polyglot" ], - "downloads": 248, + "downloads": 251, "version": "13.5.3-preview.1.26425.3" }, { @@ -1378,7 +1378,7 @@ "caching", "polyglot" ], - "downloads": 7668777, + "downloads": 7722637, "version": "13.5.3" }, { @@ -1395,7 +1395,7 @@ "logging", "polyglot" ], - "downloads": 550096, + "downloads": 553242, "version": "13.5.3" }, { @@ -1413,7 +1413,7 @@ "data", "polyglot" ], - "downloads": 7691605, + "downloads": 7742979, "version": "13.5.3" }, { @@ -1430,7 +1430,7 @@ "caching", "polyglot" ], - "downloads": 702714, + "downloads": 707510, "version": "13.5.3" }, { @@ -1447,7 +1447,7 @@ "api", "polyglot" ], - "downloads": 517666, + "downloads": 521890, "version": "13.5.3" }, { @@ -1466,7 +1466,7 @@ "identity", "security" ], - "downloads": 617596, + "downloads": 621065, "version": "13.5.3-preview.1.26425.3" }, { @@ -1488,7 +1488,7 @@ "db", "nosql" ], - "downloads": 1489057, + "downloads": 1498236, "version": "13.5.3" }, { @@ -1507,7 +1507,7 @@ "cache", "caching" ], - "downloads": 126675, + "downloads": 128069, "version": "13.5.3" }, { @@ -1526,7 +1526,7 @@ "sqlserver", "sql" ], - "downloads": 1935946, + "downloads": 1941096, "version": "13.5.3" }, { @@ -1553,7 +1553,7 @@ "cosmosdb", "nosql" ], - "downloads": 236926, + "downloads": 237853, "version": "13.5.3" }, { @@ -1578,7 +1578,7 @@ "sqlserver", "sql" ], - "downloads": 6069704, + "downloads": 6097448, "version": "13.5.3" }, { @@ -1596,7 +1596,7 @@ "configuration", "appconfiguration" ], - "downloads": 737340, + "downloads": 744958, "version": "13.5.3" }, { @@ -1616,7 +1616,7 @@ "search", "ai-search" ], - "downloads": 9403, + "downloads": 9408, "version": "13.5.3-preview.1.26425.3" }, { @@ -1634,7 +1634,7 @@ "database", "mongodb" ], - "downloads": 408327, + "downloads": 409747, "version": "13.5.3" }, { @@ -1652,7 +1652,7 @@ "database", "mongodb" ], - "downloads": 4954, + "downloads": 4958, "version": "13.5.3" }, { @@ -1676,7 +1676,7 @@ "o/rm", "mongodb" ], - "downloads": 6905, + "downloads": 6930, "version": "13.5.3" }, { @@ -1696,7 +1696,7 @@ "mysql", "sql" ], - "downloads": 2471206, + "downloads": 2471393, "version": "13.5.3" }, { @@ -1714,7 +1714,7 @@ "messaging", "eventing" ], - "downloads": 184862, + "downloads": 185765, "version": "13.5.3" }, { @@ -1735,7 +1735,7 @@ "npgsql", "sql" ], - "downloads": 3553942, + "downloads": 3563428, "version": "13.5.3" }, { @@ -1762,7 +1762,7 @@ "npgsql", "sql" ], - "downloads": 6976305, + "downloads": 7004483, "version": "13.5.3" }, { @@ -1779,7 +1779,7 @@ "ai", "openai" ], - "downloads": 727715, + "downloads": 730229, "version": "13.5.3-preview.1.26425.3" }, { @@ -1804,7 +1804,7 @@ "oracle", "sql" ], - "downloads": 250069, + "downloads": 250361, "version": "13.5.3" }, { @@ -1830,7 +1830,7 @@ "mysql", "sql" ], - "downloads": 419767, + "downloads": 420027, "version": "13.5.3" }, { @@ -1849,7 +1849,7 @@ "database", "ai-search" ], - "downloads": 123354, + "downloads": 123666, "version": "13.5.3" }, { @@ -1870,7 +1870,7 @@ "messaging", "eventing" ], - "downloads": 1193500, + "downloads": 1199223, "version": "13.5.3" }, { @@ -1891,7 +1891,7 @@ "messaging", "eventing" ], - "downloads": 5290, + "downloads": 5294, "version": "13.5.3" }, { @@ -1909,7 +1909,7 @@ "observability", "logging" ], - "downloads": 532318, + "downloads": 533906, "version": "13.5.3" }, { @@ -1927,7 +1927,7 @@ "caching", "redis" ], - "downloads": 11743649, + "downloads": 11776615, "version": "13.5.3" }, { @@ -1947,7 +1947,7 @@ "distributedcache", "redis" ], - "downloads": 3354750, + "downloads": 3372027, "version": "13.5.3" }, { @@ -1968,7 +1968,7 @@ "outputcache", "redis" ], - "downloads": 976392, + "downloads": 979257, "version": "13.5.3" }, { @@ -1982,7 +1982,7 @@ "typesystem", "polyglot" ], - "downloads": 76534, + "downloads": 77579, "version": "13.5.3" }, { @@ -2000,7 +2000,7 @@ "secret-manager", "client" ], - "downloads": 1519, + "downloads": 1522, "version": "13.5.0" }, { @@ -2019,7 +2019,7 @@ "olap", "ado.net" ], - "downloads": 1516, + "downloads": 1523, "version": "13.5.0" }, { @@ -2035,7 +2035,7 @@ "gofeatureflag", "client" ], - "downloads": 50041, + "downloads": 50051, "version": "13.5.0" }, { @@ -2052,7 +2052,7 @@ "activemq", "polyglot" ], - "downloads": 74235, + "downloads": 74365, "version": "13.5.0" }, { @@ -2069,7 +2069,7 @@ "adminer", "polyglot" ], - "downloads": 265130, + "downloads": 266893, "version": "13.5.0" }, { @@ -2087,7 +2087,7 @@ "azure", "polyglot" ], - "downloads": 90949, + "downloads": 91195, "version": "13.0.0" }, { @@ -2108,7 +2108,7 @@ "pubsub", "polyglot" ], - "downloads": 53760, + "downloads": 53819, "version": "13.0.0" }, { @@ -2126,7 +2126,7 @@ "hosting", "polyglot" ], - "downloads": 69095, + "downloads": 69124, "version": "13.5.0" }, { @@ -2144,7 +2144,7 @@ "extensions", "polyglot" ], - "downloads": 6295, + "downloads": 6310, "version": "13.5.0" }, { @@ -2163,7 +2163,7 @@ "secret-manager", "polyglot" ], - "downloads": 1292, + "downloads": 1299, "version": "13.5.0" }, { @@ -2180,7 +2180,7 @@ "dapr", "polyglot" ], - "downloads": 721004, + "downloads": 724685, "version": "13.0.0" }, { @@ -2194,7 +2194,7 @@ "communitytoolkit", "dotnetcommunitytoolkit" ], - "downloads": 4694, + "downloads": 4703, "version": "9.1.1-beta.197" }, { @@ -2211,7 +2211,7 @@ "dbgate", "polyglot" ], - "downloads": 321718, + "downloads": 323765, "version": "13.5.0" }, { @@ -2228,7 +2228,7 @@ "dbx", "polyglot" ], - "downloads": 9375, + "downloads": 10159, "version": "13.5.0" }, { @@ -2245,7 +2245,7 @@ "deno", "polyglot" ], - "downloads": 70835, + "downloads": 70934, "version": "13.5.0" }, { @@ -2264,7 +2264,7 @@ "olap", "polyglot" ], - "downloads": 1508, + "downloads": 1513, "version": "13.5.0" }, { @@ -2282,7 +2282,7 @@ "elasticvue", "polyglot" ], - "downloads": 7188, + "downloads": 7271, "version": "13.5.0" }, { @@ -2301,7 +2301,7 @@ "openfeature", "polyglot" ], - "downloads": 25613, + "downloads": 25728, "version": "13.5.0" }, { @@ -2326,7 +2326,7 @@ "tls", "polyglot" ], - "downloads": 656, + "downloads": 705, "version": "13.5.0" }, { @@ -2368,7 +2368,7 @@ "migration", "polyglot" ], - "downloads": 50262, + "downloads": 50842, "version": "13.5.0" }, { @@ -2385,7 +2385,7 @@ "gofeatureflag", "polyglot" ], - "downloads": 48368, + "downloads": 48382, "version": "13.5.0" }, { @@ -2402,7 +2402,7 @@ "java", "polyglot" ], - "downloads": 77912, + "downloads": 77993, "version": "13.5.0" }, { @@ -2423,7 +2423,7 @@ "npm", "polyglot" ], - "downloads": 166515, + "downloads": 167540, "version": "13.5.0" }, { @@ -2442,7 +2442,7 @@ "cluster", "polyglot" ], - "downloads": 1398, + "downloads": 1439, "version": "13.5.0" }, { @@ -2459,7 +2459,7 @@ "k6", "polyglot" ], - "downloads": 63425, + "downloads": 63604, "version": "13.5.0" }, { @@ -2478,7 +2478,7 @@ "extensions", "polyglot" ], - "downloads": 17685, + "downloads": 17801, "version": "13.5.1-beta.748" }, { @@ -2499,7 +2499,7 @@ "podman", "polyglot" ], - "downloads": 799, + "downloads": 809, "version": "13.5.1-beta.748" }, { @@ -2516,7 +2516,7 @@ "kurrentdb", "polyglot" ], - "downloads": 17407, + "downloads": 17457, "version": "13.5.0" }, { @@ -2533,7 +2533,7 @@ "lavinmq", "polyglot" ], - "downloads": 49346, + "downloads": 49492, "version": "13.5.0" }, { @@ -2553,7 +2553,7 @@ "marketing", "polyglot" ], - "downloads": 890, + "downloads": 901, "version": "13.5.0" }, { @@ -2573,7 +2573,7 @@ "extensions", "polyglot" ], - "downloads": 1391, + "downloads": 1395, "version": "13.5.0" }, { @@ -2591,7 +2591,7 @@ "hosting", "polyglot" ], - "downloads": 363748, + "downloads": 366293, "version": "13.5.0" }, { @@ -2610,7 +2610,7 @@ "hosting", "polyglot" ], - "downloads": 70999, + "downloads": 71240, "version": "13.5.0" }, { @@ -2627,7 +2627,7 @@ "meilisearch", "polyglot" ], - "downloads": 72928, + "downloads": 73029, "version": "13.5.0" }, { @@ -2647,7 +2647,7 @@ "deprecated", "polyglot" ], - "downloads": 183255, + "downloads": 184202, "version": "13.5.0" }, { @@ -2665,7 +2665,7 @@ "dbgate", "polyglot" ], - "downloads": 85358, + "downloads": 85609, "version": "13.5.0" }, { @@ -2684,7 +2684,7 @@ "messaging", "polyglot" ], - "downloads": 377, + "downloads": 382, "version": "13.5.0" }, { @@ -2702,7 +2702,7 @@ "dbgate", "polyglot" ], - "downloads": 46399, + "downloads": 46497, "version": "13.5.0" }, { @@ -2720,7 +2720,7 @@ "tunnels", "polyglot" ], - "downloads": 193802, + "downloads": 195976, "version": "13.5.0" }, { @@ -2738,7 +2738,7 @@ "ai", "polyglot" ], - "downloads": 385645, + "downloads": 387575, "version": "13.5.0" }, { @@ -2756,7 +2756,7 @@ "observability", "polyglot" ], - "downloads": 62679, + "downloads": 63296, "version": "13.5.0" }, { @@ -2774,7 +2774,7 @@ "hosting", "polyglot" ], - "downloads": 61910, + "downloads": 61974, "version": "13.5.0" }, { @@ -2791,7 +2791,7 @@ "perl", "polyglot" ], - "downloads": 1934, + "downloads": 1949, "version": "13.5.0" }, { @@ -2811,7 +2811,7 @@ "delivery", "polyglot" ], - "downloads": 400, + "downloads": 407, "version": "13.5.0" }, { @@ -2829,7 +2829,7 @@ "dbgate", "polyglot" ], - "downloads": 108470, + "downloads": 108894, "version": "13.5.0" }, { @@ -2849,7 +2849,7 @@ "hosting", "polyglot" ], - "downloads": 65736, + "downloads": 65949, "version": "13.5.0" }, { @@ -2867,7 +2867,7 @@ "python", "polyglot" ], - "downloads": 77637, + "downloads": 77668, "version": "13.5.0" }, { @@ -2884,7 +2884,7 @@ "ravendb", "polyglot" ], - "downloads": 71273, + "downloads": 71400, "version": "13.5.0" }, { @@ -2902,7 +2902,7 @@ "dbgate", "polyglot" ], - "downloads": 77971, + "downloads": 78170, "version": "13.5.0" }, { @@ -2922,7 +2922,7 @@ "messaging", "polyglot" ], - "downloads": 442, + "downloads": 453, "version": "13.5.0" }, { @@ -2939,7 +2939,7 @@ "rust", "polyglot" ], - "downloads": 70326, + "downloads": 70420, "version": "13.5.0" }, { @@ -2958,7 +2958,7 @@ "s3-compatible", "polyglot" ], - "downloads": 2467, + "downloads": 2533, "version": "13.5.0" }, { @@ -2978,7 +2978,7 @@ "s3", "polyglot" ], - "downloads": 1706, + "downloads": 1738, "version": "13.5.0" }, { @@ -2996,7 +2996,7 @@ "hosting", "polyglot" ], - "downloads": 9712, + "downloads": 9803, "version": "13.5.0" }, { @@ -3014,7 +3014,7 @@ "search", "polyglot" ], - "downloads": 15058, + "downloads": 15093, "version": "13.5.0" }, { @@ -3032,7 +3032,7 @@ "sqlproj", "polyglot" ], - "downloads": 342371, + "downloads": 344980, "version": "13.5.0" }, { @@ -3050,7 +3050,7 @@ "sqlite", "polyglot" ], - "downloads": 93354, + "downloads": 93503, "version": "13.5.0" }, { @@ -3068,7 +3068,7 @@ "dbgate", "polyglot" ], - "downloads": 215777, + "downloads": 217138, "version": "13.5.0" }, { @@ -3088,7 +3088,7 @@ "copilot", "polyglot" ], - "downloads": 1222, + "downloads": 1248, "version": "13.5.0" }, { @@ -3108,7 +3108,7 @@ "huggingface", "polyglot" ], - "downloads": 370, + "downloads": 375, "version": "13.5.0" }, { @@ -3127,7 +3127,7 @@ "webhooks", "polyglot" ], - "downloads": 12583, + "downloads": 12624, "version": "13.5.0" }, { @@ -3144,7 +3144,7 @@ "surrealdb", "polyglot" ], - "downloads": 22019, + "downloads": 22045, "version": "13.5.0" }, { @@ -3161,7 +3161,7 @@ "umami", "polyglot" ], - "downloads": 2367, + "downloads": 2379, "version": "13.5.0" }, { @@ -3183,7 +3183,7 @@ "oidc", "polyglot" ], - "downloads": 2384, + "downloads": 2401, "version": "13.5.0" }, { @@ -3199,7 +3199,7 @@ "kurrentdb", "client" ], - "downloads": 12636, + "downloads": 12689, "version": "13.5.0" }, { @@ -3218,7 +3218,7 @@ "oidc", "jwt" ], - "downloads": 1388, + "downloads": 1393, "version": "13.5.0" }, { @@ -3235,7 +3235,7 @@ "masstransit", "rabbitmq" ], - "downloads": 83500, + "downloads": 83679, "version": "13.5.0" }, { @@ -3251,7 +3251,7 @@ "meilisearch", "client" ], - "downloads": 83365, + "downloads": 83514, "version": "13.5.0" }, { @@ -3269,7 +3269,7 @@ "data", "ado.net" ], - "downloads": 56177, + "downloads": 56213, "version": "13.5.0" }, { @@ -3290,7 +3290,7 @@ "ef", "orm" ], - "downloads": 65782, + "downloads": 65804, "version": "9.7.2" }, { @@ -3309,7 +3309,7 @@ "storage", "deprecated" ], - "downloads": 85700, + "downloads": 85989, "version": "13.5.0" }, { @@ -3327,7 +3327,7 @@ "ollamasharp", "client" ], - "downloads": 474876, + "downloads": 477018, "version": "13.5.0" }, { @@ -3344,7 +3344,7 @@ "email", "client" ], - "downloads": 369, + "downloads": 374, "version": "13.5.0" }, { @@ -3360,7 +3360,7 @@ "client", "ravendb" ], - "downloads": 71525, + "downloads": 71563, "version": "13.5.0" }, { @@ -3379,7 +3379,7 @@ "storage", "s3" ], - "downloads": 1057, + "downloads": 1068, "version": "13.5.0" }, { @@ -3395,7 +3395,7 @@ "sftp", "client" ], - "downloads": 4570, + "downloads": 4586, "version": "13.5.0" }, { @@ -3411,7 +3411,7 @@ "surrealdb", "client" ], - "downloads": 21293, + "downloads": 21300, "version": "13.5.0" } ] \ No newline at end of file diff --git a/src/frontend/src/data/github-stats.json b/src/frontend/src/data/github-stats.json index ccf11abab..79e944efa 100644 --- a/src/frontend/src/data/github-stats.json +++ b/src/frontend/src/data/github-stats.json @@ -1,7 +1,7 @@ [ { "name": "microsoft/aspire", - "stars": 6294, + "stars": 6298, "description": "Aspire is the tool for code-first, extensible, observable dev and deploy.", "license": "https://github.com/microsoft/aspire/blob/main/LICENSE.TXT", "licenseName": "MIT License", @@ -17,7 +17,7 @@ }, { "name": "CommunityToolkit/Aspire", - "stars": 626, + "stars": 627, "description": "A community project with additional components and extensions for Aspire", "license": "https://github.com/CommunityToolkit/Aspire/blob/main/LICENSE", "licenseName": "MIT License", From 507be4bb33795ebe563fd75cd9fa0e868791058e Mon Sep 17 00:00:00 2001 From: David Pine Date: Fri, 11 Sep 2026 06:39:46 -0500 Subject: [PATCH 12/29] Improve search discoverability and agent-readable content (#1633) * feat: improve search and agent discoverability Restore page-specific descriptions, publish useful homepage Markdown, strengthen observability guidance, and defer inactive AppHost examples. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix: keep mobile homepage within layout budget Tighten spacing in the expanded observability section so the production mobile viewport remains within the existing compactness gate. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix: align agent docs and search indexing Document authenticated standalone MCP with an explicit API key and keep deferred AppHost examples out of the homepage Pagefind index. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/frontend/astro.config.mjs | 6 +- src/frontend/config/apphost-examples.mjs | 53 ++++++ ...spire-version-placeholders-integration.mjs | 30 +++- src/frontend/config/head.attrs.ts | 8 - src/frontend/config/homepage-markdown.mjs | 111 +++++++++++++ .../src/components/AppHostBuilder.astro | 14 +- .../src/components/AppHostBuilder.client.ts | 51 +++++- .../src/components/home/HomePage.astro | 49 ++++-- .../app-host/migrate-from-docker-compose.mdx | 34 ++-- .../docs/dashboard/ai-coding-agents.mdx | 113 ++++++++++--- .../src/content/docs/dashboard/overview.mdx | 22 +-- .../docs/dashboard/standalone-for-nodejs.mdx | 14 +- .../docs/dashboard/standalone-for-python.mdx | 13 +- .../src/content/docs/dashboard/standalone.mdx | 24 ++- .../content/docs/fundamentals/telemetry.mdx | 20 ++- .../docs/get-started/ai-coding-agents.mdx | 15 +- .../docs/get-started/aspire-mcp-server.mdx | 9 +- .../cli/commands/aspire-agent-mcp.mdx | 12 +- src/frontend/src/content/i18n/da.json | 6 +- src/frontend/src/content/i18n/de.json | 6 +- src/frontend/src/content/i18n/en.json | 8 +- src/frontend/src/content/i18n/es.json | 6 +- src/frontend/src/content/i18n/fr.json | 6 +- src/frontend/src/content/i18n/hi.json | 6 +- src/frontend/src/content/i18n/id.json | 6 +- src/frontend/src/content/i18n/it.json | 6 +- src/frontend/src/content/i18n/ja.json | 6 +- src/frontend/src/content/i18n/ko.json | 6 +- src/frontend/src/content/i18n/pt-BR.json | 6 +- src/frontend/src/content/i18n/ru.json | 6 +- src/frontend/src/content/i18n/tr.json | 6 +- src/frontend/src/content/i18n/uk.json | 6 +- src/frontend/src/content/i18n/zh-CN.json | 6 +- src/frontend/src/utils/page-metadata.ts | 15 +- .../tests/e2e/api-markdown-routes.spec.ts | 25 ++- .../tests/e2e/custom-components.spec.ts | 106 ++++++++++++ src/frontend/tests/e2e/homepage.spec.ts | 18 +++ src/frontend/tests/e2e/og-metadata.spec.ts | 83 ++++++++++ src/frontend/tests/e2e/site-search.spec.ts | 19 +++ .../unit/apphost-examples.vitest.test.ts | 54 +++++++ .../unit/custom-components.vitest.test.ts | 1 + .../dashboard-agent-commands.vitest.test.ts | 29 ++++ .../unit/homepage-markdown.vitest.test.ts | 151 ++++++++++++++++++ 43 files changed, 1037 insertions(+), 154 deletions(-) create mode 100644 src/frontend/config/apphost-examples.mjs create mode 100644 src/frontend/config/homepage-markdown.mjs create mode 100644 src/frontend/tests/unit/apphost-examples.vitest.test.ts create mode 100644 src/frontend/tests/unit/dashboard-agent-commands.vitest.test.ts create mode 100644 src/frontend/tests/unit/homepage-markdown.vitest.test.ts diff --git a/src/frontend/astro.config.mjs b/src/frontend/astro.config.mjs index 7dde136ed..33b675142 100644 --- a/src/frontend/astro.config.mjs +++ b/src/frontend/astro.config.mjs @@ -29,6 +29,8 @@ import Icons from 'starlight-plugin-icons'; const modeArgIndex = process.argv.indexOf('--mode'); const isSkipSearchBuild = modeArgIndex >= 0 && process.argv[modeArgIndex + 1] === 'skip-search'; const isBuildTimingEnabled = process.env.BUILD_TIMING === '1'; +const siteDescription = + 'Aspire is a multi-language local dev-time orchestration tool chain for building, running, debugging, and deploying distributed applications.'; // Astro renders pages mostly on the main JS thread. Default `build.concurrency` // is 1, so a multi-vCPU CI runner is largely idle during the generate phase. @@ -61,6 +63,7 @@ export default defineConfig({ starlight: { pagefind: !isSkipSearchBuild, title: 'Aspire', + description: siteDescription, routeMiddleware: ['./src/route-data-middleware'], defaultLocale: 'root', locales, @@ -150,8 +153,7 @@ export default defineConfig({ starlightGitHubAlerts(), starlightLlmsTxt({ projectName: 'Aspire', - description: - 'Aspire is a multi-language local dev-time orchestration tool chain for building, running, debugging, and deploying distributed applications.', + description: siteDescription, // Strip transient annotations injected by expressive-code-twoslash from the // rendered HTML before it's converted back to Markdown. Without this, the // TypeScript hover popovers (type signatures, JSDoc, error boxes, etc.) diff --git a/src/frontend/config/apphost-examples.mjs b/src/frontend/config/apphost-examples.mjs new file mode 100644 index 000000000..1e42a27ae --- /dev/null +++ b/src/frontend/config/apphost-examples.mjs @@ -0,0 +1,53 @@ +import { createHash } from 'node:crypto'; +import { select, selectAll } from 'hast-util-select'; +import rehypeParse from 'rehype-parse'; +import { unified } from 'unified'; + +/** + * Move the builder's highlighted examples to one lazy-loaded static file. + * @param {string} html + * @returns {{ html: string; examples: string; filename: string }} + */ +export function deferAppHostExamples(html) { + const tree = unified().use(rehypeParse).parse(html); + const builder = select('[data-apphost-builder]', tree); + const groups = selectAll('[data-apphost-builder] .code-lang-group', tree); + const initial = select( + '[data-apphost-builder] [data-code-lang="typescript"] [data-variant="frontend"]', + tree + ); + if (!builder || groups.length !== 2 || !initial) { + throw new Error('Cannot defer AppHost examples: missing builder or default example.'); + } + + const source = (node) => html.slice(node.position.start.offset, node.position.end.offset); + const sourceWithoutCopyControls = (node) => { + let markup = source(node); + for (const copy of selectAll('.copy', node).toReversed()) { + const start = copy.position.start.offset - node.position.start.offset; + const end = copy.position.end.offset - node.position.start.offset; + markup = markup.slice(0, start) + markup.slice(end); + } + return markup; + }; + const examples = groups.map(sourceWithoutCopyControls).join('\n'); + const hash = createHash('sha256').update(examples).digest('hex').slice(0, 16); + const filename = `apphost-examples.${hash}.html`; + + // Edit the original source ranges so unrelated homepage markup stays byte-identical. + for (const group of groups.toReversed()) { + const start = group.position.start.offset; + const openingTag = html.slice(start, html.indexOf('>', start) + 1); + const body = + group.properties.dataCodeLang === 'typescript' ? sourceWithoutCopyControls(initial) : ''; + html = + html.slice(0, start) + openingTag + body + '
' + html.slice(group.position.end.offset); + } + const attributeOffset = builder.position.start.offset + builder.tagName.length + 1; + html = + html.slice(0, attributeOffset) + + ` data-apphost-examples="/_astro/${filename}"` + + html.slice(attributeOffset); + + return { html, examples, filename }; +} diff --git a/src/frontend/config/aspire-version-placeholders-integration.mjs b/src/frontend/config/aspire-version-placeholders-integration.mjs index 0bc1197c3..9afb037bc 100644 --- a/src/frontend/config/aspire-version-placeholders-integration.mjs +++ b/src/frontend/config/aspire-version-placeholders-integration.mjs @@ -3,12 +3,15 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { replaceAspireVersionPlaceholders } from './remark-aspire-version-placeholders.mjs'; import { orderTypeScriptFirstAppHostTabsInMarkdown } from './remark-typescript-first-apphost-tabs.mjs'; +import { renderHomepageMarkdown } from './homepage-markdown.mjs'; +import { locales } from './locales.ts'; +import { deferAppHostExamples } from './apphost-examples.mjs'; // Per-page Markdown copies emitted by `starlight-page-actions` bypass the // remark transforms that replace Aspire version placeholders and order AppHost // language tabs: // that plugin `viteStaticCopy`s `src/content/docs/**/*.{md,mdx}` straight to -// `dist/**/*.md` through a regex-only transform, so it never runs through the +// `dist/**/*.md` through source cleanup, so it never runs through the // configured remark pipeline. // // Everything else is already handled before it reaches `dist`: @@ -17,10 +20,9 @@ import { orderTypeScriptFirstAppHostTabsInMarkdown } from './remark-typescript-f // - `llms*.txt` -> `starlight-llms-txt` sources rendered HTML (`render(entry)`) // - `reference/**.md` -> generated from API/sample data, not docs content // -// So this post-build pass only needs to touch `.md` files. Scoping it this way -// (instead of walking every `.html`/`.txt` in `dist`) avoids re-reading the bulk -// of the output — including the large `llms-full.txt` assets — which is what -// previously exhausted the Node heap. +// Version normalization only walks `.md` files. The homepage finalization +// below also reads the known homepage HTML files, not every `.html`/`.txt` +// asset in `dist`, which previously exhausted the Node heap. const markdownCopyExtensions = new Set(['.md']); // Process the Markdown copies through a small worker pool rather than a single @@ -33,7 +35,23 @@ export function aspireVersionPlaceholdersIntegration() { name: 'aspire-version-placeholders', hooks: { 'astro:build:done': async ({ dir }) => { - await replaceAspireVersionPlaceholdersInDirectory(fileURLToPath(dir)); + const directory = fileURLToPath(dir); + // Page-actions copies raw MDX, so component-only homepages need their + // rendered content instead. Ordinary documentation keeps its existing path. + for (const locale of Object.keys(locales)) { + const localePath = locale === 'root' ? '' : locale; + const html = await readFile(path.join(directory, localePath, 'index.html'), 'utf8'); + const markdown = await renderHomepageMarkdown(html); + await writeFile(path.join(directory, `${localePath || 'index'}.md`), markdown, 'utf8'); + const deferred = deferAppHostExamples(html); + await writeFile( + path.join(directory, '_astro', deferred.filename), + deferred.examples, + 'utf8' + ); + await writeFile(path.join(directory, localePath, 'index.html'), deferred.html, 'utf8'); + } + await replaceAspireVersionPlaceholdersInDirectory(directory); }, }, }; diff --git a/src/frontend/config/head.attrs.ts b/src/frontend/config/head.attrs.ts index 960bc0b17..32b32feb0 100644 --- a/src/frontend/config/head.attrs.ts +++ b/src/frontend/config/head.attrs.ts @@ -6,14 +6,6 @@ export type HeadAttr = { export const headAttrs: HeadAttr[] = [ // SEO meta tags for discoverability (including legacy ".NET Aspire" branding) - { - tag: 'meta', - attrs: { - name: 'description', - content: - 'Aspire is a multi-language local dev-time orchestration tool chain for building, running, debugging, and deploying distributed applications.', - }, - }, { tag: 'meta', attrs: { diff --git a/src/frontend/config/homepage-markdown.mjs b/src/frontend/config/homepage-markdown.mjs new file mode 100644 index 000000000..b8e802205 --- /dev/null +++ b/src/frontend/config/homepage-markdown.mjs @@ -0,0 +1,111 @@ +import { select, selectAll } from 'hast-util-select'; +import rehypeParse from 'rehype-parse'; +import rehypeRemark from 'rehype-remark'; +import remarkGfm from 'remark-gfm'; +import remarkStringify from 'remark-stringify'; +import { unified } from 'unified'; +import { remove } from 'unist-util-remove'; + +const decorativeContent = [ + 'script', + 'style', + 'svg', + 'button', + 'input', + 'label', + 'img[alt=""]', + 'i[aria-hidden="true"]', + 'span[aria-hidden="true"]', + '.home-hero-eyebrow', + '.section-index > span', + '.principle-number', + '.quote-mark', + '.model-terminal', + '.model-graph', + '[data-model-dashboard]', + '.dashboard-stage', + '.agent-visual', + '.environment-topology', + '.environment-stage-bar', + '[data-home-integration-rail]', + '.agent-badge-popover > strong', +].join(', '); + +/** + * Convert the homepage's authored content, not its animated demonstrations. + * @param {string} html + * @returns {Promise} + */ +export async function renderHomepageMarkdown(html) { + const tree = unified().use(rehypeParse).parse(html); + const hero = select('main .home-hero-copy', tree); + const content = select('main .aspire-home', tree); + if (!hero || !content || !select('h1', hero)) { + throw new Error('Cannot export homepage Markdown: missing homepage content landmarks.'); + } + + tree.children = [hero, content]; + const decorativeNodes = new Set(selectAll(decorativeContent, tree)); + remove(tree, (node) => node.type === 'comment' || decorativeNodes.has(node)); + + for (const actions of selectAll( + '.home-hero-actions, .observability-links, .closing-actions', + tree + )) { + const links = selectAll('a', actions); + actions.tagName = 'ul'; + actions.children = links.map((link) => ({ + type: 'element', + tagName: 'li', + properties: {}, + children: [link], + })); + } + for (const command of selectAll('.environment-command', tree)) { + command.tagName = 'ul'; + command.children = command.children + .filter((child) => child.type === 'element') + .map((child) => ({ + type: 'element', + tagName: 'li', + properties: {}, + children: [child], + })); + } + for (const caption of selectAll('.testimonial figcaption', tree)) { + const name = select('strong', caption); + const attribution = select('small', caption); + if (name && attribution) { + caption.children = [name, { type: 'text', value: ' — ' }, ...attribution.children]; + } + } + + // These are meaningful examples and environment descriptions, even when + // the interactive homepage initially hides their tab or animation stage. + for (const element of selectAll('[hidden], [aria-hidden]', tree)) { + delete element.properties.hidden; + delete element.properties.ariaHidden; + } + for (const pre of selectAll('pre[data-language]', tree)) { + const code = select('code', pre); + if (code) { + code.properties.className = [`language-${pre.properties.dataLanguage}`]; + const lines = selectAll('.ec-line .code', code); + if (lines.length > 0) { + code.children = [ + { + type: 'text', + value: lines.map((line) => textContent(line).replace(/\n/g, '')).join('\n'), + }, + ]; + } + } + } + + const processor = unified().use(rehypeRemark).use(remarkGfm).use(remarkStringify); + return processor.stringify(await processor.run(tree)); +} + +function textContent(node) { + return node.type === 'text' ? node.value : (node.children ?? []).map(textContent).join(''); +} diff --git a/src/frontend/src/components/AppHostBuilder.astro b/src/frontend/src/components/AppHostBuilder.astro index e3d8f7d23..79d81f61f 100644 --- a/src/frontend/src/components/AppHostBuilder.astro +++ b/src/frontend/src/components/AppHostBuilder.astro @@ -1022,7 +1022,12 @@ await builder.build().run();`, }; --- -
+
{heading} {description &&

{description}

} @@ -1092,7 +1097,12 @@ await builder.build().run();`,
-
+
diff --git a/src/frontend/src/components/AppHostBuilder.client.ts b/src/frontend/src/components/AppHostBuilder.client.ts index 757ffab63..9ad6eb425 100644 --- a/src/frontend/src/components/AppHostBuilder.client.ts +++ b/src/frontend/src/components/AppHostBuilder.client.ts @@ -148,11 +148,16 @@ function initializeAppHostBuilder(root: HTMLElement): void { let processing = false; let caretLineIndex = 0; let caretColumn = 0; - - const getTemplate = (language: AppHostLanguage, variant: string): HTMLElement | undefined => - root.querySelector( - `.code-lang-group[data-code-lang="${language}"] .code-variant[data-variant="${variant}"]` - ) ?? undefined; + const examples = document.createElement('template'); + + const getTemplate = (language: AppHostLanguage, variant: string): HTMLElement | undefined => { + const selector = `.code-lang-group[data-code-lang="${language}"] .code-variant[data-variant="${variant}"]`; + return ( + root.querySelector(selector) ?? + examples.content.querySelector(selector) ?? + undefined + ); + }; const setEditorState = (state: EditorState) => { stage.dataset.editorState = state; @@ -518,6 +523,34 @@ function initializeAppHostBuilder(root: HTMLElement): void { processing = true; codeDisplay.setAttribute('aria-busy', 'true'); + const examplesUrl = root.dataset.apphostExamples; + if (examplesUrl && !examples.content.childElementCount) { + try { + const response = await fetch(examplesUrl); + if (!response.ok) { + throw new Error(`AppHost examples request failed: ${response.status}`); + } + const content = await response.text(); + const parsed = document.createElement('template'); + parsed.innerHTML = content; + if ( + !parsed.content.querySelector('[data-code-lang="csharp"] .code-variant') || + !parsed.content.querySelector('[data-code-lang="typescript"] .code-variant') + ) { + throw new Error('AppHost examples response does not contain both languages.'); + } + examples.content.append(parsed.content); + } catch (error) { + console.error('Could not load AppHost examples.', error); + status.textContent = root.dataset.examplesError ?? 'Could not load AppHost examples.'; + status.classList.remove('sr-only'); + codeDisplay.setAttribute('aria-busy', 'false'); + processing = false; + return; + } + } + status.classList.add('sr-only'); + try { while ( root.isConnected && @@ -617,7 +650,13 @@ function initializeAppHostBuilder(root: HTMLElement): void { languageButtons.forEach((button) => { button.addEventListener('click', () => { const language = button.dataset.lang; - if (!isAppHostLanguage(language) || desiredLanguage === language) return; + if (!isAppHostLanguage(language)) return; + if (desiredLanguage === language) { + if (currentLanguage !== desiredLanguage || currentVariant !== desiredVariant) { + void processRequestedState(); + } + return; + } languageButtons.forEach((candidate) => { const isSelected = candidate === button; diff --git a/src/frontend/src/components/home/HomePage.astro b/src/frontend/src/components/home/HomePage.astro index 85004e018..3f5523eb8 100644 --- a/src/frontend/src/components/home/HomePage.astro +++ b/src/frontend/src/components/home/HomePage.astro @@ -592,15 +592,26 @@ const localizedPrinciples = principles.map((principle) => ({ description={t('home.observability.badgeDescription')} align="center" /> - - {t('home.observability.link')} - - +
({ } .dashboard-heading .text-link { - margin-top: 1.35rem; color: var(--home-purple); } + .observability-links { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.5rem 1.5rem; + margin-top: 1.35rem; + } + .dashboard-stage { width: min(100%, 82rem); margin: clamp(3rem, 5vw, 4.25rem) auto 0; @@ -3136,6 +3154,15 @@ const localizedPrinciples = principles.map((principle) => ({ padding: 3.5rem 1rem; } + .home-dashboard { + padding-block: 2.25rem; + } + + .observability-links { + gap: 0.25rem 1rem; + margin-top: 0.75rem; + } + .model-focus-border { display: none; } @@ -3239,7 +3266,7 @@ const localizedPrinciples = principles.map((principle) => ({ } .dashboard-stage { - margin-top: 3rem; + margin-top: 2rem; border-radius: 0.75rem; } diff --git a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx index 5fb84b651..249a48645 100644 --- a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx +++ b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx @@ -1,37 +1,39 @@ --- title: Migrate from Docker Compose to Aspire -description: Migrate your Docker Compose applications to Aspire — map services, volumes, networks, and environment variables to AppHost APIs and modernize your developer workflow. +description: Compare Aspire and Docker Compose for local development, service discovery, and observability. Map Compose services and dependencies to TypeScript or C# AppHosts. --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; -This guide helps you understand how to migrate applications from Docker Compose to Aspire, highlighting the key conceptual differences and providing accurate, practical examples for common migration scenarios. +Docker Compose and Aspire both describe and run multi-service applications. This guide compares their local development workflows and maps Compose services, dependencies, and configuration to an Aspire AppHost written in TypeScript or C#. ## Understand the differences -While Docker Compose and Aspire might seem similar at first glance, they serve different purposes and operate at different levels of abstraction. +Keep Docker Compose when a container-focused YAML workflow meets your needs. Consider Aspire when you want to compose containers with processes running directly on the host, manage service references in code, and inspect application telemetry alongside resource health. ### Docker Compose vs Aspire -| | Docker Compose | Aspire | -|--|--|--| -| **Primary purpose** | Container orchestration | Development-time orchestration and app composition | -| **Scope** | Container-focused | Multi-resource (containers, .NET projects, cloud resources) | -| **Configuration** | YAML-based | C#-based, strongly typed | -| **Target environment** | Any Docker runtime | Development and cloud deployment | -| **Service discovery** | DNS-based container discovery | Built-in service discovery with environment variables | -| **Development experience** | Manual container management | Integrated tooling, dashboard, and telemetry | +| Feature | Docker Compose | Aspire | +| ------- | -------------- | ------ | +| **Primary purpose** | Define and run multi-container applications | Compose application resources for development and deployment | +| **Scope** | Containers | Containers, Python and Node.js apps, .NET projects, executables, and cloud resources | +| **Configuration** | Declarative YAML | Strongly typed TypeScript or C# AppHost | +| **Target environment** | Docker environments | Local development and deployment through publishing integrations, including Docker Compose | +| **Service discovery** | Service names and DNS on Compose networks | Service references and connection information passed to resources | +| **Local observability** | Container logs and health checks; add OpenTelemetry tooling for application telemetry | Integrated resource health, console logs, and an OpenTelemetry dashboard; application instrumentation is still required | ### Key conceptual shifts When migrating from Docker Compose to Aspire, consider these conceptual differences: -- **From YAML to C#** — Configuration moves from declarative YAML to imperative, strongly-typed C# code -- **From containers to resources** — Aspire manages not just containers, but .NET projects, executables, parameters, and cloud resources -- **From manual networking to service discovery** — Aspire automatically configures service discovery and connection strings -- **From development gaps to integrated experience** — Aspire provides dashboard, telemetry, and debugging integration -- **Startup orchestration differs** — Docker Compose `depends_on` controls startup order, while Aspire `WithReference` only configures service discovery; use `WaitFor` for startup ordering +- **From YAML to an AppHost** — Express configuration in strongly typed TypeScript or C# code +- **From containers to resources** — Compose containers with local application processes, parameters, and cloud resources +- **From container DNS to resource references** — Pass service endpoints and connection information to dependent resources +- **From separate tools to a shared dashboard** — Inspect resource health and instrumented application logs, traces, and metrics together +- **Startup orchestration differs** — Compose `depends_on` supports startup order and health conditions; Aspire references supply connection information, while wait relationships control startup dependencies + +You don't need to migrate orchestration just to view OpenTelemetry. Point instrumented Compose services at the [standalone Aspire dashboard](/dashboard/standalone/) to inspect logs, traces, and metrics, including through [coding-agent CLI or MCP workflows](/dashboard/ai-coding-agents/#standalone-mode). Standalone mode doesn't add AppHost resource controls to Compose. For detailed API mappings, see [Docker Compose to Aspire AppHost API reference](/app-host/docker-compose-to-apphost-reference/). diff --git a/src/frontend/src/content/docs/dashboard/ai-coding-agents.mdx b/src/frontend/src/content/docs/dashboard/ai-coding-agents.mdx index 1b36b157a..3816a7f46 100644 --- a/src/frontend/src/content/docs/dashboard/ai-coding-agents.mdx +++ b/src/frontend/src/content/docs/dashboard/ai-coding-agents.mdx @@ -1,16 +1,15 @@ --- -title: AI coding agents and the Aspire Dashboard -seoTitle: Aspire dashboard and AI coding agents for distributed apps -description: Learn how AI coding agents use the Aspire CLI and MCP server to read logs and telemetry from the Aspire dashboard, diagnose failures, and propose code changes. +title: Debug app failures with AI coding agents +description: Investigate a local request failure using the same application logs, traces, and resource health in the Aspire dashboard and coding-agent CLI or MCP tools. --- -import { Aside, Steps } from '@astrojs/starlight/components'; +import { Steps } from '@astrojs/starlight/components'; -AI coding agents can use the [Aspire CLI](/reference/cli/overview/) and [Aspire MCP server](/get-started/aspire-mcp-server/) to fetch logs and telemetry from the Aspire dashboard. This gives agents the same observability data that developers see in the dashboard UI — structured logs, distributed traces, resource status, and console output — so they can diagnose issues, verify fixes, and add new features with full context. +Give a coding agent the same application evidence you inspect in the Aspire dashboard: resource status and health, console output, structured logs, and distributed traces. Use it to diagnose local request failures and verify fixes, not to monitor the agent's reasoning or token usage. Start with [Aspire skills](/get-started/aspire-skills/) and the [Aspire CLI](/reference/cli/overview/); the [MCP server](/get-started/aspire-mcp-server/) is optional. ## How agents use dashboard data -When an Aspire app is running, the dashboard collects OpenTelemetry data from all resources. AI coding agents access this data through two channels: +When an Aspire app is running, the dashboard receives OpenTelemetry from instrumented applications and resource information from the AppHost. AI coding agents access this data through two channels: - **Aspire CLI** — Commands like [`aspire logs`](/reference/cli/commands/aspire-logs/), [`aspire otel logs`](/reference/cli/commands/aspire-otel-logs/), [`aspire otel traces`](/reference/cli/commands/aspire-otel-traces/), and [`aspire describe`](/reference/cli/commands/aspire-describe/) retrieve resource status, console logs, and telemetry directly from the terminal. All commands support `--format Json` for structured output that agents can parse. - **Aspire MCP server** — The [MCP server](/get-started/aspire-mcp-server/) exposes tools such as `list_resources`, `list_structured_logs`, `list_traces`, and `list_console_logs` that agents call directly through the Model Context Protocol. @@ -31,20 +30,80 @@ The following workflow is an example — [Aspire skills](/get-started/aspire-ski +## Investigate one failed request together + +This exercise uses the existing [FastAPI weather sample](https://github.com/microsoft/aspire-samples/tree/383d5d025b53ac37cd4dd86f50a036ccf39f76f5/samples/aspire-with-python), pinned to revision `383d5d0`. It runs a Python API named `app`, Redis named `cache`, and a React frontend. The sample uses a C# AppHost; the inspection commands also work with TypeScript AppHosts. + +Use a separate local copy of the [pinned sample source](https://github.com/microsoft/aspire-samples/archive/383d5d025b53ac37cd4dd86f50a036ccf39f76f5.zip), not an application someone else is using. Follow the sample's prerequisites: the Aspire CLI, .NET 10 SDK, Python 3.13 or later, Node.js 22.21.1 or later, and a running container runtime. Install [uv](https://docs.astral.sh/uv/getting-started/installation/) for the Python package setup. Keep dashboard authentication enabled and don't share login tokens or runtime credentials with the agent. + + + +1. Open a terminal in the sample's `aspire-with-python` directory and start an isolated instance: + + ```bash title="Start only the sample AppHost" + aspire start --apphost apphost.cs --isolated + aspire wait app --apphost apphost.cs + aspire describe app --apphost apphost.cs --format Json + ``` + + Open the dashboard login URL printed by `aspire start`. Find the `app` endpoint on **Resources**, then visit `/api/weatherforecast` at that endpoint. The baseline request returns HTTP 200 and five synthetic forecasts. If your terminal doesn't resolve the generated `.dev.localhost` hostname, use the `localhost` endpoint alias in `aspire describe`. + +1. In the `app` directory's `main.py`, temporarily change `random.randint(-20, 55)` to `random.randint(55, -20)`. This reverses the valid temperature range. Restart only the Python resource: + + ```bash title="Restart the sample API" + aspire resource app restart --apphost apphost.cs + aspire wait app --apphost apphost.cs + ``` + + Wait for the sample's five-second forecast cache to expire, then request `/api/weatherforecast` again. It returns HTTP 500 even though `app` is running and its `/health` check passes. + +1. Investigate as a human. In **Console**, select `app` and find the `ValueError` stack trace pointing to `random.randint(55, -20)`. In **Traces**, open `GET /api/weatherforecast` at the failure's timestamp. Its server span has error status and HTTP 500; the Redis `GET` span succeeds. Copy the trace ID so the agent can inspect this exact request, rather than an unrelated health-check trace. + + The exception is in Uvicorn's console output. Don't assume every console line is also exported as a structured OpenTelemetry log. + +1. Ask the coding agent to investigate the same evidence: + + > In this sample directory, use `apphost.cs` to inspect the failed weather request with trace ID `` and the `app` console logs. Explain why the health check passes, propose the smallest fix, and verify the same request after the fix. + + The agent can query the same resource, console output, and trace: + + ```bash title="Query the evidence shown in the dashboard" + aspire describe app --apphost apphost.cs --format Json + aspire logs app --apphost apphost.cs --format Json + aspire otel traces app --apphost apphost.cs --has-error true --format Json + aspire otel traces --apphost apphost.cs --trace-id "" --format Json + ``` + + Replace `` with the ID from the dashboard. With optional MCP setup, `list_resources`, `list_console_logs`, and `list_traces` provide the corresponding evidence. + +1. Restore `random.randint(-20, 55)`, restart `app` with the commands above, and repeat `/api/weatherforecast`. Confirm HTTP 200 and five forecasts. In **Traces**, inspect the new request, or query it: + + ```bash title="Verify the new weather request" + aspire otel traces app --apphost apphost.cs --search "name:weatherforecast" --limit 1 --format Json + ``` + + The new trace has no error. Old failed traces remain in the dashboard; success means the repeated request now works, not that error history disappears. Stop only this sample when you're finished: + + ```bash title="Stop the sample AppHost" + aspire stop --apphost apphost.cs + ``` + + + ## Get started The fastest way to set up AI coding agents with Aspire is the `aspire agent init` command. See [Use AI coding agents](/get-started/ai-coding-agents/) for the full setup guide, including skill files, MCP server configuration, and supported AI assistants. ## Standalone mode -The Aspire CLI and MCP server work with the [standalone dashboard](/dashboard/standalone/) — you don't need an Aspire AppHost project. This is useful when monitoring any application that sends OpenTelemetry data to the dashboard. +The Aspire CLI and MCP server can query telemetry from the [standalone dashboard](/dashboard/standalone/) without an AppHost. This works with applications configured to send OTLP data, including [Python](/dashboard/standalone-for-python/) and [Node.js](/dashboard/standalone-for-nodejs/). Standalone telemetry doesn't provide AppHost process health or lifecycle commands. ### Start the standalone dashboard Start the dashboard using the Aspire CLI: ```bash title="Aspire CLI" -aspire dashboard run --allow-anonymous +aspire dashboard run ``` The dashboard starts with the following defaults: @@ -53,31 +112,35 @@ The dashboard starts with the following defaults: - **OTLP/gRPC** endpoint at `http://localhost:4317` - **OTLP/HTTP** endpoint at `http://localhost:4318` -:::caution -The `--allow-anonymous` flag starts the dashboard without authentication. Only use this on your local machine. See [Dashboard security considerations](/dashboard/security-considerations/#anonymous-access) for more information. -::: +Keep the default browser-token authentication. The CLI prints a login URL; use it locally and don't commit or share its token. See [Dashboard security considerations](/dashboard/security-considerations/). ### Use Aspire CLI with the standalone dashboard -Pass `--dashboard-url` with the full frontend URL to point CLI commands at a standalone dashboard: +Pass the full login URL through `--dashboard-url` to point CLI commands at the standalone dashboard. The CLI exchanges the browser token for an API key: ```bash title="Aspire CLI" -aspire otel logs --dashboard-url "http://localhost:18888" -aspire otel traces --dashboard-url "http://localhost:18888" -aspire otel spans --dashboard-url "http://localhost:18888" +aspire otel logs --dashboard-url "http://localhost:18888/login?t=" +aspire otel traces --dashboard-url "http://localhost:18888/login?t=" +aspire otel spans --dashboard-url "http://localhost:18888/login?t=" ``` ### Use Aspire MCP with the standalone dashboard -Start the MCP server in dashboard-only mode using `--dashboard-url`: +The MCP command doesn't exchange the browser token from a dashboard login URL. To use dashboard-only MCP with authentication, start the dashboard with an explicit telemetry API key: + +```bash title="Aspire CLI" +aspire dashboard run --Dashboard:Api:AuthMode=ApiKey --Dashboard:Api:PrimaryApiKey="" +``` + +Then start the MCP server in a separate terminal with the dashboard base URL and the same key: ```bash title="Aspire CLI" -aspire agent mcp --dashboard-url "http://localhost:18888" +aspire agent mcp --dashboard-url "http://localhost:18888" --api-key "" ``` -This exposes the dashboard's telemetry tools (structured logs, traces, and resource data) to any MCP-compatible AI assistant. +This exposes the dashboard's telemetry tools to an MCP-compatible AI assistant, not the AppHost's resource-management tools. -Configuration is required in the agent to use the MCP server. For configuration details, see [Aspire MCP server configuration](/get-started/aspire-mcp-server/#configuration). The `--dashboard-url` must be passed as a command line argument when configuring the MCP server for standalone use. +Use a high-entropy key and don't commit or share it. Configuration is required in the agent to use the MCP server. For configuration details, see [Aspire MCP server configuration](/get-started/aspire-mcp-server/#configuration). For telemetry API security details, see [Secure the telemetry API endpoint](/dashboard/security-considerations/#telemetry-api-endpoint). ### Sample skill for standalone dashboard @@ -94,35 +157,37 @@ description: Use the Aspire standalone dashboard for observability. Start the da ## Start the dashboard ```bash -aspire dashboard run --allow-anonymous +aspire dashboard run ``` The dashboard UI is at http://localhost:18888. Apps should send OpenTelemetry to http://localhost:4317 (gRPC) or http://localhost:4318 (HTTP). +Keep authentication enabled and use the login URL printed by the CLI. ## Query telemetry View structured logs: ```bash -aspire otel logs --dashboard-url http://localhost:18888 +aspire otel logs --dashboard-url "http://localhost:18888/login?t=" ``` View distributed traces: ```bash -aspire otel traces --dashboard-url http://localhost:18888 +aspire otel traces --dashboard-url "http://localhost:18888/login?t=" ``` View trace spans: ```bash -aspire otel spans --dashboard-url http://localhost:18888 +aspire otel spans --dashboard-url "http://localhost:18888/login?t=" ``` ## Rules -- Ensure the dashboard has started querying telemetry. The dashboard may already be running. +- Check whether the dashboard is already running before starting it. +- Replace with the local login token; never commit or include it in reports. - Use `--format Json` with CLI commands when you need to parse the output. - Check `aspire otel logs` for errors after making code changes. - Use `aspire otel traces` to investigate cross-service latency. diff --git a/src/frontend/src/content/docs/dashboard/overview.mdx b/src/frontend/src/content/docs/dashboard/overview.mdx index 8777c3707..1089f459c 100644 --- a/src/frontend/src/content/docs/dashboard/overview.mdx +++ b/src/frontend/src/content/docs/dashboard/overview.mdx @@ -1,6 +1,6 @@ --- -title: Aspire dashboard overview and getting started -description: Overview of the Aspire dashboard — what it shows, how the AppHost wires it up, and how to start using it for telemetry, resource management, and debugging. +title: Aspire dashboard for local OpenTelemetry +description: View application logs, distributed traces, and metrics in the Aspire dashboard. Inspect local resource health with an AppHost or receive OTLP data standalone. --- import { Image } from 'astro:assets'; @@ -9,20 +9,20 @@ import projectsImage from '@assets/dashboard/explore/projects.png'; import architectureDiagramDark from '@assets/dashboard/architecture-diagram-dark.svg'; import architectureDiagramLight from '@assets/dashboard/architecture-diagram-light.svg'; -[Aspire](/get-started/what-is-aspire/) project templates include a sophisticated dashboard for comprehensive app monitoring and inspection. The dashboard is also available in [standalone mode](#standalone-mode). +The Aspire dashboard is a local OpenTelemetry viewer for application logs, distributed traces, and metrics. Use it to follow requests across instrumented services, find errors, and inspect timing without leaving your development environment. -The dashboard enables real-time tracking of key aspects of your app, including logs, traces, and environment configurations. It's designed to enhance the development experience by providing a clear and insightful view of your app's state and structure. +With an [Aspire AppHost](/get-started/app-host/), the dashboard also shows resource state, health checks, console output, and configuration. You can use the [standalone dashboard](#standalone-mode) to receive telemetry without adopting Aspire orchestration. Key features of the dashboard include: -- Real-time tracking of logs, traces, and environment configurations. -- User interface to [stop, start, and restart resources](/dashboard/explore/#resource-actions). -- Collects and displays logs and telemetry; [view structured logs, traces, and metrics](/dashboard/explore/#monitoring-pages) in an intuitive UI. -- Enhanced debugging with [AI coding agents](/dashboard/ai-coding-agents/) that use the Aspire CLI and MCP server to fetch logs and telemetry from the dashboard. +- [View structured logs, traces, and metrics](/dashboard/explore/#monitoring-pages) from apps configured to export OpenTelemetry. +- Follow a distributed trace across local services and correlate its logs. +- Inspect resource health and [stop, start, or restart resources](/dashboard/explore/#resource-actions) when connected to an AppHost. +- Share application observability data with [AI coding agents](/dashboard/ai-coding-agents/) through the Aspire CLI or optional MCP server. ## Use the dashboard with Aspire projects -The dashboard is integrated into the [Aspire _*.AppHost_](/get-started/app-host/). During development the dashboard is automatically launched when you start the project. It's configured to display the Aspire project's resources and telemetry. +The dashboard is integrated with [TypeScript and C# AppHosts](/get-started/app-host/). During development, starting your AppHost launches the dashboard and configures its connection to your resources. Applications still need instrumentation and an OpenTelemetry exporter to send telemetry. A screenshot of the Aspire dashboard Resources page. @@ -30,7 +30,7 @@ For more information about using the dashboard during Aspire development, see [E ## Standalone mode -The Aspire dashboard can run standalone, without the rest of Aspire. The standalone dashboard provides a great UI for viewing telemetry and can be used by any application that sends OpenTelemetry data. You can start it with the Aspire CLI or run it from the standalone container image. For more information, see the [Standalone Aspire dashboard](/dashboard/standalone/). +The standalone dashboard is an OTLP viewer for any application configured to send OpenTelemetry data, including [Python](/dashboard/standalone-for-python/) and [JavaScript on Node.js](/dashboard/standalone-for-nodejs/). Start it with the Aspire CLI or a container image. Standalone mode doesn't provide AppHost resource lifecycle controls; see [Standalone Aspire dashboard](/dashboard/standalone/) for setup and limitations. ## Configuration @@ -58,3 +58,5 @@ For more information, see [Aspire dashboard security considerations](/dashboard/ ## Next steps - [Explore the Aspire dashboard](/dashboard/explore/) +- [Understand OpenTelemetry and distributed tracing](/fundamentals/telemetry/) +- [Investigate application failures with a coding agent](/dashboard/ai-coding-agents/) diff --git a/src/frontend/src/content/docs/dashboard/standalone-for-nodejs.mdx b/src/frontend/src/content/docs/dashboard/standalone-for-nodejs.mdx index 2c87f0176..60c9f31ec 100644 --- a/src/frontend/src/content/docs/dashboard/standalone-for-nodejs.mdx +++ b/src/frontend/src/content/docs/dashboard/standalone-for-nodejs.mdx @@ -1,15 +1,17 @@ --- -title: Aspire dashboard standalone for Node.js apps -description: Use the Aspire dashboard standalone with Node.js applications — wire up OpenTelemetry, point OTLP exporters at the dashboard, and visualize logs, traces, and metrics. +title: Node.js OpenTelemetry with the Aspire dashboard +description: View JavaScript and Node.js telemetry in a local Aspire dashboard. Instrument an Express app and export OpenTelemetry traces and metrics over OTLP. --- import { Steps } from '@astrojs/starlight/components'; import { Kbd } from 'starlight-kbd/components'; -The [Aspire dashboard](/dashboard/overview/) provides a great user experience for viewing telemetry. You can run it standalone with the [Aspire CLI](/reference/cli/overview/) or the standalone dashboard container image for any OpenTelemetry-enabled app. In this article, you'll learn how to: +Use the [standalone Aspire dashboard](/dashboard/standalone/) to inspect JavaScript application telemetry from Node.js locally, without an AppHost. This tutorial configures the OpenTelemetry JavaScript SDK and Node.js instrumentation for an Express app, then exports traces and metrics over OTLP. + +In this article, you'll learn how to: - Start the Aspire dashboard in standalone mode. -- Use the Aspire dashboard with a Node.js app. +- Instrument a Node.js app and inspect its requests in the dashboard. ## Prerequisites @@ -228,6 +230,8 @@ The **Traces** page shows distributed traces for HTTP requests. Each request to The **Metrics** page displays various metrics collected from your Node.js application, including HTTP request metrics, Node.js runtime metrics, and custom metrics if you choose to add them. +The `console.log` calls in this example write to your terminal, not the dashboard's **Structured logs** page. To export logs, configure OpenTelemetry logging with a supported logging library and an OTLP log exporter. See the [OpenTelemetry JavaScript documentation](https://opentelemetry.io/docs/languages/js/). + ## Add custom telemetry (optional) You can enhance your application with custom spans and metrics. Here's an example of adding a custom metric to track API requests: @@ -305,4 +309,4 @@ app.listen(port, () => { You have successfully used the Aspire dashboard with a Node.js application. To learn more about the Aspire dashboard, see the [Aspire dashboard overview](/dashboard/overview/) and how to orchestrate a Node.js application with the Aspire AppHost. -To learn more about OpenTelemetry instrumentation for Node.js applications, see the [OpenTelemetry JavaScript documentation](https://opentelemetry.io/docs/languages/js/). \ No newline at end of file +To follow requests across instrumented services, see [OpenTelemetry and distributed tracing](/fundamentals/telemetry/). To let a coding agent query the same telemetry, see [AI coding agents with the standalone dashboard](/dashboard/ai-coding-agents/#standalone-mode). \ No newline at end of file diff --git a/src/frontend/src/content/docs/dashboard/standalone-for-python.mdx b/src/frontend/src/content/docs/dashboard/standalone-for-python.mdx index 84e204916..373bd3b6c 100644 --- a/src/frontend/src/content/docs/dashboard/standalone-for-python.mdx +++ b/src/frontend/src/content/docs/dashboard/standalone-for-python.mdx @@ -1,6 +1,6 @@ --- -title: Aspire dashboard standalone for Python apps -description: Use the Aspire dashboard standalone with Python applications — configure OpenTelemetry exporters, send OTLP data to the dashboard, and inspect telemetry in real time. +title: Python OpenTelemetry with the Aspire dashboard +description: Send Python FastAPI logs, traces, and metrics to a local Aspire dashboard. Configure OpenTelemetry and OTLP exporters without running an AppHost. --- import { Image } from 'astro:assets'; @@ -13,10 +13,12 @@ import ThemeImage from '@components/ThemeImage.astro'; import aspireDashboardPythonLogs from '@assets/dashboard/standalone/aspire-dashboard-python-logs.png'; import aspireDashboardPythonLogsLight from '@assets/dashboard/standalone/aspire-dashboard-python-logs-light.png'; -The [Aspire dashboard](/dashboard/overview/) provides a great user experience for viewing telemetry. You can run it standalone with the [Aspire CLI](/reference/cli/overview/) or the standalone dashboard container image for any OpenTelemetry-enabled app. In this article, you'll learn how to: +Use the [standalone Aspire dashboard](/dashboard/standalone/) to view Python application telemetry locally. This tutorial configures the OpenTelemetry Python SDK and FastAPI instrumentation to export logs, traces, and metrics over OTLP. The Python app runs directly, without an AppHost; the dashboard doesn't instrument it automatically. + +In this article, you'll learn how to: - Start the Aspire dashboard in standalone mode. -- Use the Aspire dashboard with a Python app. +- Configure and inspect telemetry from a Python FastAPI app. ## Prerequisites @@ -215,6 +217,8 @@ With both the dashboard and your Python application running, you can now view te +The `/simulate-error` endpoint writes warning and error logs but returns a successful HTTP response. An error-level log isn't itself a failed request. For a request failure investigated through both the dashboard and CLI, see [Debug application failures with AI coding agents](/dashboard/ai-coding-agents/). + The structured logs page displays logs from your application with rich filtering and search capabilities: " +aspire dashboard run --Dashboard:Api:AuthMode=ApiKey --Dashboard:Api:PrimaryApiKey="" ``` +Then start the MCP server in a separate terminal with the dashboard base URL and the same key: + +```bash title="Aspire CLI" +aspire agent mcp --dashboard-url "http://localhost:18888" --api-key "" +``` + +Use a high-entropy key and don't commit or share it. For more information, see [Secure the telemetry API endpoint](/dashboard/security-considerations/#telemetry-api-endpoint). + ## Sample For a sample of using the standalone dashboard, see the [Standalone Aspire dashboard sample app](https://github.com/microsoft/aspire-samples/tree/main/samples/standalone-dashboard). diff --git a/src/frontend/src/content/docs/fundamentals/telemetry.mdx b/src/frontend/src/content/docs/fundamentals/telemetry.mdx index 4d6f00164..ad4b56e56 100644 --- a/src/frontend/src/content/docs/fundamentals/telemetry.mdx +++ b/src/frontend/src/content/docs/fundamentals/telemetry.mdx @@ -1,14 +1,15 @@ --- -title: Telemetry -seoTitle: 'Aspire telemetry: OpenTelemetry logs, traces, and metrics' -description: Learn the essential Aspire telemetry concepts — logging, distributed tracing, and metrics with OpenTelemetry, and how the Aspire dashboard surfaces them in real time. +title: OpenTelemetry and distributed tracing in Aspire +description: Correlate application logs, distributed traces, and metrics across local services. Learn how Aspire receives OpenTelemetry and makes it available to coding agents. --- import { Aside } from '@astrojs/starlight/components'; import { Kbd } from 'starlight-kbd/components'; import LearnMore from '@components/LearnMore.astro'; -One of the primary objectives of Aspire is to ensure that apps are straightforward to debug and diagnose. Aspire integrations automatically set up logging, tracing, and metrics configurations—sometimes known as the pillars of observability—using the [.NET OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-dotnet). +Aspire uses OpenTelemetry to make distributed applications easier to debug. Instrumented services send logs, traces, and metrics to the [Aspire dashboard](/dashboard/overview/), where you can follow a request across local services and correlate errors with the work that produced them. + +Telemetry depends on each application's instrumentation and exporter configuration. .NET service defaults and client integrations configure the .NET OpenTelemetry SDK; [Python](/dashboard/standalone-for-python/) and [JavaScript on Node.js](/dashboard/standalone-for-nodejs/) use their own SDKs. Running a service through Aspire doesn't automatically instrument every language or library. ## The three pillars of observability @@ -20,11 +21,17 @@ One of the primary objectives of Aspire is to ensure that apps are straightforwa Together, these types of telemetry allow you to gain insights into your application's behavior and performance using various monitoring and analysis tools. Depending on the backing service, some integrations may only support some of these features. +### Follow a request across local services + +A distributed trace groups spans from one request under a shared trace ID. Instrument the incoming request handlers and outgoing clients in each service so they propagate trace context across HTTP calls or other supported transports. The dashboard can then show which service or dependency failed, how long each operation took, and logs that carry the same trace ID. + +Resource health and request success answer different questions. A process can be running and pass its health check while a particular request returns an error. Inspect the failed request's trace and correlated logs, not only the resource's health indicator. + ## Aspire OpenTelemetry integration The [.NET OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-dotnet) includes features for gathering data from several .NET APIs, including `ILogger`, `Activity`, `Meter`, and `Instrument`. These APIs correspond to telemetry features like logging, tracing, and metrics. -Aspire projects define OpenTelemetry SDK configurations in the service defaults project. By default, the `ConfigureOpenTelemetry` method enables logging, tracing, and metrics for the app. It also adds exporters for these data points so they can be collected by other monitoring tools. +.NET projects using service defaults define OpenTelemetry SDK configuration there. By default, the `ConfigureOpenTelemetry` method enables logging, tracing, and metrics for the app. It also configures exporters so other monitoring tools can collect these signals. For more information, see [Service defaults](/get-started/csharp-service-defaults/). @@ -74,7 +81,7 @@ All of these steps happen internally, so in most cases you simply need to run th ### Use telemetry with AI coding agents -AI coding agents can access Aspire telemetry to diagnose issues, inspect app behavior, and monitor resources without requiring you to manually copy data from the dashboard. The Aspire CLI is built for agent-driven workflows—commands support non-interactive execution and `--format Json` for structured output that agents can parse. +AI coding agents can access the same application telemetry you inspect in the dashboard to diagnose failures and verify fixes. This is observability of your application for coding agents, not monitoring of the agents' reasoning or token usage. [Aspire skills](/get-started/aspire-skills/) teach CLI-first workflows, including non-interactive commands and `--format Json` output. When running an Aspire AppHost, agents use CLI commands like `aspire otel logs`, `aspire otel traces`, and `aspire describe` to fetch structured logs, distributed traces, and resource status directly from the dashboard. A typical agent workflow starts the app with `aspire start`, waits for resources with `aspire wait`, then queries telemetry to diagnose issues and verify fixes. @@ -83,6 +90,7 @@ When using a standalone dashboard, agents pass `--dashboard-url` to point CLI co - [AI coding agents and Aspire](/get-started/ai-coding-agents/) — using AI agents with an Aspire AppHost +- [Debug application failures with AI coding agents](/dashboard/ai-coding-agents/) — investigate the same logs and traces as a human - [AI coding agents and the Aspire Dashboard](/dashboard/ai-coding-agents/#standalone-mode) — using AI agents with a standalone dashboard 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 0641dfcb9..b70720a19 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 @@ -1,7 +1,6 @@ --- -title: Use AI coding agents -seoTitle: Use AI coding agents with Aspire AppHost projects today -description: Set up AI coding agents to work with Aspire — install skills, add optional tools, and guide agents through distributed-app workflows. +title: Use AI coding agents with Aspire observability +description: Set up Aspire skills so coding agents can inspect application logs, traces, and resource health, diagnose local failures, and verify fixes with runtime evidence. --- import { Aside, Steps, TabItem, Tabs } from '@astrojs/starlight/components'; @@ -9,11 +8,11 @@ import AsciinemaPlayer from '@components/AsciinemaPlayer.astro'; import LearnMore from '@components/LearnMore.astro'; import LoopingVideo from '@components/LoopingVideo.astro'; -Aspire provides a first-class setup experience for AI coding agents. Run `aspire agent init` in your project and your AI assistant — whether it's GitHub Copilot, Claude Code, or another MCP-compatible tool — can immediately understand, build, debug, and monitor your distributed applications. +Give your AI coding agent access to application observability, not just source code. Run `aspire agent init` in your project to install skills that teach your assistant to use the Aspire CLI, inspect local services, and work with TypeScript or C# AppHosts. A runtime MCP server is optional. ## Why Aspire for coding agents -Aspire gives coding agents the same visibility into your running application that a developer has. The resource data, structured logs, and distributed traces you see in the [Aspire Dashboard](/dashboard/overview/) are exposed to agents through the [Aspire MCP server](/get-started/aspire-mcp-server/) and the [Aspire CLI](/get-started/install-cli/). Whether a person is debugging in the dashboard or an agent is diagnosing through MCP, they see the same picture. +Aspire gives coding agents access to the resource status, health checks, application logs, and distributed traces you inspect in the [Aspire dashboard](/dashboard/overview/). Start with [Aspire skills](/get-started/aspire-skills/) and the [Aspire CLI](/get-started/install-cli/); add the [Aspire MCP server](/get-started/aspire-mcp-server/) if you want runtime tools exposed through MCP. Both paths let an agent investigate the same request evidence as a developer. The Aspire CLI is built for agent-driven workflows — commands support non-interactive execution to avoid blocking on prompts, and many commands support `--format Json` for structured plain text output. Key commands include `aspire start` (background execution), `aspire start --isolated` (parallel worktrees), `aspire wait` (block until healthy), `aspire describe`, `aspire logs`, and `aspire docs search`. @@ -62,7 +61,7 @@ Aspire skill files teach your AI coding agent how to use Aspire CLI workflows, r ### Aspire MCP server -The MCP server gives your AI agent direct runtime access to your running Aspire application — resource status, logs, traces, and commands. See [Aspire MCP server](/get-started/aspire-mcp-server/) for configuration details, available tools, and the security model. +The optional MCP server gives your AI agent direct runtime access to your running Aspire application — resource status, logs, traces, and commands. CLI skills can already query runtime data without MCP. See [Aspire MCP server](/get-started/aspire-mcp-server/) for configuration details, available tools, and the security model. ## Migrate from AGENTS.md @@ -92,8 +91,12 @@ Once configured, start your preferred AI coding environment. Try asking your age > "Analyze HTTP request performance for my API." +> "Investigate this failed request using its trace ID and correlated logs. After the fix, repeat the request and verify the response and new trace." + > "Add a Redis cache to my AppHost." +For a worked investigation using the same evidence in the dashboard and CLI, see [Debug application failures with AI coding agents](/dashboard/ai-coding-agents/). Passing resource health checks alone doesn't prove that a failing request is fixed. + MCP server gives AI coding agents direct runtime access to your running Aspire application. Through the Model Context Protocol (MCP), agents can query resource status, read logs, inspect distributed traces, and execute commands — without you copy-pasting terminal output. +The Aspire MCP server exposes application observability to AI coding agents. Agents can query resource status and health, read application logs, inspect distributed traces, and execute resource commands. They use the same runtime evidence you inspect in the [Aspire dashboard](/dashboard/overview/), rather than inferring application behavior from source code alone. :::tip[Aspire skills are preferred] -For most AI coding-agent workflows, install [Aspire skills](/get-started/aspire-skills/) first. Aspire skills are the preferred way to teach agents Aspire commands, workflows, and AppHost conventions. Add the Aspire MCP server when the agent also needs live runtime data such as resource status, logs, traces, or resource commands. +For most AI coding-agent workflows, install [Aspire skills](/get-started/aspire-skills/) first. Skills teach agents Aspire CLI commands, workflows, and TypeScript or C# AppHost conventions, including how to query live runtime data. Add the optional MCP server when you prefer to expose that data through MCP tools instead. ::: To set up your project for AI coding agents, see [Use AI coding agents](/get-started/ai-coding-agents/). + For a request-level investigation, see [Debug application failures with AI coding agents](/dashboard/ai-coding-agents/). ## Configuration diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-mcp.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-mcp.mdx index 7e3d9f2f7..cc240d448 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-mcp.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-agent-mcp.mdx @@ -34,11 +34,11 @@ The following options are available: - **`--dashboard-url `** - The URL of a standalone Aspire Dashboard to connect to instead of discovering one from an AppHost. Accepts a base URL (for example, `http://localhost:18888`) or a full login URL including a browser token (for example, `http://localhost:18888/login?t=`). When a login URL is provided, the token is automatically exchanged for an API key. + The base URL of a standalone Aspire Dashboard to connect to instead of discovering one from an AppHost, for example `http://localhost:18888`. Browser login tokens aren't used to authenticate MCP telemetry tools. - **`--api-key `** - The API key used to authenticate with the dashboard's Telemetry API. Only required when `--dashboard-url` is specified and the dashboard is configured with `ApiKey` authentication and no login URL is provided. + The API key used to authenticate with the dashboard's Telemetry API. Provide it when `--dashboard-url` targets a dashboard configured with `ApiKey` authentication. - @@ -60,16 +60,10 @@ The following options are available: aspire agent mcp ``` -- Start the MCP server in dashboard-only mode using a login URL: - - ```bash title="Aspire CLI" - aspire agent mcp --dashboard-url "http://localhost:18888/login?t=" - ``` - - Start the MCP server in dashboard-only mode with an API key: ```bash title="Aspire CLI" - aspire agent mcp --dashboard-url "http://localhost:18888" --api-key "" + aspire agent mcp --dashboard-url "http://localhost:18888" --api-key "" ``` ## See also diff --git a/src/frontend/src/content/i18n/da.json b/src/frontend/src/content/i18n/da.json index 8c7134c57..fa2e936f3 100644 --- a/src/frontend/src/content/i18n/da.json +++ b/src/frontend/src/content/i18n/da.json @@ -245,7 +245,10 @@ "body": "Følg en forespørgsel på tværs af ressourcer, skift mellem strukturerede logge og traces, inspicér metrikker, og handl på ressourcesundhed fra ét udviklerkontrolpanel.", "badgeLabel": "Agenter handler på disse signaler", "badgeDescription": "Aspire giver tilsluttede AI-værktøjer kontekst fra kontrolpanelet, herunder logge, traces, metrikker, sundhed og ressourcekommandoer.", - "link": "Udforsk Aspire-kontrolpanelet" + "link": "Udforsk Aspire-kontrolpanelet", + "standaloneLink": "Selvstændigt kontrolpanel", + "telemetryLink": "OpenTelemetry-begreber", + "agentsLink": "Fejlfind med kodningsagenter" }, "integrations": { "index": "Udvidelig som standard", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "AppHost-eksemplerne kunne ikke indlæses. Vælg en mulighed for at prøve igen.", "heading": "Byg din {{appHost}}", "description": "Slå forskellige funktioner til/fra for at se hvordan Aspire definerer dele af din stack.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/de.json b/src/frontend/src/content/i18n/de.json index 1c4faed64..ba83dae99 100644 --- a/src/frontend/src/content/i18n/de.json +++ b/src/frontend/src/content/i18n/de.json @@ -245,7 +245,10 @@ "body": "Verfolge eine Anfrage über Ressourcen hinweg, wechsle zwischen strukturierten Logs und Traces, prüfe Metriken und reagiere in einem Entwickler-Dashboard auf den Ressourcenzustand.", "badgeLabel": "Agenten handeln auf Basis dieser Signale", "badgeDescription": "Aspire gibt verbundenen KI-Tools Dashboard-Kontext, einschließlich Logs, Traces, Metriken, Zustand und Ressourcenbefehlen.", - "link": "Aspire-Dashboard entdecken" + "link": "Aspire-Dashboard entdecken", + "standaloneLink": "Eigenständiges Dashboard", + "telemetryLink": "OpenTelemetry-Konzepte", + "agentsLink": "Mit Coding-Agenten debuggen" }, "integrations": { "index": "Standardmäßig erweiterbar", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "AppHost-Beispiele konnten nicht geladen werden. Wähle eine Option, um es erneut zu versuchen.", "heading": "Baue dein {{appHost}}", "description": "Funktionen an/aus schalten um zu sehen wie Aspire Teile deines Stacks definiert.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/en.json b/src/frontend/src/content/i18n/en.json index bc088476f..62d070fed 100644 --- a/src/frontend/src/content/i18n/en.json +++ b/src/frontend/src/content/i18n/en.json @@ -237,10 +237,13 @@ "observability": { "index": "Observability included", "title": "See the whole application.", - "body": "Follow requests across resources, logs, traces, metrics, and health from one developer dashboard.", + "body": "View OpenTelemetry logs, traces, and metrics locally. Follow requests across services with your team or coding agent.", "badgeLabel": "Agents act on these signals", "badgeDescription": "Aspire gives connected AI tools dashboard context, including logs, traces, metrics, health, and resource commands.", - "link": "Explore the Aspire dashboard" + "link": "Explore the Aspire dashboard", + "standaloneLink": "Standalone dashboard", + "telemetryLink": "OpenTelemetry concepts", + "agentsLink": "Debug with coding agents" }, "integrations": { "index": "Extensible by default", @@ -493,6 +496,7 @@ } }, "appHostBuilder": { + "examplesError": "Could not load AppHost examples. Select an option to try again.", "heading": "Build your {{appHost}}", "description": "Toggle different features on/off to see how Aspire defines different parts of your stack.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/es.json b/src/frontend/src/content/i18n/es.json index 4d685cf3d..a48087ed5 100644 --- a/src/frontend/src/content/i18n/es.json +++ b/src/frontend/src/content/i18n/es.json @@ -245,7 +245,10 @@ "body": "Sigue una solicitud entre recursos, alterna entre registros estructurados y trazas, inspecciona métricas y actúa sobre el estado de los recursos desde un solo panel para desarrolladores.", "badgeLabel": "Los agentes actúan sobre estas señales", "badgeDescription": "Aspire proporciona a las herramientas de IA conectadas contexto del panel, incluidos registros, trazas, métricas, estado y comandos de recursos.", - "link": "Explora el panel de Aspire" + "link": "Explora el panel de Aspire", + "standaloneLink": "Panel independiente", + "telemetryLink": "Conceptos de OpenTelemetry", + "agentsLink": "Depura con agentes de programación" }, "integrations": { "index": "Extensible de forma predeterminada", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "No se pudieron cargar los ejemplos de AppHost. Selecciona una opción para volver a intentarlo.", "heading": "Crea tu {{appHost}}", "description": "Activa o desactiva diferentes características para ver cómo Aspire define las distintas partes de tu pila.", "frontend": "Interfaz web", diff --git a/src/frontend/src/content/i18n/fr.json b/src/frontend/src/content/i18n/fr.json index ff01c7060..0ed90a9ae 100644 --- a/src/frontend/src/content/i18n/fr.json +++ b/src/frontend/src/content/i18n/fr.json @@ -245,7 +245,10 @@ "body": "Suivez une requête entre les ressources, passez des journaux structurés aux traces, inspectez les métriques et agissez sur l’état d’intégrité des ressources depuis un seul tableau de bord développeur.", "badgeLabel": "Les agents agissent sur ces signaux", "badgeDescription": "Aspire fournit aux outils d’IA connectés le contexte du tableau de bord, y compris les journaux, traces, métriques, l’état d’intégrité et les commandes de ressources.", - "link": "Explorer le tableau de bord Aspire" + "link": "Explorer le tableau de bord Aspire", + "standaloneLink": "Tableau de bord autonome", + "telemetryLink": "Concepts OpenTelemetry", + "agentsLink": "Déboguer avec des agents de programmation" }, "integrations": { "index": "Extensible par défaut", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "Impossible de charger les exemples AppHost. Sélectionnez une option pour réessayer.", "heading": "Construisez votre {{appHost}}", "description": "Activez/désactivez des fonctionnalités pour voir comment Aspire définit les parties de votre pile.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/hi.json b/src/frontend/src/content/i18n/hi.json index 27dd04396..341da99a9 100644 --- a/src/frontend/src/content/i18n/hi.json +++ b/src/frontend/src/content/i18n/hi.json @@ -245,7 +245,10 @@ "body": "एक डेवलपर डैशबोर्ड से संसाधनों के पार अनुरोध को ट्रैक करें, संरचित लॉग और ट्रेस के बीच जाएँ, मेट्रिक्स देखें और संसाधन स्वास्थ्य पर कार्रवाई करें.", "badgeLabel": "एजेंट इन संकेतों पर कार्रवाई करते हैं", "badgeDescription": "Aspire जुड़े हुए AI टूल्स को डैशबोर्ड संदर्भ देता है, जिसमें लॉग, ट्रेस, मेट्रिक्स, स्वास्थ्य और संसाधन कमांड शामिल हैं.", - "link": "Aspire डैशबोर्ड देखें" + "link": "Aspire डैशबोर्ड देखें", + "standaloneLink": "स्टैंडअलोन डैशबोर्ड", + "telemetryLink": "OpenTelemetry की अवधारणाएँ", + "agentsLink": "कोडिंग एजेंट के साथ डीबग करें" }, "integrations": { "index": "डिफ़ॉल्ट रूप से विस्तार योग्य", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "AppHost उदाहरण लोड नहीं हो सके। फिर से कोशिश करने के लिए कोई विकल्प चुनें।", "heading": "अपना {{appHost}} बनाएँ", "description": "देखें Aspire आपके स्टैक के भागों को कैसे परिभाषित करता है — फीचर्स को ऑन/ऑफ करें।", "frontend": "फ्रंटएंड", diff --git a/src/frontend/src/content/i18n/id.json b/src/frontend/src/content/i18n/id.json index 251936dda..639461485 100644 --- a/src/frontend/src/content/i18n/id.json +++ b/src/frontend/src/content/i18n/id.json @@ -245,7 +245,10 @@ "body": "Ikuti permintaan melintasi sumber daya, berpindah antara log terstruktur dan jejak, periksa metrik, dan tangani kesehatan sumber daya dari satu dasbor pengembang.", "badgeLabel": "Agen bertindak berdasarkan sinyal ini", "badgeDescription": "Aspire memberi alat AI yang terhubung konteks dasbor, termasuk log, jejak, metrik, kesehatan, dan perintah sumber daya.", - "link": "Jelajahi dasbor Aspire" + "link": "Jelajahi dasbor Aspire", + "standaloneLink": "Dasbor mandiri", + "telemetryLink": "Konsep OpenTelemetry", + "agentsLink": "Debug dengan agen pengodean" }, "integrations": { "index": "Mudah diperluas secara default", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "Contoh AppHost tidak dapat dimuat. Pilih opsi untuk mencoba lagi.", "heading": "Bangun {{appHost}} Anda", "description": "Aktif/nonaktifkan fitur untuk melihat bagaimana Aspire mendefinisikan stack Anda.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/it.json b/src/frontend/src/content/i18n/it.json index c5f40bdcf..8bbc69506 100644 --- a/src/frontend/src/content/i18n/it.json +++ b/src/frontend/src/content/i18n/it.json @@ -245,7 +245,10 @@ "body": "Segui una richiesta tra le risorse, passa tra log strutturati e tracce, ispeziona le metriche e intervieni sull'integrità delle risorse da un unico pannello per sviluppatori.", "badgeLabel": "Gli agenti agiscono su questi segnali", "badgeDescription": "Aspire offre agli strumenti di IA connessi il contesto del pannello, inclusi log, tracce, metriche, integrità e comandi delle risorse.", - "link": "Esplora il pannello di controllo di Aspire" + "link": "Esplora il pannello di controllo di Aspire", + "standaloneLink": "Pannello autonomo", + "telemetryLink": "Concetti di OpenTelemetry", + "agentsLink": "Debug con agenti di programmazione" }, "integrations": { "index": "Estendibile per impostazione predefinita", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "Impossibile caricare gli esempi AppHost. Seleziona un'opzione per riprovare.", "heading": "Crea il tuo {{appHost}}", "description": "Attiva/disattiva funzionalità per vedere come Aspire definisce parti dello stack.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/ja.json b/src/frontend/src/content/i18n/ja.json index 03647cde7..8fda7b2c6 100644 --- a/src/frontend/src/content/i18n/ja.json +++ b/src/frontend/src/content/i18n/ja.json @@ -245,7 +245,10 @@ "body": "1 つの開発者向けダッシュボードから、リソースをまたいでリクエストを追跡し、構造化ログとトレースを行き来し、メトリックを確認し、リソースの正常性に対応できます。", "badgeLabel": "エージェントはこれらのシグナルに対応", "badgeDescription": "Aspire は、ログ、トレース、メトリック、正常性、リソース コマンドを含むダッシュボード コンテキストを、接続された AI ツールに提供します。", - "link": "Aspire ダッシュボードを詳しく見る" + "link": "Aspire ダッシュボードを詳しく見る", + "standaloneLink": "スタンドアロン ダッシュボード", + "telemetryLink": "OpenTelemetry の概念", + "agentsLink": "コーディング エージェントでデバッグ" }, "integrations": { "index": "既定で拡張可能", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "AppHost の例を読み込めませんでした。オプションを選択して再試行してください。", "heading": "{{appHost}} を構築", "description": "機能をオン/オフして Aspire がスタックをどう定義するか確認。", "frontend": "フロントエンド", diff --git a/src/frontend/src/content/i18n/ko.json b/src/frontend/src/content/i18n/ko.json index 9496090c0..64e6e4e06 100644 --- a/src/frontend/src/content/i18n/ko.json +++ b/src/frontend/src/content/i18n/ko.json @@ -245,7 +245,10 @@ "body": "하나의 개발자 대시보드에서 리소스 전반의 요청을 추적하고, 구조화된 로그와 추적 사이를 이동하고, 메트릭을 살펴보고, 리소스 상태에 대응하세요.", "badgeLabel": "에이전트가 이 신호에 따라 동작합니다", "badgeDescription": "Aspire는 연결된 AI 도구에 로그, 추적, 메트릭, 상태, 리소스 명령을 포함한 대시보드 컨텍스트를 제공합니다.", - "link": "Aspire 대시보드 살펴보기" + "link": "Aspire 대시보드 살펴보기", + "standaloneLink": "독립 실행형 대시보드", + "telemetryLink": "OpenTelemetry 개념", + "agentsLink": "코딩 에이전트로 디버깅" }, "integrations": { "index": "기본적으로 확장 가능", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "AppHost 예제를 로드할 수 없습니다. 옵션을 선택하여 다시 시도하세요.", "heading": "{{appHost}} 빌드", "description": "기능을 켜거나 꺼서 Aspire가 스택을 어떻게 정의하는지 확인.", "frontend": "프런트엔드", diff --git a/src/frontend/src/content/i18n/pt-BR.json b/src/frontend/src/content/i18n/pt-BR.json index 01e58b83c..e296721a5 100644 --- a/src/frontend/src/content/i18n/pt-BR.json +++ b/src/frontend/src/content/i18n/pt-BR.json @@ -245,7 +245,10 @@ "body": "Acompanhe uma requisição entre recursos, alterne entre registros estruturados e rastreamentos, inspecione métricas e aja sobre a integridade dos recursos em um único painel de desenvolvedor.", "badgeLabel": "Agentes agem sobre esses sinais", "badgeDescription": "O Aspire dá às ferramentas de IA conectadas contexto do painel, incluindo registros, rastreamentos, métricas, integridade e comandos de recursos.", - "link": "Explore o painel do Aspire" + "link": "Explore o painel do Aspire", + "standaloneLink": "Painel independente", + "telemetryLink": "Conceitos do OpenTelemetry", + "agentsLink": "Depure com agentes de programação" }, "integrations": { "index": "Extensível por padrão", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "Não foi possível carregar os exemplos do AppHost. Selecione uma opção para tentar novamente.", "heading": "Construa seu {{appHost}}", "description": "Ative/desative recursos para ver como o Aspire define sua stack.", "frontend": "Frontend", diff --git a/src/frontend/src/content/i18n/ru.json b/src/frontend/src/content/i18n/ru.json index 6912bc653..e7859133b 100644 --- a/src/frontend/src/content/i18n/ru.json +++ b/src/frontend/src/content/i18n/ru.json @@ -245,7 +245,10 @@ "body": "Отслеживайте запрос между ресурсами, переходите между структурированными журналами и трассировками, изучайте метрики и реагируйте на состояние ресурсов из единой панели мониторинга для разработчиков.", "badgeLabel": "Агенты действуют по этим сигналам", "badgeDescription": "Aspire даёт подключённым ИИ-инструментам контекст панели мониторинга, включая журналы, трассировки, метрики, состояние и команды ресурсов.", - "link": "Изучить панель мониторинга Aspire" + "link": "Изучить панель мониторинга Aspire", + "standaloneLink": "Автономная панель мониторинга", + "telemetryLink": "Концепции OpenTelemetry", + "agentsLink": "Отладка с агентами программирования" }, "integrations": { "index": "Расширяемость по умолчанию", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "Не удалось загрузить примеры AppHost. Выберите вариант, чтобы повторить попытку.", "heading": "Постройте свой {{appHost}}", "description": "Включайте и выключайте функции, чтобы увидеть, как Aspire определяет части вашего стека.", "frontend": "Фронтенд", diff --git a/src/frontend/src/content/i18n/tr.json b/src/frontend/src/content/i18n/tr.json index 91a70b00b..4df987a72 100644 --- a/src/frontend/src/content/i18n/tr.json +++ b/src/frontend/src/content/i18n/tr.json @@ -245,7 +245,10 @@ "body": "Bir isteği kaynaklar arasında izleyin, yapılandırılmış günlükler ile izler arasında geçiş yapın, metrikleri inceleyin ve tek bir geliştirici panosundan kaynak sağlığına göre işlem yapın.", "badgeLabel": "Ajanlar bu sinyallerle hareket eder", "badgeDescription": "Aspire, bağlı yapay zekâ araçlarına günlükler, izler, metrikler, sağlık ve kaynak komutları dahil pano bağlamı sağlar.", - "link": "Aspire panosunu keşfedin" + "link": "Aspire panosunu keşfedin", + "standaloneLink": "Bağımsız pano", + "telemetryLink": "OpenTelemetry kavramları", + "agentsLink": "Kodlama ajanlarıyla hata ayıklayın" }, "integrations": { "index": "Varsayılan olarak genişletilebilir", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "AppHost örnekleri yüklenemedi. Yeniden denemek için bir seçenek seçin.", "heading": "{{appHost}} Oluştur", "description": "Aspire'ın yığını nasıl tanımladığını görmek için özellikleri aç/kapat.", "frontend": "Ön Uç", diff --git a/src/frontend/src/content/i18n/uk.json b/src/frontend/src/content/i18n/uk.json index 4cd1086d1..ca69dbbf2 100644 --- a/src/frontend/src/content/i18n/uk.json +++ b/src/frontend/src/content/i18n/uk.json @@ -245,7 +245,10 @@ "body": "Відстежуйте запит між ресурсами, переходьте між структурованими журналами й трасами, переглядайте метрики та реагуйте на справність ресурсів з одного дашборду розробника.", "badgeLabel": "Агенти діють за цими сигналами", "badgeDescription": "Aspire надає під’єднаним інструментам ШІ контекст дашборду, зокрема журнали, траси, метрики, стан справності та команди ресурсів.", - "link": "Дослідити дашборд Aspire" + "link": "Дослідити дашборд Aspire", + "standaloneLink": "Автономний дашборд", + "telemetryLink": "Концепції OpenTelemetry", + "agentsLink": "Налагодження з агентами програмування" }, "integrations": { "index": "Розширюваність за замовчуванням", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "Не вдалося завантажити приклади AppHost. Виберіть опцію, щоб спробувати ще раз.", "heading": "Побудуйте свій {{appHost}}", "description": "Вмикайте/вимикайте функції, щоб побачити як Aspire визначає частини стеку.", "frontend": "Фронтенд", diff --git a/src/frontend/src/content/i18n/zh-CN.json b/src/frontend/src/content/i18n/zh-CN.json index 48d25186d..d71252b0b 100644 --- a/src/frontend/src/content/i18n/zh-CN.json +++ b/src/frontend/src/content/i18n/zh-CN.json @@ -245,7 +245,10 @@ "body": "在一个开发者仪表板中跟踪请求跨资源的路径,在结构化日志与跟踪之间切换,检查指标,并根据资源健康状态采取行动。", "badgeLabel": "智能体可基于这些信号行动", "badgeDescription": "Aspire 为已连接的 AI 工具提供仪表板上下文,包括日志、跟踪、指标、健康状态和资源命令。", - "link": "浏览 Aspire 仪表板" + "link": "浏览 Aspire 仪表板", + "standaloneLink": "独立仪表板", + "telemetryLink": "OpenTelemetry 概念", + "agentsLink": "使用编码智能体调试" }, "integrations": { "index": "默认可扩展", @@ -487,6 +490,7 @@ } }, "appHostBuilder": { + "examplesError": "无法加载 AppHost 示例。请选择一个选项以重试。", "heading": "构建你的 {{appHost}}", "description": "切换不同功能,查看 Aspire 如何定义你的技术栈各部分。", "frontend": "前端", diff --git a/src/frontend/src/utils/page-metadata.ts b/src/frontend/src/utils/page-metadata.ts index 7658efd5c..e3e00a4e2 100644 --- a/src/frontend/src/utils/page-metadata.ts +++ b/src/frontend/src/utils/page-metadata.ts @@ -22,18 +22,9 @@ export const DEFAULT_OG_IMAGE_WIDTH = 1200; export const DEFAULT_OG_IMAGE_HEIGHT = 630; /** - * Marketing-grade fallback description used for the home page and for any - * page that somehow lacks a frontmatter `description`. This intentionally - * differs from `structured-data.ts`'s `organizationDescription` and from the - * site-wide `description` meta in `config/head.attrs.ts` because each is - * sized for its own audience: - * - * - `astro.config.mjs` / `head.attrs.ts` — long-form marketing copy, no - * length cap, shown only on the home page. - * - `structured-data.ts` `organizationDescription` — JSON-LD organization - * summary, slightly tighter and product-focused. - * - This constant — Open Graph fallback, kept short enough for social-card - * previews and truncated to `OG_DESCRIPTION_MAX_LENGTH` before emission. + * Social-card fallback for pages without a frontmatter `description`. + * Starlight owns the standard description meta tag; this fallback only + * applies to Open Graph and Twitter previews. */ export const FALLBACK_DESCRIPTION = 'Aspire streamlines your development workflow with code-first control, ' + diff --git a/src/frontend/tests/e2e/api-markdown-routes.spec.ts b/src/frontend/tests/e2e/api-markdown-routes.spec.ts index b933a0c15..ffdbcae74 100644 --- a/src/frontend/tests/e2e/api-markdown-routes.spec.ts +++ b/src/frontend/tests/e2e/api-markdown-routes.spec.ts @@ -1,4 +1,5 @@ import { expect, test } from '@playwright/test'; +import { locales } from '../../config/locales'; const markdownRoutes = [ { @@ -85,4 +86,26 @@ for (const route of markdownRoutes) { expect(body).toContain(route.expectedText); expect(body).not.toContain(''); }); -} \ No newline at end of file +} + +test('built homepages publish useful Markdown through their existing companion paths', async ({ + request, +}) => { + test.skip(!process.env.CI, 'Homepage Markdown is finalized by the production build.'); + + for (const locale of Object.keys(locales)) { + const prefix = locale === 'root' ? '' : `/${locale}`; + const response = await request.get(`${prefix || '/index'}.md`); + expect(response.ok()).toBe(true); + expect(response.headers()['content-type']).toContain('text/markdown'); + const markdown = await response.text(); + + expect(markdown).toMatch(/^# .+/m); + expect(markdown).toContain('OpenTelemetry'); + expect(markdown).toContain(`](${prefix}/get-started/first-app/)`); + expect(markdown).toContain(`](${prefix}/dashboard/standalone/)`); + expect(markdown).toContain('```typescript\n'); + expect(markdown).toContain('```csharp\n'); + expect(markdown).not.toMatch(/|class="code-variant"/); + } +}); diff --git a/src/frontend/tests/e2e/custom-components.spec.ts b/src/frontend/tests/e2e/custom-components.spec.ts index eaed1158a..195d405af 100644 --- a/src/frontend/tests/e2e/custom-components.spec.ts +++ b/src/frontend/tests/e2e/custom-components.spec.ts @@ -1,6 +1,112 @@ import { expect, test } from '@playwright/test'; import { dismissCookieConsentIfVisible } from '@tests/e2e/helpers'; +import { deferAppHostExamples } from '../../config/apphost-examples.mjs'; + +test.describe('deferred AppHost examples', () => { + test.beforeEach(async ({ page, request, baseURL }) => { + // Exercise the production transformation locally without a full site build. + const response = await request.get('/'); + const html = await response.text(); + if (!html.includes('data-apphost-examples=')) { + const deferred = deferAppHostExamples(html); + await page.route(new URL('/', baseURL).href, (route) => + route.fulfill({ response, body: deferred.html }) + ); + await page.route(`**/_astro/${deferred.filename}`, (route) => + route.fulfill({ contentType: 'text/html', body: deferred.examples }) + ); + } + await page.emulateMedia({ reducedMotion: 'reduce' }); + }); + + test('loads examples once on interaction and keeps the initial default useful', async ({ + page, + }) => { + const exampleRequests: string[] = []; + page.on('request', (request) => { + if (/\/_astro\/apphost-examples\./.test(request.url())) { + exampleRequests.push(request.url()); + } + }); + await page.goto('/'); + await dismissCookieConsentIfVisible(page); + const builder = page.locator('[data-apphost-builder]').first(); + const stage = builder.locator('[data-code-stage]'); + await expect(stage).toHaveAttribute('data-code-variant', 'frontend'); + await expect(stage).toContainText('.addViteApp("frontend"'); + await expect(builder.locator('.code-variant')).toHaveCount(1); + expect(exampleRequests).toHaveLength(0); + + await builder.locator('[data-toggle="database"]').click(); + await expect(stage).toHaveAttribute('data-code-variant', 'databaseFrontend'); + await builder.locator('[data-lang="csharp"]').click(); + await expect(stage).toHaveAttribute('data-code-lang', 'csharp'); + await expect(stage).toContainText('AddPostgres("db")'); + expect(exampleRequests).toHaveLength(1); + }); + + for (const failure of ['unavailable', 'invalid content']) { + test(`keeps the last preview and allows retry after ${failure}`, async ({ page }) => { + let requests = 0; + await page.route('**/_astro/apphost-examples.*.html', async (route) => { + requests++; + if (requests === 1) { + await route.fulfill({ + status: failure === 'unavailable' ? 503 : 200, + contentType: 'text/html', + body: 'Examples unavailable', + }); + } else { + await route.fallback(); + } + }); + await page.goto('/'); + await dismissCookieConsentIfVisible(page); + const builder = page.locator('[data-apphost-builder]').first(); + const stage = builder.locator('[data-code-stage]'); + const status = builder.locator('[data-code-status]'); + await builder.locator('[data-lang="csharp"]').click(); + await expect(status).toBeVisible(); + await expect(status).toContainText('Select an option to try again.'); + await expect(stage).toHaveAttribute('data-code-lang', 'typescript'); + await expect(stage).toContainText('.addViteApp("frontend"'); + await expect(builder.locator('[data-apphost-code-display]')).toHaveAttribute( + 'aria-busy', + 'false' + ); + + await builder.locator('[data-lang="csharp"]').click(); + await expect(stage).toHaveAttribute('data-code-lang', 'csharp'); + await expect(status).not.toContainText('Could not load'); + expect(requests).toBe(2); + }); + } + + test('uses the latest selection when controls change during loading', async ({ page }) => { + const gate = Promise.withResolvers(); + await page.route('**/_astro/apphost-examples.*.html', async (route) => { + await gate.promise; + await route.fallback(); + }); + await page.goto('/'); + await dismissCookieConsentIfVisible(page); + const builder = page.locator('[data-apphost-builder]').first(); + await builder.locator('[data-toggle="database"]').click(); + await expect(builder.locator('[data-apphost-code-display]')).toHaveAttribute( + 'aria-busy', + 'true' + ); + await builder.locator('[data-toggle="api"]').click(); + await builder.locator('[data-lang="csharp"]').click(); + gate.resolve(); + + const stage = builder.locator('[data-code-stage]'); + await expect(stage).toHaveAttribute('data-code-lang', 'csharp'); + await expect(stage).toHaveAttribute('data-code-variant', 'databaseApiFrontend'); + await expect(stage).toContainText('AddPostgres("db")'); + }); +}); test('app host builder swaps visible code when toggles and language change', async ({ page }) => { await page.goto('/'); diff --git a/src/frontend/tests/e2e/homepage.spec.ts b/src/frontend/tests/e2e/homepage.spec.ts index 0f4c6843e..c67e77bd4 100644 --- a/src/frontend/tests/e2e/homepage.spec.ts +++ b/src/frontend/tests/e2e/homepage.spec.ts @@ -8,6 +8,24 @@ test.beforeEach(async ({ page }) => { await dismissCookieConsentIfVisible(page); }); +test('links directly to local observability and agent debugging guides', async ({ page }) => { + const links = page.locator('.observability-links a'); + await expect(links).toHaveText([ + 'Explore the Aspire dashboard', + 'Standalone dashboard', + 'OpenTelemetry concepts', + 'Debug with coding agents', + ]); + expect( + await links.evaluateAll((anchors) => anchors.map((anchor) => anchor.getAttribute('href'))) + ).toEqual([ + '/dashboard/overview/', + '/dashboard/standalone/', + '/fundamentals/telemetry/', + '/dashboard/ai-coding-agents/', + ]); +}); + test('renders a complete semantic landing page without horizontal overflow', async ({ page }) => { await expect(page.locator('main h1')).toHaveCount(1); await expect( diff --git a/src/frontend/tests/e2e/og-metadata.spec.ts b/src/frontend/tests/e2e/og-metadata.spec.ts index 067761d46..0ab9026d3 100644 --- a/src/frontend/tests/e2e/og-metadata.spec.ts +++ b/src/frontend/tests/e2e/og-metadata.spec.ts @@ -1,4 +1,8 @@ import { expect, test } from '@playwright/test'; +import { select, selectAll } from 'hast-util-select'; +import rehypeParse from 'rehype-parse'; +import { unified } from 'unified'; +import { FALLBACK_DESCRIPTION } from '../../src/utils/page-metadata'; /** * Smoke tests for the page-specific Open Graph metadata wired up in @@ -36,6 +40,85 @@ const PAGES: PageExpectation[] = [ }, ]; +for (const url of [ + '/', + '/dashboard/overview/', + '/dashboard/standalone/', + '/dashboard/ai-coding-agents/', + '/dashboard/standalone-for-python/', + '/dashboard/standalone-for-nodejs/', + '/get-started/ai-coding-agents/', + '/get-started/aspire-mcp-server/', + '/fundamentals/telemetry/', + '/app-host/migrate-from-docker-compose/', + '/da/', + '/uk/', +]) { + test(`uses the page description in standard and social metadata for ${url}`, async ({ + request, + }) => { + const response = await request.get(url); + expect(response.ok()).toBe(true); + const tree = unified() + .use(rehypeParse) + .parse(await response.text()); + const descriptions = selectAll('meta[name="description"]', tree); + const ogDescriptions = selectAll('meta[property="og:description"]', tree); + + expect(descriptions).toHaveLength(1); + expect(ogDescriptions).toHaveLength(1); + const description = descriptions[0].properties.content; + expect(description).toBeTruthy(); + expect(description).toBe(ogDescriptions[0].properties.content); + expect(description).not.toBe( + 'Aspire is a multi-language local dev-time orchestration tool chain for building, running, debugging, and deploying distributed applications.' + ); + }); +} + +test('preserves Starlight content languages and canonical links for translations and fallbacks', async ({ + request, +}) => { + for (const [url, locale, contentLanguage] of [ + ['/da/', 'da', 'da'], + ['/uk/', 'uk', 'uk'], + ['/ja/fundamentals/telemetry/', 'ja', 'ja'], + ['/da/fundamentals/telemetry/', 'da', 'en'], + ['/uk/fundamentals/telemetry/', 'uk', 'en'], + ]) { + const response = await request.get(url); + expect(response.ok()).toBe(true); + const tree = unified() + .use(rehypeParse) + .parse(await response.text()); + expect(select('html', tree)?.properties.lang).toBe(locale); + expect(select('main', tree)?.properties.lang).toBe(contentLanguage); + expect(select('link[rel="canonical"]', tree)?.properties.href).toBe(`https://aspire.dev${url}`); + expect(select(`link[hreflang="${locale}"]`, tree)?.properties.href).toBe( + `https://aspire.dev${url}` + ); + } +}); + +test('uses Starlight site description only when page frontmatter has no description', async ({ + request, +}) => { + const response = await request.get('/ja/architecture/resource-publishing/'); + expect(response.ok()).toBe(true); + const tree = unified() + .use(rehypeParse) + .parse(await response.text()); + const descriptions = selectAll('meta[name="description"]', tree); + const ogDescriptions = selectAll('meta[property="og:description"]', tree); + + expect(descriptions).toHaveLength(1); + expect(descriptions[0].properties.content).toBe( + 'Aspire is a multi-language local dev-time orchestration tool chain for building, running, debugging, and deploying distributed applications.' + ); + expect(ogDescriptions).toHaveLength(1); + expect(ogDescriptions[0].properties.content).toBe(FALLBACK_DESCRIPTION); +}); + function escape(value: string): string { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } diff --git a/src/frontend/tests/e2e/site-search.spec.ts b/src/frontend/tests/e2e/site-search.spec.ts index 14c5450c3..8c92154f7 100644 --- a/src/frontend/tests/e2e/site-search.spec.ts +++ b/src/frontend/tests/e2e/site-search.spec.ts @@ -34,6 +34,25 @@ async function typeSearchQuery(page: Page, query: string): Promise { } test.describe('site search dialog', () => { + test('does not index AppHost examples deferred from the homepage', async ({ page }) => { + test.skip(!process.env.CI, 'Pagefind is generated by the production build.'); + await page.goto('/'); + + const urls = await page.evaluate(async () => { + const pagefind = (await import( + /* @vite-ignore */ `${window.location.origin}/pagefind/pagefind.js` + )) as { + search: (query: string) => Promise<{ + results: Array<{ data: () => Promise<{ url: string }> }>; + }>; + }; + const response = await pagefind.search('publishAsKubernetes'); + return Promise.all(response.results.map(async (result) => (await result.data()).url)); + }); + + expect(urls).not.toContain('/'); + }); + test('renders keyboard shortcut hints in the footer', async ({ page }) => { await page.goto('/'); await dismissCookieConsentIfVisible(page); diff --git a/src/frontend/tests/unit/apphost-examples.vitest.test.ts b/src/frontend/tests/unit/apphost-examples.vitest.test.ts new file mode 100644 index 000000000..af0356171 --- /dev/null +++ b/src/frontend/tests/unit/apphost-examples.vitest.test.ts @@ -0,0 +1,54 @@ +import { selectAll } from 'hast-util-select'; +import rehypeParse from 'rehype-parse'; +import { unified } from 'unified'; +import { describe, expect, test } from 'vitest'; +import { deferAppHostExamples } from '../../config/apphost-examples.mjs'; + +const csharp = (copyLabel = 'Copy') => + ``; +const typescript = (copyLabel = 'Copy') => + `
await builder.addViteApp("frontend");
await builder.addPostgres("database");
`; +const prefix = 'Aspire & apps'; +const suffix = '

Other homepage content

'; +const homepage = (copyLabel = 'Copy') => + `${prefix}

AppHost

${csharp(copyLabel)}${typescript(copyLabel)}
${suffix}`; +const html = homepage(); + +describe('deferred AppHost examples', () => { + test('keeps only the default frame while preserving other HTML and scoped classes', () => { + const result = deferAppHostExamples(html); + const tree = unified().use(rehypeParse).parse(result.html); + const variants = selectAll('[data-apphost-builder] .code-variant', tree); + + expect(variants).toHaveLength(1); + expect(variants[0].properties.dataVariant).toBe('frontend'); + expect(result.html).toContain('
Typing animation'); + }); + + test('uses one content-addressed file containing the original highlighted examples', () => { + const result = deferAppHostExamples(html); + + expect(result.examples).not.toContain('class="copy"'); + expect(result.filename).toMatch(/^apphost-examples\.[a-f0-9]{16}\.html$/); + expect(result.html).toContain(`data-apphost-examples="/_astro/${result.filename}"`); + expect(deferAppHostExamples(html).filename).toBe(result.filename); + expect(deferAppHostExamples(html.replace('addPostgres', 'addSqlServer')).filename).not.toBe( + result.filename + ); + expect(deferAppHostExamples(homepage('Kopier')).filename).toBe(result.filename); + }); + + test('fails instead of publishing a broken default preview', () => { + expect(() => deferAppHostExamples('
No builder
')).toThrow( + 'missing builder or default example' + ); + expect(() => + deferAppHostExamples(html.replace('data-code-lang="typescript"', 'data-code-lang="unknown"')) + ).toThrow('missing builder or default example'); + }); +}); diff --git a/src/frontend/tests/unit/custom-components.vitest.test.ts b/src/frontend/tests/unit/custom-components.vitest.test.ts index 0b2eef97b..c6889c99f 100644 --- a/src/frontend/tests/unit/custom-components.vitest.test.ts +++ b/src/frontend/tests/unit/custom-components.vitest.test.ts @@ -626,6 +626,7 @@ const basicRenderCases: BasicRenderCase[] = [ 'data-editor-caret', 'data-editor-motion-toggle', 'data-disable-copy', + 'data-pagefind-ignore', 'data-toggle="database"', ], }, diff --git a/src/frontend/tests/unit/dashboard-agent-commands.vitest.test.ts b/src/frontend/tests/unit/dashboard-agent-commands.vitest.test.ts new file mode 100644 index 000000000..a3da54c0e --- /dev/null +++ b/src/frontend/tests/unit/dashboard-agent-commands.vitest.test.ts @@ -0,0 +1,29 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, expect, test } from 'vitest'; + +const testsDir = path.dirname(fileURLToPath(import.meta.url)); +const docsRoot = path.resolve(testsDir, '..', '..', 'src', 'content', 'docs'); + +describe('standalone dashboard MCP commands', () => { + for (const file of [ + 'dashboard/standalone.mdx', + 'dashboard/ai-coding-agents.mdx', + 'reference/cli/commands/aspire-agent-mcp.mdx', + ]) { + test(`${file} uses an explicit API key instead of a browser login token`, () => { + const source = readFileSync(path.join(docsRoot, file), 'utf8'); + const commands = [...source.matchAll(/^\s*aspire agent mcp .*--dashboard-url.*$/gm)].map( + (match) => match[0].trim() + ); + + expect(commands).not.toHaveLength(0); + for (const command of commands) { + expect(command).toContain('--dashboard-url "http://localhost:18888"'); + expect(command).toContain('--api-key ""'); + expect(command).not.toContain('/login?t='); + } + }); + } +}); diff --git a/src/frontend/tests/unit/homepage-markdown.vitest.test.ts b/src/frontend/tests/unit/homepage-markdown.vitest.test.ts new file mode 100644 index 000000000..e30344933 --- /dev/null +++ b/src/frontend/tests/unit/homepage-markdown.vitest.test.ts @@ -0,0 +1,151 @@ +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { describe, expect, test } from 'vitest'; +import { aspireVersionPlaceholdersIntegration } from '../../config/aspire-version-placeholders-integration.mjs'; +import { currentAspireVersion } from '../../config/aspire-versions.mjs'; +import { renderHomepageMarkdown } from '../../config/homepage-markdown.mjs'; +import { locales } from '../../config/locales'; + +function homepage(title = 'Compose distributed apps in code.', prefix = '') { + return ` + +
+
+
+

Free and open source

+

${title}

+

Model, run, observe, and deploy your application.

+ Build your first app +
+
+
Inactive builder variants
+
Default builder variant
Inactive builder variants
+
+
+
+

Local OpenTelemetry observability

+

Read application logs, distributed traces, and resource health.

+ Standalone dashboard +

Application context for coding agents

+ Set up your agent +
Simulated terminal output
+ + +
aspire run4 resources healthy
+

Useful quote.

Steven PriceSoftware Engineering Manager
+ + + +
+
Footer navigation
+
+ `; +} + +describe('homepage Markdown', () => { + test('keeps the real hero, explanations, links, and warnings without decorative UI', async () => { + const markdown = await renderHomepageMarkdown(homepage()); + + expect(markdown).toContain('# Compose distributed apps in code.'); + expect(markdown).toMatch(/^# Compose distributed apps in code\./); + expect(markdown).toContain('## Local OpenTelemetry observability'); + expect(markdown).toContain('Read application logs, distributed traces, and resource health.'); + expect(markdown).toContain('[Build your first app](/get-started/first-app/)'); + expect(markdown).toContain('[Standalone dashboard](/dashboard/standalone/)'); + expect(markdown).toContain('[Set up your agent](/get-started/ai-coding-agents/)'); + expect(markdown).toContain('### Deploy the model'); + expect(markdown).toContain('* `aspire run`\n* 4 resources healthy'); + expect(markdown).toContain( + '**[Steven Price](https://example.com)** — Software Engineering Manager' + ); + expect(markdown).toContain('Keep application telemetry private.'); + expect(markdown).not.toMatch( + /Free and open source|Site navigation|Footer navigation|Inactive builder|Simulated terminal|Animated topology|not content| { + const markdown = await renderHomepageMarkdown(homepage()); + + expect(markdown).toContain( + '```typescript\nconst builder = await createBuilder();\nawait builder.build().run();\n```' + ); + expect(markdown).toContain( + '```csharp\nvar builder = DistributedApplication.CreateBuilder(args);\nbuilder.Build().Run();\n```' + ); + expect(markdown).not.toContain('Copy'); + }); + + test('uses the rendered locale content and links without inventing English copy', async () => { + const markdown = await renderHomepageMarkdown(homepage('Lokale apps', '/da')); + expect(markdown).toContain('# Lokale apps'); + expect(markdown).toContain('(/da/dashboard/standalone/)'); + expect(markdown).not.toContain('Compose distributed apps in code.'); + }); + + test('fails explicitly if a redesign removes the required content landmarks', async () => { + await expect(renderHomepageMarkdown('

Aspire

')).rejects.toThrow( + 'missing homepage content landmarks' + ); + }); + + test('finalizes every existing homepage companion and retains ordinary Markdown normalization', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'aspire-homepage-markdown-')); + try { + await mkdir(path.join(directory, '_astro')); + for (const locale of Object.keys(locales)) { + const prefix = locale === 'root' ? '' : `/${locale}`; + const htmlDirectory = path.join(directory, locale === 'root' ? '' : locale); + await mkdir(htmlDirectory, { recursive: true }); + await writeFile(path.join(htmlDirectory, 'index.html'), homepage(locale, prefix)); + await writeFile( + path.join(directory, `${locale === 'root' ? 'index' : locale}.md`), + '# Aspire\n\n' + ); + } + await writeFile(path.join(directory, 'guide.md'), 'Use Aspire %ASPIRE_VERSION%.'); + + await aspireVersionPlaceholdersIntegration().hooks['astro:build:done']({ + dir: pathToFileURL(`${directory}${path.sep}`), + }); + + for (const locale of Object.keys(locales)) { + const markdown = await readFile( + path.join(directory, `${locale === 'root' ? 'index' : locale}.md`), + 'utf8' + ); + expect(markdown).toContain(`# ${locale}`); + expect(markdown).toContain('Read application logs'); + expect(markdown).not.toContain(' Date: Fri, 11 Sep 2026 07:11:16 -0500 Subject: [PATCH 13/29] Bump OpenTelemetry.Exporter.OpenTelemetryProtocol and 4 others (#1602) Bumps OpenTelemetry.Exporter.OpenTelemetryProtocol from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Extensions.Hosting from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Instrumentation.AspNetCore from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Instrumentation.Http from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Instrumentation.Runtime from 1.17.0 to 1.18.0 --- updated-dependencies: - dependency-name: OpenTelemetry.Exporter.OpenTelemetryProtocol dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-selected - dependency-name: OpenTelemetry.Extensions.Hosting dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-selected - dependency-name: OpenTelemetry.Instrumentation.AspNetCore dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-selected - dependency-name: OpenTelemetry.Instrumentation.Http dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-selected - dependency-name: OpenTelemetry.Instrumentation.Runtime dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: nuget-selected ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/statichost/StaticHost/StaticHost.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/statichost/StaticHost/StaticHost.csproj b/src/statichost/StaticHost/StaticHost.csproj index b706d85b7..944a617ef 100644 --- a/src/statichost/StaticHost/StaticHost.csproj +++ b/src/statichost/StaticHost/StaticHost.csproj @@ -15,11 +15,11 @@ - - - - - + + + + + From b603774f277bceddb26be3bd6a97e64e36637295 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 07:11:24 -0500 Subject: [PATCH 14/29] build(deps): bump the github-actions group across 1 directory with 2 updates (#1601) Bumps the github-actions group with 2 updates in the / directory: [github/gh-aw-actions/setup](https://github.com/github/gh-aw-actions) and [github/gh-aw-actions/setup-cli](https://github.com/github/gh-aw-actions). Updates `github/gh-aw-actions/setup` from 0.87.1 to 0.88.0 - [Release notes](https://github.com/github/gh-aw-actions/releases) - [Changelog](https://github.com/github/gh-aw-actions/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/gh-aw-actions/compare/423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3...afc709f45ed6a3f756eb4551856c6a9c42e15b2c) Updates `github/gh-aw-actions/setup-cli` from 0.87.1 to 0.88.0 - [Release notes](https://github.com/github/gh-aw-actions/releases) - [Changelog](https://github.com/github/gh-aw-actions/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/gh-aw-actions/compare/423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3...afc709f45ed6a3f756eb4551856c6a9c42e15b2c) --- updated-dependencies: - dependency-name: github/gh-aw-actions/setup dependency-version: 0.87.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/gh-aw-actions/setup-cli dependency-version: 0.87.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/agentics-maintenance.yml | 30 +++++++++++----------- .github/workflows/copilot-setup-steps.yml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml index a6b68de43..e54daad7c 100644 --- a/.github/workflows/agentics-maintenance.yml +++ b/.github/workflows/agentics-maintenance.yml @@ -96,7 +96,7 @@ jobs: pull-requests: write steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -134,7 +134,7 @@ jobs: actions: write steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -163,7 +163,7 @@ jobs: persist-credentials: false - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -178,7 +178,7 @@ jobs: await main(); - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup-cli@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: version: v0.81.6 @@ -210,7 +210,7 @@ jobs: pull-requests: write steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -256,7 +256,7 @@ jobs: persist-credentials: false - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -302,7 +302,7 @@ jobs: persist-credentials: false - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -317,7 +317,7 @@ jobs: await main(); - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup-cli@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: version: v0.81.6 @@ -348,7 +348,7 @@ jobs: persist-credentials: false - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -363,7 +363,7 @@ jobs: await main(); - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup-cli@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: version: v0.81.6 @@ -453,7 +453,7 @@ jobs: persist-credentials: false - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -468,7 +468,7 @@ jobs: await main(); - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup-cli@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: version: v0.81.6 @@ -545,7 +545,7 @@ jobs: issues: write steps: - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -582,7 +582,7 @@ jobs: persist-credentials: false - name: Setup Scripts - uses: github/gh-aw-actions/setup@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: destination: ${{ runner.temp }}/gh-aw/actions @@ -597,7 +597,7 @@ jobs: await main(); - name: Install gh-aw - uses: github/gh-aw-actions/setup-cli@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup-cli@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: version: v0.81.6 diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 411080179..eec1f0083 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -21,6 +21,6 @@ jobs: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install gh-aw extension - uses: github/gh-aw-actions/setup-cli@423b3dc04bbf1b1797194a4a75aa5cf5d0d4f5b3 # v0.87.1 + uses: github/gh-aw-actions/setup-cli@afc709f45ed6a3f756eb4551856c6a9c42e15b2c # v0.88.0 with: version: v0.81.6 From 858b965a26aa0102aaaa49ee2f8a632aaa247bdf Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 14 Sep 2026 11:25:35 -0500 Subject: [PATCH 15/29] Hide the right TOC when the mobile TOC is visible (#1655) * Fix right TOC width at browser zoom levels Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Hide right TOC when mobile TOC is visible Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/frontend/src/styles/site.css | 14 ++++ src/frontend/tests/e2e/ui-regressions.spec.ts | 68 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/frontend/src/styles/site.css b/src/frontend/src/styles/site.css index 1c6eb5957..a3b62790d 100644 --- a/src/frontend/src/styles/site.css +++ b/src/frontend/src/styles/site.css @@ -1490,6 +1490,20 @@ it configures at which point the mobile toc should be replaced with the normal t display: flex; } + /* The mobile TOC replaces the right sidebar in this range. Release + the reserved sidebar column so the main content can use the space. */ + :root[data-has-toc] .right-sidebar-container { + width: 0; + } + + :root[data-has-toc] .right-sidebar-panel { + display: none; + } + + :root[data-has-sidebar][data-has-toc] .main-pane { + width: 100%; + } + :root[data-has-toc] .content-panel > .sl-container { margin-inline: 0; } diff --git a/src/frontend/tests/e2e/ui-regressions.spec.ts b/src/frontend/tests/e2e/ui-regressions.spec.ts index 49b0b9a4a..4b88e875e 100644 --- a/src/frontend/tests/e2e/ui-regressions.spec.ts +++ b/src/frontend/tests/e2e/ui-regressions.spec.ts @@ -1259,6 +1259,74 @@ test('sidebar collapse toggle stays visible without overlapping the H1 on no-TOC ).toBe(true); }); +test('mobile TOC replaces the right TOC across zoom levels and display sizes', async ({ page }) => { + test.skip( + page.viewportSize()?.width !== 1440, + 'The responsive TOC zoom matrix is covered once from the desktop project.' + ); + + await page.goto('/app-host/certificate-configuration/'); + await dismissCookieConsentIfVisible(page); + await waitForTopicSidebarReady(page); + + const cdp = await page.context().newCDPSession(page); + const mobileToc = page.locator('#starlight__on-this-page--mobile'); + const rightToc = page.locator('.right-sidebar-panel'); + const cases = [ + { resolution: '1366x768', width: 1366, height: 768, zoom: 1, mobile: true }, + { resolution: '1440x900', width: 1440, height: 900, zoom: 1.25, mobile: true }, + { resolution: '1920x1080', width: 1920, height: 1080, zoom: 1.25, mobile: true }, + { resolution: '2560x1440', width: 2560, height: 1440, zoom: 1.75, mobile: true }, + { resolution: '3840x2160', width: 3840, height: 2160, zoom: 3, mobile: true }, + { resolution: '1920x1080', width: 1920, height: 1080, zoom: 1, mobile: false }, + { resolution: '2560x1440', width: 2560, height: 1440, zoom: 1.5, mobile: false }, + { resolution: '3840x2160', width: 3840, height: 2160, zoom: 2, mobile: false }, + ]; + + try { + for (const testCase of cases) { + await cdp.send('Emulation.setDeviceMetricsOverride', { + width: Math.floor(testCase.width / testCase.zoom), + height: Math.floor(testCase.height / testCase.zoom), + deviceScaleFactor: testCase.zoom, + mobile: false, + screenWidth: testCase.width, + screenHeight: testCase.height, + }); + + const label = `${testCase.resolution} at ${testCase.zoom * 100}% zoom`; + + if (testCase.mobile) { + await expect(mobileToc, `${label} should show the mobile TOC`).toBeVisible(); + await expect(rightToc, `${label} should hide the right TOC`).toBeHidden(); + } else { + await expect(mobileToc, `${label} should hide the mobile TOC`).toBeHidden(); + await expect(rightToc, `${label} should show the right TOC`).toBeVisible(); + } + + const layout = await page.locator('.main-pane').evaluate((mainPane) => { + const bounds = mainPane.getBoundingClientRect(); + return { + documentOverflows: + document.documentElement.scrollWidth > document.documentElement.clientWidth, + rightEdge: bounds.right, + viewportWidth: window.innerWidth, + }; + }); + + expect(layout.documentOverflows, `${label} should not overflow horizontally`).toBe(false); + if (testCase.mobile) { + expect( + Math.abs(layout.rightEdge - layout.viewportWidth), + `${label} should release the hidden right TOC column` + ).toBeLessThanOrEqual(1); + } + } + } finally { + await cdp.send('Emulation.clearDeviceMetricsOverride'); + } +}); + test('Aspire 13.5 preserves published section anchors', async ({ page }) => { test.skip( page.viewportSize()?.width !== 1440, From a30b4da0a09ca84a72f57c945ebfcb2d90712c07 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Sep 2026 08:59:53 +0000 Subject: [PATCH 16/29] Docs: capture 13.2 Foundry rename breaking changes and remove legacy AIFoundry references (#1163) * docs: clarify Foundry migration guidance Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs: update Foundry package versions Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b8ebe88c-337e-4d4a-aa80-e14c2c76289b --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Maddy Montaquila Copilot-Session: b8ebe88c-337e-4d4a-aa80-e14c2c76289b --- .../azure-ai-foundry-host.mdx | 12 +++++--- .../content/docs/ja/whats-new/aspire-13-2.mdx | 29 ++++++++++++------- .../content/docs/whats-new/aspire-13-2.mdx | 29 ++++++++++++------- .../src/content/docs/whats-new/aspire-9-4.mdx | 7 +++++ 4 files changed, 51 insertions(+), 26 deletions(-) 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 bc84cfbf3..ba8f6b6f5 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 @@ -54,10 +54,14 @@ Or, choose a manual installation approach: diff --git a/src/frontend/src/content/docs/ja/whats-new/aspire-13-2.mdx b/src/frontend/src/content/docs/ja/whats-new/aspire-13-2.mdx index 95cc8eb84..ff9714479 100644 --- a/src/frontend/src/content/docs/ja/whats-new/aspire-13-2.mdx +++ b/src/frontend/src/content/docs/ja/whats-new/aspire-13-2.mdx @@ -892,9 +892,9 @@ await builder.build().run(); この領域の新しい API には、`AddProject`、`AddModelDeployment`、`WithAppInsights`、`WithKeyVault`、`WithContainerRegistry`、`PublishAsHostedAgent`、`AddAndPublishPromptAgent` があります。 `RunAsFoundryLocal` は引き続きローカル モデル開発に使用できますが、親リソースが Foundry Local として構成されている場合、Foundry プロジェクトはサポートされません。 @@ -1227,22 +1227,29 @@ AppHost に統合されたダッシュボード シナリオは、As​​pire.H 接続プロパティのサフィックスが追加されました。接続プロパティに直接アクセスするコードの更新が必要になる場合があります。 -### AIFoundry から Foundry への移行 +### Foundry パッケージと名前空間の移行 -`Aspire.Hosting.Azure.AIFoundry` は、より広い `Aspire.Hosting.Foundry` サーフェスに置き換えられました。 +Aspire 13.2 では、Foundry ホスティング サーフェスが `Aspire.Hosting.Foundry` に統一されました。 -アップグレードする場合は、次の両方の変更を加えます: +| 以前の 13.1 名称 | 13.2 の名称 | +| ---------------- | ----------- | +| ホスティング パッケージ: `Aspire.Hosting.Azure.AIFoundry` | ホスティング パッケージ: `Aspire.Hosting.Foundry` | +| リソース型とモデル型の名前空間: `Aspire.Hosting.Azure` | リソース型とモデル型の名前空間: `Aspire.Hosting.Foundry` | +| `AddAzureAIFoundry(...)` | `AddFoundry(...)` | +| `AzureAIFoundryResource` | `FoundryResource` | +| `AzureAIFoundryExtensions` | `FoundryExtensions` | +| `AzureAIFoundryDeploymentResource` | `FoundryDeploymentResource` | +| `AIFoundryModel` | `FoundryModel` | -- `Aspire.Hosting.Azure.AIFoundry` パッケージ参照を `Aspire.Hosting.Foundry` に置き換えます。 -- `AddAzureAIFoundry()` から `AddFoundry()` に移行し、`AddDeployment()` または `AddModelDeployment()` を使用してデプロイメントを明示的に追加します。 +移行のヒント: パッケージ参照を更新し、リソース型またはモデル型を直接参照する場合は `using Aspire.Hosting.Foundry;` を追加し、`AddAzureAIFoundry(...)` を `AddFoundry(...)` に変更してください。`using Aspire.Hosting.Azure;` は、コードでその名前空間の他の型を使用しなくなった場合にのみ削除してください。拡張メソッドの名前空間は引き続き `Aspire.Hosting` です。 -```xml title="AppHost project file" +```xml title="XML — AppHost project file" - + ``` -```csharp title="移行例" +```csharp title="C# — 移行例" // 移行前 var ai = builder.AddAzureAIFoundry("ai"); diff --git a/src/frontend/src/content/docs/whats-new/aspire-13-2.mdx b/src/frontend/src/content/docs/whats-new/aspire-13-2.mdx index 5e5dfc396..778e407f8 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-13-2.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-13-2.mdx @@ -875,9 +875,9 @@ New APIs in this area include `AddProject`, `AddModelDeployment`, `WithAppInsigh @@ -1280,22 +1280,29 @@ C# apps that consume the Aspire client integrations (for example, `AddNpgsqlData For the full per-resource property catalog, see the Connection properties section on each integration's *connect* page — for example, [Connect to Azure Cosmos DB](/integrations/cloud/azure/azure-cosmos-db/azure-cosmos-db-connect/#connection-properties), [Connect to SQL Server](/integrations/databases/sql-server/sql-server-connect/#connection-properties), or [Connect to GitHub Models](/integrations/ai/github-models/github-models-connect/#connection-properties). -### AIFoundry to Foundry transition +### Foundry package and namespace transition -`Aspire.Hosting.Azure.AIFoundry` was replaced by the broader `Aspire.Hosting.Foundry` surface. +Aspire 13.2 standardizes the Foundry hosting surface under `Aspire.Hosting.Foundry`. -When upgrading, make both of these changes: +| Previous 13.1 name | 13.2 name | +| ------------------ | --------- | +| Hosting package: `Aspire.Hosting.Azure.AIFoundry` | Hosting package: `Aspire.Hosting.Foundry` | +| Resource and model namespace: `Aspire.Hosting.Azure` | Resource and model namespace: `Aspire.Hosting.Foundry` | +| `AddAzureAIFoundry(...)` | `AddFoundry(...)` | +| `AzureAIFoundryResource` | `FoundryResource` | +| `AzureAIFoundryExtensions` | `FoundryExtensions` | +| `AzureAIFoundryDeploymentResource` | `FoundryDeploymentResource` | +| `AIFoundryModel` | `FoundryModel` | -- Replace the `Aspire.Hosting.Azure.AIFoundry` package reference with `Aspire.Hosting.Foundry`. -- Migrate from `AddAzureAIFoundry()` to `AddFoundry()`, then add deployments explicitly with `AddDeployment()` or `AddModelDeployment()`. +Migration tip: update your package reference, add `using Aspire.Hosting.Foundry;` for direct resource or model type references, and rename `AddAzureAIFoundry(...)` to `AddFoundry(...)`. Remove `using Aspire.Hosting.Azure;` only if your code no longer uses other types from that namespace. Extension methods remain in the `Aspire.Hosting` namespace. -```xml title="AppHost project file" +```xml title="XML — AppHost project file" - + ``` -```csharp title="Migration example" +```csharp title="C# — Migration example" // Before var ai = builder.AddAzureAIFoundry("ai"); diff --git a/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx b/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx index 59e99f12b..1532ae4de 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx @@ -1081,6 +1081,13 @@ var webService = builder.AddProject("webservice") builder.Build().Run(); ``` + + #### Client integration Once you've configured the [Azure AI Foundry resource](https://aspire.dev/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-get-started/) in your AppHost, consume it in your services using the [Azure AI Inference SDK](https://aspire.dev/integrations/cloud/azure/azure-ai-inference/azure-ai-inference-get-started/) or [OpenAI SDK](https://aspire.dev/integrations/cloud/azure/azure-openai/azure-openai-get-started/) for compatible models: From 173e01fbbcd82f13839ef1c0ec02e0c0975d0e59 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Sep 2026 11:27:15 -0500 Subject: [PATCH 17/29] Update deployment docs to pipeline-step APIs and remove legacy callback annotation references (#1158) * Update deployment docs to pipeline-step API Refresh custom deployment examples for pipeline steps and clarify legacy callback references in deployment, diagnostics, and release notes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5b0c81a3-d822-462e-8cf5-8eb6debfe968 * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Restore historical What's new content Keep release-version articles unchanged while retaining the current pipeline API updates elsewhere. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address deployment docs review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b156fe61-0b1c-460c-9735-1eaeaa356b0a * Align Aspire 9.4 deployment example with pipelines Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b156fe61-0b1c-460c-9735-1eaeaa356b0a --------- Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: David Pine Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Maddy Montaquila Copilot-Session: 5b0c81a3-d822-462e-8cf5-8eb6debfe968 Copilot-Session: b156fe61-0b1c-460c-9735-1eaeaa356b0a --- .../docs/deployment/custom-deployments.mdx | 253 ++++++++---------- .../src/content/docs/deployment/pipelines.mdx | 4 +- .../docs/diagnostics/aspirepipelines001.mdx | 10 +- .../docs/diagnostics/aspirepipelines002.mdx | 8 +- .../docs/diagnostics/aspirepipelines003.mdx | 13 +- .../content/docs/ja/deployment/pipelines.mdx | 4 +- .../src/content/docs/whats-new/aspire-9-4.mdx | 36 ++- 7 files changed, 144 insertions(+), 184 deletions(-) diff --git a/src/frontend/src/content/docs/deployment/custom-deployments.mdx b/src/frontend/src/content/docs/deployment/custom-deployments.mdx index 257478541..0b7e34ff6 100644 --- a/src/frontend/src/content/docs/deployment/custom-deployments.mdx +++ b/src/frontend/src/content/docs/deployment/custom-deployments.mdx @@ -4,22 +4,21 @@ seoTitle: Build custom Aspire deployment pipelines for your apps description: Build container images from your Aspire resources and create custom deployment pipelines — extend publishing, target new platforms, and integrate with existing CD tools. --- -import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; -import LearnMore from '@components/LearnMore.astro'; +import { Aside } from '@astrojs/starlight/components'; Aspire provides powerful APIs for building container images from your resources during publishing and deployment operations. This article covers the key components that enable programmatic container image creation and progress reporting. -During publishing and deployment, the container image builder is available to create images for resources that need them. Aspire uses this builder when a resource requires a container image, such as when publishing with Docker Compose. The process involves two main components: +During publishing and deployment, the container image manager is available to create images for resources that need them. Aspire uses this manager when a resource requires a container image, such as when publishing with Docker Compose. The process involves two main components: -- `IResourceContainerImageBuilder`: The service that turns resource definitions into runnable container images. +- `IResourceContainerImageManager`: The service that builds and pushes container images for resources. - `IPipelineActivityReporter`: The API that provides structured progress reporting during long-running operations. These APIs give you fine-grained control over the image building process and provide real-time feedback to users during lengthy build operations. @@ -37,25 +36,26 @@ Consider using the container image building and progress reporting APIs in these container images automatically without requiring these APIs. -## Resource container image builder API +## Resource container image manager API -The `IResourceContainerImageBuilder` is the core service in the `Aspire.Hosting.Publishing` layer that converts resource definitions into container images. It analyzes each resource in your distributed application model and determines whether to: +The `IResourceContainerImageManager` is the core service in the `Aspire.Hosting.Publishing` layer that converts resource definitions into container images. It analyzes each resource in your distributed application model and determines whether to: - Reuse an existing image. - Build from a .NET project using `dotnet publish /t:PublishContainer`. - Build from a Dockerfile using the local container runtime. -### Container build options +### Configure container builds -The `ContainerBuildOptions` class provides strongly typed configuration for container builds. This class allows you to specify: +Configure each compute resource with `WithContainerBuildOptions`. The callback receives a `ContainerBuildOptionsCallbackContext` that allows you to specify: +- **Destination**: Push the image to a registry or save it as an archive. - **Image format**: Docker or Open Container Initiative (OCI) format. - **Target platform**: Linux x64, Windows, ARM64, etc. - **Output path**: Where to save the built images. ### Container runtime health checks -The builder performs container runtime health checks (Docker/Podman) only when at least one resource requires a Dockerfile build. This change eliminates false-positive errors in projects that publish directly from .NET assemblies. If the container runtime is required but unhealthy, the builder throws an explicit `InvalidOperationException` to surface the problem early. +The manager performs container runtime health checks (Docker/Podman) only when at least one resource requires a Dockerfile build. This change eliminates false-positive errors in projects that publish directly from .NET assemblies. If the container runtime is required but unhealthy, the manager throws an explicit `InvalidOperationException` to surface the problem early. ## Pipeline activity reporter API @@ -65,52 +65,40 @@ The `PipelineActivityReporter` API enables structured progress reporting during The progress reporter uses a hierarchical model with guaranteed ordering and thread-safe operations: -| Concept | Description | CLI Rendering | Behavior | -| -------------------- | -------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | -| **Step** | Top-level phase, such as "Build images" or "Deploy workloads". | Step message with status glyph and elapsed time. | Forms a strict tree structure; nested steps are unsupported. Steps are created automatically during pipeline execution. | -| **Task** | Discrete unit of work nested under a step. | Task message with indentation. | Belongs to a single step; supports parallel creation with deterministic completion ordering. | -| **Completion state** | Final status: `Completed`, `Warning`, or `Error`. | ✅ (Completed)
⚠️ (Warning)
❌ (Error) | Each step/task transitions exactly once to a final state. | +| Concept | Description | CLI Rendering | Behavior | +| -------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| **Step** | Top-level phase, such as "Build images" or "Deploy workloads". | Step message with status glyph and elapsed time. | Forms a strict tree structure; nested steps are unsupported. Steps are created automatically during pipeline execution. | +| **Task** | Discrete unit of work nested under a step. | Task message with indentation. | Belongs to a single step; supports parallel creation with deterministic completion ordering. | +| **Completion state** | Final status: `Completed`, `CompletedWithWarning`, or `CompletedWithError`. | ✅ (Completed)
⚠️ (Completed with warning)
❌ (Completed with error) | Each step/task transitions exactly once to a final state. | ### API structure and usage The reporter API provides structured access to progress reporting with the following characteristics: -- **Acquisition**: Retrieved from `PublishingContext.ActivityReporter` or through the `PipelineStepContext.ReportingStep` property in pipeline steps. -- **Step creation**: Steps are now created automatically during pipeline execution. The `CreateStepAsync(title, ct)` method returns an `IReportingStep`. +- **Acquisition**: The pipeline runner creates an `IReportingStep` for each pipeline step and exposes it through `PipelineStepContext.ReportingStep`. +- **Step creation**: Register steps with `WithPipelineStepFactory` or `builder.Pipeline.AddStep`. The pipeline runner creates the corresponding reporting step during execution. - **Task creation**: `IReportingStep.CreateTaskAsync(title, ct)` returns an `IReportingTask`. - **State transitions**: `SucceedAsync`, `WarnAsync`, `FailAsync` methods accept a summary message. -- **Completion**: `CompletePublishAsync(message, state, isDeploy, ct)` marks the entire operation. +- **Completion**: Complete individual tasks in the callback. The runner disposes the reporting step after the callback and completes the overall pipeline operation. - **Ordering**: Creation and completion events preserve call order; updates are serialized. - **Cancellation**: All APIs accept `CancellationToken` and propagate cancellation to the CLI. - **Disposal contract**: Disposing steps automatically completes them if unfinished, preventing orphaned phases. ## Example: Build container images and report progress -To use these APIs, add a `PublishingCallbackAnnotation`, a `DeployingCallbackAnnotation`, or both to a resource in your app model. You can annotate custom (or built-in) resources by adding annotations to the `IResource.Annotations` collection. +To use these APIs, register pipeline steps with `WithPipelineStepFactory` (resource-level) or `builder.Pipeline.AddStep` (application-level). This lets custom resources participate in publish and deploy flows with explicit step dependencies. As a developer, you can choose to: -- Use both annotations if your resource needs to do work in both publishing and deployment. For example, build images and generate manifests during publishing, then push images or configure deployment targets during deployment. Publishing always happens before deployment, so you can keep logic for each phase separate. -- Use only `PublishingCallbackAnnotation` if your resource only needs to do something during publishing. This is common when you just need to build artifacts or images, but don't need to do anything during deployment. -- Use only `DeployingCallbackAnnotation` if your resource only needs to do something during deployment. This fits cases where you use prebuilt images and just need to deploy or configure them. +- Register a step that is `requiredBy` `WellKnownPipelineSteps.Publish` when your resource needs custom publishing behavior. +- Register a step that is `requiredBy` `WellKnownPipelineSteps.Deploy` when your resource needs custom deployment behavior. +- Register both when your resource performs work in both phases and needs ordering between those steps. -Choose one or more annotations that match your resource's responsibilities to keep your application model clear and maintainable. This separation lets you clearly define logic for each phase, but you can use both the activity reporter and the resource container image builder in either callback as needed. +For broader pipeline orchestration patterns, see [Deployment pipelines](/deployment/pipelines/). For custom resource authoring basics, see [Create custom resources](/extensibility/custom-resources/). -### Example resource with annotations +### Example resource with pipeline steps -For example, consider the `ComputeEnvironmentResource` constructor: - -```csharp title="ComputeEnvironmentResource.cs" -public ComputeEnvironmentResource(string name) : base(name) -{ - Annotations.Add(new PublishingCallbackAnnotation(PublishAsync)); - Annotations.Add(new DeployingCallbackAnnotation(DeployAsync)); -} -``` - -When instantiated, it defines both a publishing and deploying callback annotation. - -Given the example `ComputeEnvironmentResource` type, imagine you have an extension method that you expose so consumers are able to add the compute environment: +For example, consider an extension method that registers two pipeline steps for a custom `ComputeEnvironmentResource`: ```csharp title="ComputeEnvironmentResourceExtensions.cs" public static class ComputeEnvironmentResourceExtensions @@ -121,163 +109,143 @@ public static class ComputeEnvironmentResourceExtensions { var resource = new ComputeEnvironmentResource(name); - return builder.AddResource(resource); + return builder.AddResource(resource) + .WithPipelineStepFactory( + stepName: $"{name}-build-images", + callback: PublishAsync, + requiredBy: [WellKnownPipelineSteps.Publish], + description: "Build container images and write deployment artifacts.") + .WithPipelineStepFactory( + stepName: $"{name}-deploy", + callback: DeployAsync, + dependsOn: [$"{name}-build-images"], + requiredBy: [WellKnownPipelineSteps.Deploy], + description: "Deploy generated artifacts to the target environment."); } } ``` +In the same class, define `PublishAsync` and `DeployAsync` as private static methods that each accept `PipelineStepContext` (shown in the next sections). +The explicit `dependsOn` relationship ensures the deploy step waits for this resource's image-build step, even when you add other custom publish or deploy steps to the pipeline. + The preceding code: - Defines an extension method on the `IDistributedApplicationBuilder`. - Accepts a `name` for the compute environment resource, protected by the `ResourceNameAttribute`. -- Instantiates a `ComputeEnvironmentResource` given the `name` and adds it to the `builder`. +- Instantiates a `ComputeEnvironmentResource` given the `name`. +- Registers a publish step and a deploy step with explicit dependencies. +- Adds both steps through `WithPipelineStepFactory`. +- Uses the validated resource name as the prefix for stable, unambiguous step names. ### Example AppHost -In your AppHost, you can add the `ComputeEnvironmentResource` to the application model like this: +In your AppHost, configure the project image output and add the `ComputeEnvironmentResource` to the application model: - - ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); var cache = builder.AddRedis("redis"); builder.AddProject("api") - .WithReference(cache); + .WithReference(cache) + .WithContainerBuildOptions(options => + { + options.Destination = ContainerImageDestination.Archive; + options.ImageFormat = ContainerImageFormat.Oci; + options.TargetPlatform = ContainerTargetPlatform.LinuxAmd64; + options.OutputPath = Path.Combine( + builder.AppHostDirectory, + "artifacts", + "images"); + }); builder.AddComputeEnvironment("compute-env"); builder.Build().Run(); ``` - - -:::note -Custom resource types and callback-based deployment extensibility aren't yet available in the TypeScript AppHost SDK, so this AppHost example is currently C#-only. -::: - - -The preceding code uses the `AddComputeEnvironment` extension method to add the `ComputeEnvironmentResource` to the application model. + + +The preceding code configures the project image as an OCI archive, then uses the `AddComputeEnvironment` extension method to add the `ComputeEnvironmentResource` to the application model. -### Publishing callback annotation +### Publish pipeline step -When you add the `ComputeEnvironmentResource`, it registers a `PublishingCallbackAnnotation`. The callback uses the `PublishAsync` method: +The publish step callback can build container images and generate deployment artifacts: -```csharp title="ComputeEnvironmentResource.cs" -private static async Task PublishAsync(PublishingContext context) +```csharp title="ComputeEnvironmentResourceExtensions.cs" +private static async Task PublishAsync(PipelineStepContext context) { - var reporter = context.ActivityReporter; - var imageBuilder = context.Services.GetRequiredService(); + var imageManager = context.Services.GetRequiredService(); + var reportingStep = context.ReportingStep; - // Build container images for all project resources in the application - await using (var buildStep = await reporter.CreateStepAsync( - "Build container images", context.CancellationToken)) - { - // Find all resources that need container images - var projectResources = context.Model.Resources - .OfType() - .ToList(); - - if (projectResources.Count > 0) - { - // Configure how images should be built - var buildOptions = new ContainerBuildOptions - { - ImageFormat = ContainerImageFormat.Oci, - TargetPlatform = ContainerTargetPlatform.LinuxAmd64, - OutputPath = Path.Combine(context.OutputPath, "images") - }; - - var buildTask = await buildStep.CreateTaskAsync( - $"Building {projectResources.Count} container image(s)", context.CancellationToken); - - // Build all the container images - await imageBuilder.BuildImagesAsync( - projectResources, buildOptions, context.CancellationToken); - - await buildTask.SucceedAsync( - $"Built {projectResources.Count} image(s) successfully", context.CancellationToken); - } - else - { - var skipTask = await buildStep.CreateTaskAsync( - "No container images to build", context.CancellationToken); - - await skipTask.SucceedAsync("Skipped - no project resources found", context.CancellationToken); - } - - await buildStep.SucceedAsync("Container image build completed", context.CancellationToken); - } + var projectResources = context.Model.Resources + .OfType() + .ToList(); - // Generate deployment manifests - await using (var manifestStep = await reporter.CreateStepAsync( - "Generate deployment manifests", context.CancellationToken)) + if (projectResources.Count > 0) { - var bicepTask = await manifestStep.CreateTaskAsync( - "Write main.bicep", context.CancellationToken); + var buildTask = await reportingStep.CreateTaskAsync( + $"Building {projectResources.Count} container image(s)", + context.CancellationToken); - // Write file to context.OutputPath … - await bicepTask.SucceedAsync( - $"main.bicep at {context.OutputPath}", context.CancellationToken); + await imageManager.BuildImagesAsync(projectResources, context.CancellationToken); - await manifestStep.SucceedAsync("Manifests ready", context.CancellationToken); + await buildTask.SucceedAsync( + $"Built {projectResources.Count} image(s) successfully", + context.CancellationToken); + } + else + { + var skipTask = await reportingStep.CreateTaskAsync( + "No container images to build", + context.CancellationToken); + await skipTask.SucceedAsync("Skipped - no project resources found", context.CancellationToken); } - // Complete the publishing operation - await reporter.CompletePublishAsync( - completionMessage: "Publishing pipeline completed successfully", - completionState: CompletionState.Completed, - cancellationToken: context.CancellationToken); + var manifestTask = await reportingStep.CreateTaskAsync( + "Generate deployment manifests", + context.CancellationToken); + // Write deployment files... + await manifestTask.SucceedAsync("Manifests ready", context.CancellationToken); } ``` The preceding code: -- Implements a publishing pipeline that builds container images and generates deployment manifests. -- Uses the `IResourceContainerImageBuilder` API to build container images. -- Reports progress and completion status using the `PipelineActivityReporter` API. +- Implements a publish step that builds container images and generates deployment manifests. +- Uses the `IResourceContainerImageManager` API to build container images. +- Reports progress with `IReportingStep` tasks from `PipelineStepContext.ReportingStep`. -Your publishing callback might use `IResourceContainerImageBuilder` to build container images, while your deployment callback might use the built images and push them to a registry or deployment target. +Your publish step might use `IResourceContainerImageManager` to build images, while your deploy step might use those artifacts and push them to a registry or target environment. -### Deploying callback annotation +### Deploy pipeline step -Like the publishing callback, the deploying callback is registered using the `DeployingCallbackAnnotation` and calls the `DeployAsync` method: +The deploy step callback can apply deployment artifacts and report task-level progress: -```csharp title="ComputeEnvironmentResource.cs" -private static async Task DeployAsync(DeployingContext context) +```csharp title="ComputeEnvironmentResourceExtensions.cs" +private static async Task DeployAsync(PipelineStepContext context) { - var reporter = context.ActivityReporter; - - await using (var deployStep = await reporter.CreateStepAsync( - "Deploy to target environment", context.CancellationToken)) - { - var applyTask = await deployStep.CreateTaskAsync( - "Apply Kubernetes manifests", context.CancellationToken); + var reportingStep = context.ReportingStep; - // Simulate deploying to Kubernetes cluster - await Task.Delay(1_000, context.CancellationToken); + var applyTask = await reportingStep.CreateTaskAsync( + "Apply Kubernetes manifests", + context.CancellationToken); - await applyTask.SucceedAsync("All workloads deployed", context.CancellationToken); - - await deployStep.SucceedAsync("Deployment to cluster completed", context.CancellationToken); - } + // Simulate deploying to Kubernetes cluster + await Task.Delay(1_000, context.CancellationToken); - // Complete the deployment operation - await reporter.CompletePublishAsync( - completionMessage: "Deployment completed successfully", - completionState: CompletionState.Completed, - isDeploy: true, - cancellationToken: context.CancellationToken); + await applyTask.SucceedAsync("All workloads deployed", context.CancellationToken); } ``` The preceding code: - Simulates deploying workloads to a Kubernetes cluster. -- Uses the `PipelineActivityReporter` API to create and manage deployment steps and tasks. -- Reports progress and marks each deployment phase as completed. -- Completes the deployment operation with a final status update. +- Uses `PipelineStepContext.ReportingStep` to create and complete deployment tasks. - Handles cancellation through the provided `CancellationToken`. ## Best practices @@ -286,7 +254,7 @@ When using these APIs, follow these guidelines: ### Image building -- Always specify explicit `ContainerBuildOptions` for production scenarios. +- Configure production resources with `WithContainerBuildOptions`. - Consider target platform requirements when building for deployment. - Use OCI format for maximum compatibility with container registries. - Handle `InvalidOperationException` when container runtime health checks fail. @@ -295,7 +263,6 @@ When using these APIs, follow these guidelines: - Encapsulate long-running logical phases in steps rather than emitting raw tasks. - Keep titles concise (under 60 characters) as the CLI truncates longer strings. -- Call `CompletePublishAsync` exactly once per publishing or deployment operation. - Treat warnings as recoverable and allow subsequent steps to proceed. - Treat errors as fatal and fail fast with clear diagnostics. - Use asynchronous, cancellation-aware operations to avoid blocking event processing. diff --git a/src/frontend/src/content/docs/deployment/pipelines.mdx b/src/frontend/src/content/docs/deployment/pipelines.mdx index 1eeb8aab4..06608baa5 100644 --- a/src/frontend/src/content/docs/deployment/pipelines.mdx +++ b/src/frontend/src/content/docs/deployment/pipelines.mdx @@ -680,8 +680,8 @@ The old publishing callback system has been removed and replaced with pipeline s **Removed APIs:** - `WithPublishingCallback` extension method -- `PublishingContext` and `PublishingCallbackAnnotation` -- `DeployingContext` and `DeployingCallbackAnnotation` +- `PublishingContext` and the legacy publish callback annotation type +- `DeployingContext` and the legacy deploy callback annotation type - `IDistributedApplicationPublisher` interface **New APIs:** diff --git a/src/frontend/src/content/docs/diagnostics/aspirepipelines001.mdx b/src/frontend/src/content/docs/diagnostics/aspirepipelines001.mdx index eccee9703..e8e0d72a6 100644 --- a/src/frontend/src/content/docs/diagnostics/aspirepipelines001.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspirepipelines001.mdx @@ -15,7 +15,7 @@ import { Badge } from '@astrojs/starlight/components'; > Pipeline infrastructure APIs are for evaluation purposes only and are subject to change or removal in future updates. Suppress this diagnostic to proceed. -Aspire introduced pipeline infrastructure APIs starting in version 9.2. These APIs provide core functionality for building deployment pipelines, including interfaces and types for pipeline activity reporting, step management, and publishing contexts. Pipeline infrastructure enables you to create custom deployment workflows and track their execution. +Aspire introduced pipeline infrastructure APIs starting in version 9.2. These APIs provide core functionality for building deployment pipelines, including interfaces and types for pipeline activity reporting, step management, and pipeline execution contexts. Pipeline infrastructure enables you to create custom deployment workflows and track their execution. Pipeline infrastructure APIs are considered experimental and are expected to change in future updates. @@ -23,15 +23,17 @@ Pipeline infrastructure APIs are considered experimental and are expected to cha This diagnostic applies to the following pipeline infrastructure APIs: +- `IDistributedApplicationPipeline` - Interface for configuring pipeline steps +- `PipelineStep` - Class that defines a pipeline action and its dependencies +- `PipelineContext` and `PipelineStepContext` - Contexts provided during pipeline execution - `IPipelineActivityReporter` - Interface for reporting pipeline activities - `IReportingStep` - Interface for managing pipeline steps - `IReportingTask` - Interface for managing tasks within a step -- `PublishingContext` - Context for publishing operations -- `PublishingCallbackAnnotation` - Annotation for publishing callbacks +- `WellKnownPipelineSteps` and `WellKnownPipelineTags` - Constants for standard steps and tags - Related extension methods and implementations :::note -In Aspire 13.5, only the `CompletionState` enumeration graduated from experimental and no longer triggers this diagnostic. The other APIs listed above remain experimental and continue to require suppressing `ASPIREPIPELINES001`. +In Aspire 13.5, the `CompletionState` enumeration graduated from experimental and no longer triggers this diagnostic. The APIs listed above remain experimental and continue to require suppressing `ASPIREPIPELINES001`. ::: ## To correct this error diff --git a/src/frontend/src/content/docs/diagnostics/aspirepipelines002.mdx b/src/frontend/src/content/docs/diagnostics/aspirepipelines002.mdx index 9e61a754b..6078c9cd2 100644 --- a/src/frontend/src/content/docs/diagnostics/aspirepipelines002.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspirepipelines002.mdx @@ -1,6 +1,6 @@ --- title: Compiler Error ASPIREPIPELINES002 -seoTitle: "ASPIREPIPELINES002: Deployment state manager APIs are for" +seoTitle: 'ASPIREPIPELINES002: Deployment state manager APIs are for' description: Learn what causes the Aspire compiler error ASPIREPIPELINES002 and how to fix it so your AppHost builds cleanly. --- @@ -24,12 +24,8 @@ Deployment state manager APIs are considered experimental and are expected to ch This diagnostic applies to the following deployment state manager APIs: - `IDeploymentStateManager` - Interface for managing deployment state +- `DeploymentStateSection` - A versioned section of persisted deployment state - Deployment state manager implementations -- `Deploy` property in `PublishingOptions` -- `ClearCache` property in `PublishingOptions` -- `Step` property in `PublishingOptions` -- `DeployingCallbackAnnotation` - Annotation for deploying callbacks -- Azure provisioning context providers - Related extension methods and implementations ## To correct this error diff --git a/src/frontend/src/content/docs/diagnostics/aspirepipelines003.mdx b/src/frontend/src/content/docs/diagnostics/aspirepipelines003.mdx index 4c3e3ac86..32f07ac8b 100644 --- a/src/frontend/src/content/docs/diagnostics/aspirepipelines003.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspirepipelines003.mdx @@ -1,6 +1,6 @@ --- title: Compiler Error ASPIREPIPELINES003 -seoTitle: "ASPIREPIPELINES003: Container image build APIs are for" +seoTitle: 'ASPIREPIPELINES003: Container image build APIs are for' description: Learn what causes the Aspire compiler error ASPIREPIPELINES003 and how to fix it so your AppHost builds cleanly. --- @@ -23,13 +23,14 @@ Container image build APIs are considered experimental and are expected to chang This diagnostic applies to the following container image build APIs: -- `IResourceContainerImageBuilder` - Interface for building container images -- `ContainerBuildOptions` - Options for configuring container builds +- `IResourceContainerImageManager` - Interface for building and pushing container images +- `ContainerImageBuildOptions` - Options for building an individual container image +- `ContainerBuildOptionsCallbackContext` - Context for configuring resource image builds +- `ContainerImageDestination` - Enumeration for selecting a registry or archive destination - `ContainerImageFormat` - Enumeration for specifying image format - `ContainerTargetPlatform` - Type for specifying target platform -- `ContainerTargetPlatformExtensions` - Extension methods for platform configuration -- Docker and Podman container runtime implementations -- Related extension methods and implementations +- `WithContainerBuildOptions` - Extension methods for configuring compute resource builds +- Related annotations, options, and extension methods ## To correct this error diff --git a/src/frontend/src/content/docs/ja/deployment/pipelines.mdx b/src/frontend/src/content/docs/ja/deployment/pipelines.mdx index 1528f152b..1d668a9ba 100644 --- a/src/frontend/src/content/docs/ja/deployment/pipelines.mdx +++ b/src/frontend/src/content/docs/ja/deployment/pipelines.mdx @@ -679,8 +679,8 @@ Aspire 13.0はより柔軟なパイプラインシステムで発行コールバ **削除された API:** - `WithPublishingCallback` 拡張メソッド -- `PublishingContext` と `PublishingCallbackAnnotation` -- `DeployingContext` と `DeployingCallbackAnnotation` +- `PublishingContext` とレガシー publish コールバック注釈型 +- `DeployingContext` とレガシー deploy コールバック注釈型 - `IDistributedApplicationPublisher` インターフェース **新しい API:** diff --git a/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx b/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx index 1532ae4de..c0542703a 100644 --- a/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx +++ b/src/frontend/src/content/docs/whats-new/aspire-9-4.mdx @@ -118,21 +118,21 @@ aspire exec --start-resource my-worker -- npm run build #### `aspire deploy` -The `aspire deploy` command supports extensible deployment workflows through the new [`DeployingCallbackAnnotation`](https://aspire.dev/fundamentals/annotations-overview/), enabling custom pre/post-deploy logic and richer integration with external systems during deployment operations. +The `aspire deploy` command introduced extensible deployment workflows, enabling custom logic and richer integration with external systems during deployment operations. **Key capabilities:** -- **Custom deployment hooks** using `Aspire.Hosting.ApplicationModel.DeployingCallbackAnnotation` to execute custom logic during the `aspire deploy` command -- **Workflow activity reporting** via the `Aspire.Hosting.Publishing.IPublishingActivityReporter` to support progress notifications and prompting in commmands -- **Integration with publish** - `aspire deploy` runs `Aspire.Hosting.Publishing.PublishingCallbackAnnotations` to support deploying artifacts emitted by publish steps, if applicable +- **Custom deployment steps** using `WithPipelineStepFactory` to execute custom logic during the `aspire deploy` command +- **Workflow activity reporting** through tasks created from `PipelineStepContext.ReportingStep`, with prompts provided by `IInteractionService` +- **Pipeline ordering and dependencies** using `dependsOn`, `requiredBy`, and well-known pipeline steps -The example below demonstrates using the `DeployingCallbackAnnotation` to register custom deployment behavior and showcases [CLI-based prompting](#-enhanced-publish-and-deploy-output) and progress notifications. +The example below shows the current pipeline-step approach for custom deployment behavior and showcases [CLI-based prompting](#-enhanced-publish-and-deploy-output) and progress notifications. ```csharp -#pragma warning disable ASPIREPUBLISHERS001 +#pragma warning disable ASPIREPIPELINES001 #pragma warning disable ASPIREINTERACTION001 -using Aspire.Hosting.Publishing; +using Aspire.Hosting.Pipelines; using Microsoft.Extensions.DependencyInjection; var builder = DistributedApplication.CreateBuilder(args); @@ -158,12 +158,11 @@ internal static class DataSeedJobBuilderExtensions var job = new DataSeedJobResource(name, seedDataPath); var resourceBuilder = builder.AddResource(job); - // Attach a DeployingCallbackAnnotation that will be invoked on `aspire deploy` - job.Annotations.Add(new DeployingCallbackAnnotation(async ctx => + resourceBuilder.WithPipelineStepFactory("seed-initial-data", async ctx => { CancellationToken ct = ctx.CancellationToken; - // Prompt the user for a confirmation using the interaction service + // Prompt the user for deployment input using the interaction service var interactionService = ctx.Services.GetRequiredService(); var envResult = await interactionService.PromptInputAsync( @@ -179,27 +178,22 @@ internal static class DataSeedJobBuilderExtensions cancellationToken: ct); - // Use the ActivityReporter to report progress on the seeding process - var reporter = ctx.ActivityReporter; - - var step = await reporter.CreateStepAsync("Seeding data", ct); - var task = await step.CreateTaskAsync($"Loading seed data from {seedDataPath}", ct); + // ReportingStep is the progress-reporting surface for this pipeline step. + var seedTask = await ctx.ReportingStep.CreateTaskAsync($"Loading seed data from {seedDataPath}", ct); try { // Do some work here await Task.Delay(3000); - await task.SucceedAsync("Seed data loaded", ct); - await step.SucceedAsync("Data seeding completed", ct); + await seedTask.SucceedAsync("Seed data loaded", ct); } catch (Exception ex) { - await task.FailAsync(ex.Message, ct); - await step.FailAsync("Data seeding failed", ct); + await seedTask.FailAsync(ex.Message, ct); throw; } - })); + }, requiredBy: [WellKnownPipelineSteps.Deploy]); return resourceBuilder; } @@ -213,7 +207,7 @@ This custom deployment logic executes as follows from the `aspire deploy` comman Now, integration owners can create sophisticated `aspire deploy` workflows. This work also provides a foundation for advanced deployment automation scenarios.