From e5d478247c7c63ee056a7900c2697f632a683292 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:25:22 -0600 Subject: [PATCH 01/90] Add WithBun() documentation to JavaScript integration page (#289) * Initial plan * Add WithBun() documentation to JavaScript integration page Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> * Update Bun example to use specific version tag Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --- .../integrations/frameworks/javascript.mdx | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx b/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx index 817015183..42d642ca8 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx @@ -18,7 +18,7 @@ import jsIcon from '@assets/icons/javascript.svg'; data-zoom-off /> -The Aspire JavaScript/TypeScript hosting integration enables you to orchestrate JavaScript applications alongside your Aspire projects in the AppHost. This integration provides a unified approach to running JavaScript applications with support for multiple package managers (npm, yarn, pnpm), runtimes (Node.js), and build tools (Vite, and more). +The Aspire JavaScript/TypeScript hosting integration enables you to orchestrate JavaScript applications alongside your Aspire projects in the AppHost. This integration provides a unified approach to running JavaScript applications with support for multiple package managers (npm, yarn, pnpm, bun), runtimes (Node.js), and build tools (Vite, and more). :::tip[Package rename] In Aspire 13.0, the `Aspire.Hosting.NodeJs` package was renamed to `Aspire.Hosting.JavaScript` to better reflect its broader support for JavaScript applications. @@ -106,7 +106,7 @@ var viteApp = builder.AddViteApp("vite-app", "./vite-app") - **Development script**: Runs the "dev" script (typically `vite`) during local development - **Build script**: Runs the "build" script (typically `vite build`) when publishing -- **Package manager**: Uses npm by default, but can be customized with `WithYarn()` or `WithPnpm()` +- **Package manager**: Uses npm by default, but can be customized with `WithYarn()`, `WithPnpm()`, or `WithBun()` The method accepts the same parameters as `AddJavaScriptApp`: @@ -183,6 +183,39 @@ var customApp = builder.AddJavaScriptApp("custom-app", "./custom-app") When publishing, Aspire uses `pnpm install --frozen-lockfile` if `pnpm-lock.yaml` exists, otherwise it uses `pnpm install`. +### Use Bun + +To use Bun as the package manager, call the `WithBun` extension method: + +```csharp title="C# — AppHost.cs" "WithBun" +var builder = DistributedApplication.CreateBuilder(args); + +var app = builder.AddViteApp("app", "./app") + .WithBun(); + +// Customize Bun with additional flags +var customApp = builder.AddViteApp("custom-app", "./custom-app") + .WithBun(installArgs: ["--frozen-lockfile"]); + +// After adding all resources, run the app... +``` + +When publishing, Aspire uses `bun install --frozen-lockfile` if `bun.lock` or `bun.lockb` exists, otherwise it uses `bun install`. + +Bun supports passing script arguments without the `--` separator, so commands like `bun run dev --port 3000` work without needing `bun run dev -- --port 3000`. + +When publishing to a container, `WithBun()` automatically configures a Bun build image (`oven/bun:1`) since Bun is not available in the default Node.js base images. To use a specific Bun version, configure a custom build image: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var app = builder.AddViteApp("app", "./app") + .WithBun() + .WithDockerfileBaseImage(buildImage: "oven/bun:1.1"); + +// After adding all resources, run the app... +``` + ## Customize scripts You can customize which scripts run during development and build: From b9de4ee1005726b23fbecf74bb9bb7cf068e3b06 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 11:19:35 -0600 Subject: [PATCH 02/90] Add documentation for deployment slot support in Azure App Service (#290) * Initial plan * Add documentation for deployment slot support to Azure App Service Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --- .../cloud/azure/azure-app-service.mdx | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-service.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-service.mdx index ea4ffad20..ca82f238d 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-service.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-app-service.mdx @@ -129,6 +129,67 @@ The preceding code: - Adds an application setting for `ASPNETCORE_ENVIRONMENT`. - Adds multiple tags for metadata and organization. +## Deployment slots + +[Deployment slots](https://learn.microsoft.com/azure/app-service/deploy-staging-slots) let you deploy your app to a staging environment for testing before swapping it into production. The `WithDeploymentSlot` extension method configures a deployment slot for the App Service environment: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddAzureAppServiceEnvironment("appservice") + .WithDeploymentSlot("staging"); + +var apiService = builder.AddProject("apiservice") + .WithHttpHealthCheck("/health") + .WithExternalHttpEndpoints(); + +builder.AddProject("webfrontend") + .WithExternalHttpEndpoints() + .WithHttpHealthCheck("/health") + .WithReference(apiService) + .WaitFor(apiService); + +builder.Build().Run(); +``` + +The preceding code configures all App Service websites to be deployed to a `staging` slot. + +### Deployment slot behavior + +When you deploy to a slot, the deployment behavior depends on whether the production App Service already exists: + +- **New App Service**: If the production App Service (production slot) doesn't exist at the time of deployment, Aspire deploys to both the production App Service and the specified deployment slot. +- **Existing App Service**: If the production App Service already exists, Aspire deploys only to the specified deployment slot. + +This behavior allows you to safely deploy and test changes in a staging environment before swapping to production. + +### Using parameters for deployment slots + +You can also specify the deployment slot value as a parameter, allowing the slot name to be provided at deployment time: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var slotName = builder.AddParameter("deploymentSlot"); + +builder.AddAzureAppServiceEnvironment("appservice") + .WithDeploymentSlot(slotName); + +// Add your projects and other resources... + +builder.Build().Run(); +``` + +With this configuration, you can specify the slot name when running `aspire deploy` by providing a value for the `deploymentSlot` parameter. + +### Applying customizations to slots + + + +When you customize App Service resources using `PublishAsAzureAppServiceWebsite` or `ConfigureInfrastructure`, those customizations apply to the production slot by default. If you need the same customizations on your deployment slot, you must apply them separately. This gives you fine-grained control over the configuration of each slot, allowing staging and production environments to have different settings when needed. + ## Provisioning-generated Bicep If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. From 151c77363b43d29f2edb4e579dbae2aa28d0b91f Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Sun, 25 Jan 2026 12:17:23 -0600 Subject: [PATCH 03/90] Add Azure integrations documentation and CLI command references - Created documentation for Azure Application Insights integration. - Created documentation for Azure Data Explorer (Kusto) integration. - Created documentation for Azure Log Analytics integration. - Created documentation for Azure Data Lake Storage integration. - Added `aspire doctor` command placeholder with redirect to main CLI command page. - Added documentation for `aspire ps` command to list running AppHost processes. - Added documentation for `aspire stop` command to stop running AppHost processes. --- run_git_commands.ps1 | 58 +++ src/frontend/config/sidebar/docs.topics.ts | 52 +-- .../config/sidebar/integrations.topics.ts | 16 + .../config/sidebar/reference.topics.ts | 2 + .../assets/icons/azure-dataexplorer-icon.svg | 1 + .../src/assets/icons/azure-datalake-icon.png | Bin 0 -> 9334 bytes .../src/content/docs/app-host/eventing.mdx | 114 +++++- .../src/content/docs/architecture/glossary.md | 25 -- .../docs/architecture/resource-examples.mdx | 118 +++--- .../aspirecontainershellexecution001.mdx | 46 +++ .../docs/diagnostics/aspiredotnettool.mdx | 44 +++ .../docs/diagnostics/aspireextension001.mdx | 49 +++ .../docs/diagnostics/aspireinteraction001.mdx | 38 +- .../docs/diagnostics/aspirepostgres001.mdx | 43 +++ .../src/content/docs/diagnostics/overview.mdx | 13 +- .../docs/extensibility/custom-resources.mdx | 292 +++++++++++++++ .../fundamentals/annotations-overview.mdx | 103 ++++++ .../docs/fundamentals/health-checks.mdx | 26 +- .../docs/fundamentals/networking-overview.mdx | 113 ++++++ .../docs/fundamentals/service-discovery.mdx | 77 +++- .../content/docs/get-started/aspire-sdk.mdx | 2 +- .../content/docs/get-started/first-app.mdx | 10 +- .../src/content/docs/get-started/glossary.mdx | 336 ++++++++++++++++++ .../docs/get-started/troubleshooting.mdx | 164 +++++++++ .../docs/get-started/what-is-aspire.mdx | 82 ++++- .../azure/azure-application-insights.mdx | 260 ++++++++++++++ .../cloud/azure/azure-data-explorer.mdx | 308 ++++++++++++++++ .../cloud/azure/azure-log-analytics.mdx | 157 ++++++++ .../cloud/azure/azure-sql-database.mdx | 105 ++++++ .../cloud/azure/azure-storage-blobs.mdx | 87 +++++ .../cloud/azure/azure-storage-datalake.mdx | 278 +++++++++++++++ .../cloud/azure/customize-resources.mdx | 8 +- .../docs/reference/cli/commands/aspire-ps.mdx | 85 +++++ .../reference/cli/commands/aspire-stop.mdx | 60 ++++ .../docs/reference/cli/commands/aspire.mdx | 2 + .../docs/reference/cli/configuration.mdx | 10 +- .../cli/includes/config-settings-table.md | 1 + src/frontend/src/data/integration-docs.json | 18 +- 38 files changed, 3068 insertions(+), 135 deletions(-) create mode 100644 run_git_commands.ps1 create mode 100644 src/frontend/src/assets/icons/azure-dataexplorer-icon.svg create mode 100644 src/frontend/src/assets/icons/azure-datalake-icon.png delete mode 100644 src/frontend/src/content/docs/architecture/glossary.md create mode 100644 src/frontend/src/content/docs/diagnostics/aspirecontainershellexecution001.mdx create mode 100644 src/frontend/src/content/docs/diagnostics/aspiredotnettool.mdx create mode 100644 src/frontend/src/content/docs/diagnostics/aspireextension001.mdx create mode 100644 src/frontend/src/content/docs/diagnostics/aspirepostgres001.mdx create mode 100644 src/frontend/src/content/docs/extensibility/custom-resources.mdx create mode 100644 src/frontend/src/content/docs/get-started/glossary.mdx create mode 100644 src/frontend/src/content/docs/get-started/troubleshooting.mdx create mode 100644 src/frontend/src/content/docs/integrations/cloud/azure/azure-application-insights.mdx create mode 100644 src/frontend/src/content/docs/integrations/cloud/azure/azure-data-explorer.mdx create mode 100644 src/frontend/src/content/docs/integrations/cloud/azure/azure-log-analytics.mdx create mode 100644 src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-datalake.mdx create mode 100644 src/frontend/src/content/docs/reference/cli/commands/aspire-ps.mdx create mode 100644 src/frontend/src/content/docs/reference/cli/commands/aspire-stop.mdx diff --git a/run_git_commands.ps1 b/run_git_commands.ps1 new file mode 100644 index 000000000..4dc0e4a77 --- /dev/null +++ b/run_git_commands.ps1 @@ -0,0 +1,58 @@ +# Change to the repository directory +Set-Location "E:\GitHub\aspire.dev" + +# 1. Stage all changes +Write-Host "===== Step 1: git add -A =====" +git add -A +if ($LASTEXITCODE -eq 0) { + Write-Host "Successfully staged all changes" +} else { + Write-Host "Error staging changes (exit code: $LASTEXITCODE)" +} + +# 2. Check status +Write-Host "`n===== Step 2: git status =====" +git status + +# 3. Commit with the provided message +Write-Host "`n===== Step 3: git commit =====" +$commitMessage = @" +Documentation coverage audit: CLI commands, diagnostics, and config updates + +## New CLI command documentation +- aspire-stop.mdx: Stop a running Aspire AppHost +- aspire-ps.mdx: List running Aspire AppHost processes + +## New diagnostic pages (experimental APIs) +- ASPIREINTERACTION001: Interaction service experimental API +- ASPIREDOTNETTOOL: .NET tool resource experimental API +- ASPIREPOSTGRES001: PostgreSQL MCP experimental API +- ASPIREEXTENSION001: Extension debugging experimental API +- ASPIRECONTAINERSHELLEXECUTION001: Container shell execution experimental API + +## Configuration updates +- Added missing polyglotSupportEnabled feature flag to config-settings-table.md +- Fixed stale feature flags in example settings.json + +## Navigation updates +- Updated sidebar with aspire ps and aspire stop commands +- Updated aspire.mdx commands table with new commands + +Note: aspire doctor command is covered by PR #270 +"@ + +git commit -m $commitMessage +if ($LASTEXITCODE -eq 0) { + Write-Host "Successfully committed changes" +} else { + Write-Host "Error during commit (exit code: $LASTEXITCODE)" +} + +# 4. Push changes +Write-Host "`n===== Step 4: git push =====" +git push +if ($LASTEXITCODE -eq 0) { + Write-Host "Successfully pushed changes" +} else { + Write-Host "Error during push (exit code: $LASTEXITCODE)" +} diff --git a/src/frontend/config/sidebar/docs.topics.ts b/src/frontend/config/sidebar/docs.topics.ts index 0d2791c6e..d8cd34189 100644 --- a/src/frontend/config/sidebar/docs.topics.ts +++ b/src/frontend/config/sidebar/docs.topics.ts @@ -422,6 +422,10 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { }, slug: 'get-started/configure-mcp', }, + { + label: 'Troubleshooting', + slug: 'get-started/troubleshooting', + }, ], }, { @@ -754,6 +758,28 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { 'zh-CN': 'Aspire 应用生命周期指南', }, }, + { + label: 'Glossary', + slug: 'get-started/glossary', + translations: { + da: 'Ordliste', + de: 'Glossar', + en: 'Glossary', + es: 'Glosario', + fr: 'Glossaire', + hi: 'शब्दावली', + id: 'Glosarium', + it: 'Glossario', + ja: '用語集', + ko: '용어 사전', + 'pt-BR': 'Glossário', + 'pt-PT': 'Glossário', + ru: 'Глоссарий', + tr: 'Sözlük', + uk: 'Глосарій', + 'zh-CN': '术语表', + }, + }, ], }, { @@ -862,6 +888,10 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { ja: '拡張性', }, items: [ + { + label: 'Custom resources', + slug: 'extensibility/custom-resources', + }, { label: 'Interaction service', slug: 'extensibility/interaction-service', @@ -1168,28 +1198,6 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { }, slug: 'architecture/resource-examples', }, - { - label: 'Glossary', - translations: { - da: 'Ordbog', - de: 'Glossar', - en: 'Glossary', - es: 'Glosario', - fr: 'Glossaire', - hi: 'शब्दावली', - id: 'Kamus', - it: 'Glossario', - ja: '用語集', - ko: '용어집', - 'pt-BR': 'Glossário', - 'pt-PT': 'Glossário', - ru: 'Глоссарий', - tr: 'Sözlük', - uk: 'Глосарій', - 'zh-CN': '术语表', - }, - slug: 'architecture/glossary', - }, ], }, ], diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index 80af1db76..e7567d070 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -293,6 +293,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { label: 'Azure App Service', slug: 'integrations/cloud/azure/azure-app-service', }, + { + label: 'Azure Application Insights', + slug: 'integrations/cloud/azure/azure-application-insights', + }, { label: 'Azure Cache for Redis', slug: 'integrations/cloud/azure/azure-cache-redis', @@ -305,6 +309,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { label: 'Azure Cosmos DB', slug: 'integrations/cloud/azure/azure-cosmos-db', }, + { + label: 'Azure Data Explorer', + slug: 'integrations/cloud/azure/azure-data-explorer', + }, { label: 'Azure Event Hubs', slug: 'integrations/cloud/azure/azure-event-hubs', @@ -317,6 +325,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { label: 'Azure Key Vault', slug: 'integrations/cloud/azure/azure-key-vault', }, + { + label: 'Azure Log Analytics', + slug: 'integrations/cloud/azure/azure-log-analytics', + }, { label: 'Azure PostgreSQL', collapsed: true, @@ -355,6 +367,10 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { label: 'Azure Storage Blobs', slug: 'integrations/cloud/azure/azure-storage-blobs', }, + { + label: 'Azure Data Lake Storage', + slug: 'integrations/cloud/azure/azure-storage-datalake', + }, { label: 'Azure Storage Queues', slug: 'integrations/cloud/azure/azure-storage-queues', diff --git a/src/frontend/config/sidebar/reference.topics.ts b/src/frontend/config/sidebar/reference.topics.ts index 24cb36e52..3354c8764 100644 --- a/src/frontend/config/sidebar/reference.topics.ts +++ b/src/frontend/config/sidebar/reference.topics.ts @@ -281,11 +281,13 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig = { ], }, { label: 'aspire new', slug: 'reference/cli/commands/aspire-new' }, + { label: 'aspire ps', slug: 'reference/cli/commands/aspire-ps' }, { label: 'aspire publish', slug: 'reference/cli/commands/aspire-publish', }, { label: 'aspire run', slug: 'reference/cli/commands/aspire-run' }, + { label: 'aspire stop', slug: 'reference/cli/commands/aspire-stop' }, { label: 'aspire update', slug: 'reference/cli/commands/aspire-update', diff --git a/src/frontend/src/assets/icons/azure-dataexplorer-icon.svg b/src/frontend/src/assets/icons/azure-dataexplorer-icon.svg new file mode 100644 index 000000000..59d2fd753 --- /dev/null +++ b/src/frontend/src/assets/icons/azure-dataexplorer-icon.svg @@ -0,0 +1 @@ +Icon-analytics-145 diff --git a/src/frontend/src/assets/icons/azure-datalake-icon.png b/src/frontend/src/assets/icons/azure-datalake-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3aadfd0cb6dcf9d4d85e5bd906e253ad857b0aee GIT binary patch literal 9334 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 ecT6BIA

YfC;(9pL{sjpR%F`xJ>?O@c#lw9GlYs literal 0 HcmV?d00001 diff --git a/src/frontend/src/content/docs/app-host/eventing.mdx b/src/frontend/src/content/docs/app-host/eventing.mdx index 5d0ac3dd4..a0dd66872 100644 --- a/src/frontend/src/content/docs/app-host/eventing.mdx +++ b/src/frontend/src/content/docs/app-host/eventing.mdx @@ -1,9 +1,10 @@ --- title: AppHost eventing APIs -description: Learn how to use the Aspire AppHost eventing features. +description: Learn how to use the .NET Aspire AppHost eventing features for lifecycle events, custom event publishing, and event-driven resource orchestration. --- import { Aside, Steps } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; In Aspire, eventing allows you to publish and subscribe to events during various AppHost life cycles. Eventing is more flexible than life cycle events. Both let you run arbitrary code during event callbacks, but eventing offers finer control of event timing, publishing, and provides supports for custom events. @@ -302,3 +303,114 @@ The subscriber approach keeps builder code minimal while still letting you respo - You can register handlers for any built-in event (AppHost or resource) or for your own custom `IDistributedApplicationEvent` types. Use this pattern whenever you previously relied on `IDistributedApplicationLifecycleHook`. The lifecycle hook APIs remain only for backward compatibility and will be removed in a future release. + +### Migrating from lifecycle hooks + +If you're migrating from the deprecated `IDistributedApplicationLifecycleHook` interface, use the following mapping: + +| Old pattern (deprecated) | New pattern | +|--------------------------|-------------| +| `BeforeStartAsync()` | Subscribe to `BeforeStartEvent` | +| `AfterEndpointsAllocatedAsync()` | Subscribe to `ResourceEndpointsAllocatedEvent` | +| `AfterResourcesCreatedAsync()` | Subscribe to `AfterResourcesCreatedEvent` | +| `TryAddLifecycleHook()` | `TryAddEventingSubscriber()` | + +**Before (deprecated):** + +```csharp title="OldLifecycleHook.cs" +public class MyHook : IDistributedApplicationLifecycleHook +{ + public Task AfterResourcesCreatedAsync( + DistributedApplicationModel model, + CancellationToken cancellationToken) + { + // Handle event + return Task.CompletedTask; + } +} + +// Registration +builder.Services.TryAddLifecycleHook(); +``` + +**After (recommended):** + +```csharp title="NewEventingSubscriber.cs" +public class MySubscriber : IDistributedApplicationEventingSubscriber +{ + public Task SubscribeAsync( + IDistributedApplicationEventing eventing, + DistributedApplicationExecutionContext context, + CancellationToken cancellationToken) + { + eventing.Subscribe((@event, ct) => + { + // Handle event using context.Model + return Task.CompletedTask; + }); + + return Task.CompletedTask; + } +} + +// Registration +builder.Services.TryAddEventingSubscriber(); +``` + +

+ +## Additional events + +Beyond the core lifecycle events, Aspire provides additional events for specific scenarios: + +### Publishing events + +When publishing your application (generating deployment manifests), these events are raised: + +| Event | When raised | Purpose | +|-------|-------------|---------| +| `BeforePublishEvent` | Before publishing begins | Validate or modify resources before manifest generation | +| `AfterPublishEvent` | After publishing completes | Perform cleanup or post-publish actions | + +```csharp title="AppHost.cs" +builder.Eventing.Subscribe((@event, ct) => +{ + // Validate resources before publishing + return Task.CompletedTask; +}); + +builder.Eventing.Subscribe((@event, ct) => +{ + // Post-publish actions + return Task.CompletedTask; +}); +``` + + +For details on what happens during publishing, see [Publishing and deployment overview](/deployment/overview/). + + +### Resource stopped event + +The `ResourceStoppedEvent` is raised when a resource stops execution: + +```csharp title="AppHost.cs" +builder.Eventing.Subscribe( + cache, + (@event, ct) => + { + logger.LogInformation("Resource {Name} stopped", @event.Resource.Name); + return Task.CompletedTask; + }); +``` + + + +## See also + +- [Custom resources](/extensibility/custom-resources/) +- [Resource annotations](/fundamentals/annotations-overview/) diff --git a/src/frontend/src/content/docs/architecture/glossary.md b/src/frontend/src/content/docs/architecture/glossary.md deleted file mode 100644 index a1a8acfb0..000000000 --- a/src/frontend/src/content/docs/architecture/glossary.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Glossary -description: A glossary of key terms and concepts in Aspire. -giscus: false -next: false -prev: false ---- - -| API Terms | Description | -| --------------------- | ------------------------------------------------- | -| `IResourceAnnotation` | Typed metadata object attached to resources. | -| `WithAnnotation()` | Fluent method to attach typed annotations. | -| `ReferenceExpression` | Structured formatter preserving value references. | - -| Term | Definition | -| ----------------------------- | -------------------------------------------------- | -| Resource | Service or infrastructure element in your app. | -| Annotation | Metadata attached to a resource. | -| DAG | Directed acyclic graph. | -| Heterogeneous DAG | DAG containing varied resource types. | -| Publisher | Emits deployment artifacts from the model. | -| Hoisting | Leaving a value unresolved for later substitution. | -| Deferred evaluation | Computing a value only when needed. | -| `ResourceNotificationService` | Publishes observable state updates. | -| Lifecycle events | Time-based signals for resource transitions. | diff --git a/src/frontend/src/content/docs/architecture/resource-examples.mdx b/src/frontend/src/content/docs/architecture/resource-examples.mdx index 01180ef33..d2318d703 100644 --- a/src/frontend/src/content/docs/architecture/resource-examples.mdx +++ b/src/frontend/src/content/docs/architecture/resource-examples.mdx @@ -213,87 +213,89 @@ public class RedisResource(string name) This example demonstrates creating a completely custom resource (`TalkingClockResource`) that doesn't derive from built-in types. It shows: - Defining a simple resource class. -- Implementing a custom lifecycle hook (`TalkingClockLifecycleHook`) to manage the resource's behavior (starting, logging, state updates). +- Implementing a custom eventing subscriber (`TalkingClockEventingSubscriber`) to manage the resource's behavior (starting, logging, state updates). - Using `ResourceLoggerService` for per-resource logging. - Using `ResourceNotificationService` to publish state updates. -- Creating an `AddTalkingClock` extension method to register the resource and its lifecycle hook. +- Creating an `AddTalkingClock` extension method to register the resource and its eventing subscriber. ```csharp title="C# — TalkingClockResource.cs" // Define the custom resource type. It inherits from the base Aspire 'Resource' class. -// This class is primarily a data container; Aspire behavior is added via lifecycle hooks and extension methods. +// This class is primarily a data container; Aspire behavior is added via eventing subscribers and extension methods. public sealed class TalkingClockResource(string name) : Resource(name); ``` -```csharp title="C# — TalkingClockLifecycleHook.cs" -// Define an Aspire lifecycle hook that implements the behavior for the TalkingClockResource. -// Lifecycle hooks allow plugging into the application's startup and shutdown sequences. -public sealed class TalkingClockLifecycleHook( +```csharp title="C# — TalkingClockEventingSubscriber.cs" +// Define an Aspire eventing subscriber that implements the behavior for the TalkingClockResource. +// Eventing subscribers allow plugging into the application's startup and lifecycle events. +public sealed class TalkingClockEventingSubscriber( // Aspire service for publishing resource state updates (e.g., Running, Starting). ResourceNotificationService notification, - // Aspire service for publishing and subscribing to application-wide events. - IDistributedApplicationEventing eventing, // Aspire service for getting a logger scoped to a specific resource. ResourceLoggerService loggerSvc, // General service provider for dependency injection if needed. - IServiceProvider services) : IDistributedApplicationLifecycleHook // Implement the Aspire hook interface. + IServiceProvider services) : IDistributedApplicationEventingSubscriber // Implement the Aspire eventing subscriber interface. { - // This method is called by Aspire after all resources have been initially added to the application model. - public Task AfterResourcesCreatedAsync( - DistributedApplicationModel model, // The Aspire application model containing all resources. - CancellationToken token) // Cancellation token for graceful shutdown. + // This method is called by Aspire to allow subscription to lifecycle events. + public Task SubscribeAsync( + IDistributedApplicationEventing eventing, // The eventing service to subscribe to. + DistributedApplicationExecutionContext context, // Execution context with model and environment info. + CancellationToken cancellationToken) // Cancellation token for graceful shutdown. { - // Find all instances of TalkingClockResource in the Aspire application model. - foreach (var clock in model.Resources.OfType()) + // Subscribe to the AfterResourcesCreatedEvent to start the clock behavior. + eventing.Subscribe(async (@event, ct) => { - // Get an Aspire logger specifically for this clock instance. Logs will be associated with this resource in the dashboard. - var log = loggerSvc.GetLogger(clock); - - // Start a background task to manage the clock's lifecycle and behavior. - _ = Task.Run(async () => + // Find all instances of TalkingClockResource in the Aspire application model. + foreach (var clock in context.Model.Resources.OfType()) { - // Publish an Aspire event indicating that this resource is about to start. - // Other components could subscribe to this event for pre-start actions. - await eventing.PublishAsync( - new BeforeResourceStartedEvent(clock, services), token); - - // Log an informational message associated with the resource. - log.LogInformation("Starting Talking Clock..."); - - // Publish an initial state update to the Aspire notification service. - // This sets the resource's state to 'Running' and records the start time. - // The Aspire dashboard and other orchestrators observe these state updates. - await notification.PublishUpdateAsync(clock, s => s with - { - StartTimeStamp = DateTime.UtcNow, - State = KnownResourceStates.Running // Use an Aspire well-known state. - }); + // Get an Aspire logger specifically for this clock instance. + // Logs will be associated with this resource in the dashboard. + var log = loggerSvc.GetLogger(clock); - // Enter the main loop that runs as long as cancellation is not requested. - while (!token.IsCancellationRequested) + // Start a background task to manage the clock's lifecycle and behavior. + _ = Task.Run(async () => { - // Log the current time, associated with the resource. - log.LogInformation("The time is {time}", DateTime.UtcNow); + // Publish an Aspire event indicating that this resource is about to start. + // Other components could subscribe to this event for pre-start actions. + await eventing.PublishAsync( + new BeforeResourceStartedEvent(clock, services), ct); + + // Log an informational message associated with the resource. + log.LogInformation("Starting Talking Clock..."); + + // Publish an initial state update to the Aspire notification service. + // This sets the resource's state to 'Running' and records the start time. + // The Aspire dashboard and other orchestrators observe these state updates. + await notification.PublishUpdateAsync(clock, s => s with + { + StartTimeStamp = DateTime.UtcNow, + State = KnownResourceStates.Running // Use an Aspire well-known state. + }); - // Publish a custom state update "Tick" using Aspire's ResourceStateSnapshot. - // This demonstrates using custom state strings and styles in the Aspire dashboard. - await notification.PublishUpdateAsync(clock, - s => s with { State = new ResourceStateSnapshot("Tick", KnownResourceStateStyles.Info) }); + // Enter the main loop that runs as long as cancellation is not requested. + while (!ct.IsCancellationRequested) + { + // Log the current time, associated with the resource. + log.LogInformation("The time is {time}", DateTime.UtcNow); - await Task.Delay(1000, token); + // Publish a custom state update "Tick" using Aspire's ResourceStateSnapshot. + // This demonstrates using custom state strings and styles in the Aspire dashboard. + await notification.PublishUpdateAsync(clock, + s => s with { State = new ResourceStateSnapshot("Tick", KnownResourceStateStyles.Info) }); - // Publish another custom state update "Tock" using Aspire's ResourceStateSnapshot. - await notification.PublishUpdateAsync(clock, - s => s with { State = new ResourceStateSnapshot("Tock", KnownResourceStateStyles.Success) }); + await Task.Delay(1000, ct); - await Task.Delay(1000, token); - } - }, token); - } + // Publish another custom state update "Tock" using Aspire's ResourceStateSnapshot. + await notification.PublishUpdateAsync(clock, + s => s with { State = new ResourceStateSnapshot("Tock", KnownResourceStateStyles.Success) }); + + await Task.Delay(1000, ct); + } + }, ct); + } + }); - // Indicate that this hook's work (starting the background tasks) is complete for now. return Task.CompletedTask; } - // Other Aspire lifecycle hook methods (e.g., BeforeStartAsync, AfterEndpointsAllocatedAsync) could be implemented here if needed. } ``` @@ -308,9 +310,9 @@ public static class TalkingClockExtensions this IDistributedApplicationBuilder builder, // Extends the Aspire application builder. string name) // The name for this resource instance. { - // Register the TalkingClockLifecycleHook with the DI container using Aspire's helper method. - // The Aspire hosting infrastructure will automatically discover and run registered lifecycle hooks. - builder.Services.TryAddLifecycleHook(); + // Register the TalkingClockEventingSubscriber with the DI container using Aspire's helper method. + // The Aspire hosting infrastructure will automatically discover and run registered eventing subscribers. + builder.Services.TryAddEventingSubscriber(); // Create a new instance of the TalkingClockResource. var clockResource = new TalkingClockResource(name); diff --git a/src/frontend/src/content/docs/diagnostics/aspirecontainershellexecution001.mdx b/src/frontend/src/content/docs/diagnostics/aspirecontainershellexecution001.mdx new file mode 100644 index 000000000..d9cb83e17 --- /dev/null +++ b/src/frontend/src/content/docs/diagnostics/aspirecontainershellexecution001.mdx @@ -0,0 +1,46 @@ +--- +title: ASPIRECONTAINERSHELLEXECUTION001 +description: The container shell execution property is experimental and subject to change. +--- + +## Overview + +| Property | Value | +|----------|-------| +| **Diagnostic ID** | ASPIRECONTAINERSHELLEXECUTION001 | +| **Severity** | Warning | +| **Category** | Usage | + +The `ShellExecution` property on `ContainerResource` is an experimental feature that controls whether custom arguments should be wrapped for shell execution. This API may change or be removed in future versions. + +## Cause + +This warning appears when you set the `ShellExecution` property on a container resource: + +```csharp +container.ShellExecution = true; +``` + +When enabled, custom arguments are wrapped in `-c "values"` format for shell execution. + +## How to suppress + +If you understand the experimental nature of this API and want to use it, suppress the warning: + +```csharp title="Suppress in code" +#pragma warning disable ASPIRECONTAINERSHELLEXECUTION001 +container.ShellExecution = true; +#pragma warning restore ASPIRECONTAINERSHELLEXECUTION001 +``` + +Or in your project file: + +```xml title="Suppress in project file" + + $(NoWarn);ASPIRECONTAINERSHELLEXECUTION001 + +``` + +## See also + +- [Container resources](/get-started/app-host/#add-container-resource) - Learn about container resources diff --git a/src/frontend/src/content/docs/diagnostics/aspiredotnettool.mdx b/src/frontend/src/content/docs/diagnostics/aspiredotnettool.mdx new file mode 100644 index 000000000..fddcf8196 --- /dev/null +++ b/src/frontend/src/content/docs/diagnostics/aspiredotnettool.mdx @@ -0,0 +1,44 @@ +--- +title: ASPIREDOTNETTOOL +description: The .NET tool resource APIs are experimental and subject to change. +--- + +## Overview + +| Property | Value | +|----------|-------| +| **Diagnostic ID** | ASPIREDOTNETTOOL | +| **Severity** | Warning | +| **Category** | Usage | + +The `DotnetToolResource` and related APIs for adding .NET CLI tools as resources are experimental features. These APIs may change or be removed in future versions. + +## Cause + +This warning appears when you use APIs for adding .NET tools as resources: + +- `DotnetToolResource` +- `DotnetToolAnnotation` +- `AddDotnetTool` extension methods + +## How to suppress + +If you understand the experimental nature of these APIs and want to use them, suppress the warning: + +```csharp title="Suppress in code" +#pragma warning disable ASPIREDOTNETTOOL +var tool = builder.AddDotnetTool("my-tool", "dotnet-tool-package"); +#pragma warning restore ASPIREDOTNETTOOL +``` + +Or in your project file: + +```xml title="Suppress in project file" + + $(NoWarn);ASPIREDOTNETTOOL + +``` + +## See also + +- [Executables](/get-started/app-host/#add-executable-resource) - Learn about executable resources diff --git a/src/frontend/src/content/docs/diagnostics/aspireextension001.mdx b/src/frontend/src/content/docs/diagnostics/aspireextension001.mdx new file mode 100644 index 000000000..2cb938300 --- /dev/null +++ b/src/frontend/src/content/docs/diagnostics/aspireextension001.mdx @@ -0,0 +1,49 @@ +--- +title: ASPIREEXTENSION001 +description: The extension debugging support APIs are experimental and subject to change. +--- + +## Overview + +| Property | Value | +|----------|-------| +| **Diagnostic ID** | ASPIREEXTENSION001 | +| **Severity** | Warning | +| **Category** | Usage | + +The `WithDebugSupport` extension method and related APIs for enabling debugging support in IDE extensions are experimental features. These APIs may change or be removed in future versions. + +## Cause + +This warning appears when you use APIs for adding debug support to resources: + +- `WithDebugSupport` extension method +- `SupportsDebuggingAnnotation` + +These APIs are primarily used by integration authors to enable F5 debugging for custom resource types in Visual Studio and other IDEs. + +## How to suppress + +If you understand the experimental nature of these APIs and want to use them, suppress the warning: + +```csharp title="Suppress in code" +#pragma warning disable ASPIREEXTENSION001 +builder.AddMyResource("resource") + .WithDebugSupport( + processId => new MyLaunchConfiguration { ProcessId = processId }, + "myResourceType"); +#pragma warning restore ASPIREEXTENSION001 +``` + +Or in your project file: + +```xml title="Suppress in project file" + + $(NoWarn);ASPIREEXTENSION001 + +``` + +## See also + +- [Debugging overview](/fundamentals/debugging/) - Learn about debugging Aspire applications +- [Custom hosting integrations](/integrations/custom-integrations/hosting-integrations/) - Learn about creating custom integrations diff --git a/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx b/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx index 2adf7b5e6..b959377d8 100644 --- a/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspireinteraction001.mdx @@ -67,6 +67,42 @@ dotnet_diagnostic.ASPIREINTERACTION001.severity = none ### Suppressing in a project file ```xml title="YourProject.csproj" +title: ASPIREINTERACTION001 +description: The interaction service APIs are experimental and subject to change. +--- + +## Overview + +| Property | Value | +|----------|-------| +| **Diagnostic ID** | ASPIREINTERACTION001 | +| **Severity** | Warning | +| **Category** | Usage | + +The `IInteractionService` and related APIs are experimental features that enable interactive prompts and confirmations during AppHost execution. These APIs may change or be removed in future versions. + +## Cause + +This warning appears when you use the interaction service APIs such as: + +- `IInteractionService.PromptAsync` +- `IInteractionService.ConfirmAsync` +- `IInteractionService.SelectAsync` +- `InputGeneratorAnnotation` + +## How to suppress + +If you understand the experimental nature of these APIs and want to use them, suppress the warning: + +```csharp title="Suppress in code" +#pragma warning disable ASPIREINTERACTION001 +var result = await interactionService.PromptAsync("Enter value:", cancellationToken); +#pragma warning restore ASPIREINTERACTION001 +``` + +Or in your project file: + +```xml title="Suppress in project file" $(NoWarn);ASPIREINTERACTION001 @@ -85,4 +121,4 @@ var result = await interactionService.PromptConfirmationAsync( ## See also -- [Interaction service (Preview)](/extensibility/interaction-service/) +- [Interaction service](/extensibility/interaction-service/) - Learn how to use the interaction service diff --git a/src/frontend/src/content/docs/diagnostics/aspirepostgres001.mdx b/src/frontend/src/content/docs/diagnostics/aspirepostgres001.mdx new file mode 100644 index 000000000..1d9e7fefd --- /dev/null +++ b/src/frontend/src/content/docs/diagnostics/aspirepostgres001.mdx @@ -0,0 +1,43 @@ +--- +title: ASPIREPOSTGRES001 +description: The PostgreSQL MCP integration APIs are experimental and subject to change. +--- + +## Overview + +| Property | Value | +|----------|-------| +| **Diagnostic ID** | ASPIREPOSTGRES001 | +| **Severity** | Warning | +| **Category** | Usage | + +The `WithPostgresMcp` extension method for adding Model Context Protocol (MCP) support to PostgreSQL resources is an experimental feature. This API may change or be removed in future versions. + +## Cause + +This warning appears when you use the `WithPostgresMcp` extension method to add MCP capabilities to a PostgreSQL database resource. + +## How to suppress + +If you understand the experimental nature of this API and want to use it, suppress the warning: + +```csharp title="Suppress in code" +#pragma warning disable ASPIREPOSTGRES001 +var db = builder.AddAzurePostgresFlexibleServer("postgres") + .AddDatabase("mydb") + .WithPostgresMcp(); +#pragma warning restore ASPIREPOSTGRES001 +``` + +Or in your project file: + +```xml title="Suppress in project file" + + $(NoWarn);ASPIREPOSTGRES001 + +``` + +## See also + +- [PostgreSQL integration](/integrations/databases/postgresql/postgresql-host/) - Learn about PostgreSQL hosting integration +- [Configure MCP](/get-started/configure-mcp/) - Learn about Model Context Protocol configuration diff --git a/src/frontend/src/content/docs/diagnostics/overview.mdx b/src/frontend/src/content/docs/diagnostics/overview.mdx index 01c232b8a..834421f71 100644 --- a/src/frontend/src/content/docs/diagnostics/overview.mdx +++ b/src/frontend/src/content/docs/diagnostics/overview.mdx @@ -24,20 +24,25 @@ The following table lists the possible MSBuild and analyzer warnings and errors | [ASPIRECOMPUTE002](/diagnostics/aspirecompute002/) | (Experimental) Warning | The GetHostAddressExpression method is for evaluation purposes only and is subject to change or removal in future updates. | | [ASPIRECOMPUTE003](/diagnostics/aspirecompute003/) | (Experimental) Warning | The ContainerRegistryResource type is for evaluation purposes only and is subject to change or removal in future updates. | | [ASPIRECONTAINERRUNTIME001](/diagnostics/aspirecontainerruntime001/) | (Experimental) Warning | Type is for evaluation purposes only and is subject to change or removal in future updates. | -| [ASPIRECSHARPAPPS001](/diagnostics/aspirecsharpapps001/) | (Experimental) Error | `AddCSharpApp` is for evaluation purposes only and is subject to change or removal in future updates. | +| [ASPIRECONTAINERSHELLEXECUTION001](/diagnostics/aspirecontainershellexecution001/) | (Experimental) Warning | Container shell execution property is for evaluation purposes only and is subject to change or removal in future updates. | | [ASPIRECOSMOSDB001](/diagnostics/aspirecosmosdb001/) | (Experimental) Error | `RunAsPreviewEmulator` is for evaluation purposes only and is subject to change or removal in future updates. | +| [ASPIRECSHARPAPPS001](/diagnostics/aspirecsharpapps001/) | (Experimental) Error | `AddCSharpApp` is for evaluation purposes only and is subject to change or removal in future updates. | | [ASPIREDOCKERFILEBUILDER001](/diagnostics/aspiredockerfilebuilder001/) | (Experimental) Warning | Dockerfile builder types and members are for evaluation purposes only and are subject to change or removal in future updates. | +| [ASPIREDOTNETTOOL](/diagnostics/aspiredotnettool/) | (Experimental) Warning | .NET tool resource types and members are for evaluation purposes only and are subject to change or removal in future updates. | +| [ASPIREEXTENSION001](/diagnostics/aspireextension001/) | (Experimental) Warning | Extension debugging support APIs are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREFILESYSTEM001](/diagnostics/aspirefilesystem001/) | (Experimental) Warning | File system service types and members are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREINTERACTION001](/diagnostics/aspireinteraction001/) | (Experimental) Warning | Interaction service types and members are for evaluation purposes only and are subject to change or removal in future updates. | -| [ASPIREPIPELINES004](/diagnostics/aspirepipelines004/) | (Experimental) Warning | Type is for evaluation purposes only and is subject to change or removal in future updates. | -| [ASPIREPROBES001](/diagnostics/aspireprobes001/) | (Experimental) Warning | Probe-related types and members are for evaluation purposes only and are subject to change or removal in future updates. | -| [ASPIREUSERSECRETS001](/diagnostics/aspireusersecrets001/) | (Experimental) Warning | Type is for evaluation purposes only and is subject to change or removal in future updates. | | [ASPIREHOSTINGPYTHON001](/diagnostics/aspirehostingpython001/) | (Experimental) Error | `AddPythonApp` is for evaluation purposes only and is subject to change or removal in future updates. | +| [ASPIREINTERACTION001](/diagnostics/aspireinteraction001/) | (Experimental) Warning | Interaction service APIs are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREPIPELINES001](/diagnostics/aspirepipelines001/) | (Experimental) Error | Pipeline infrastructure APIs are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREPIPELINES002](/diagnostics/aspirepipelines002/) | (Experimental) Error | Deployment state manager APIs are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREPIPELINES003](/diagnostics/aspirepipelines003/) | (Experimental) Error | Container image build APIs are for evaluation purposes only and are subject to change or removal in future updates. | +| [ASPIREPIPELINES004](/diagnostics/aspirepipelines004/) | (Experimental) Warning | Type is for evaluation purposes only and is subject to change or removal in future updates. | +| [ASPIREPOSTGRES001](/diagnostics/aspirepostgres001/) | (Experimental) Warning | PostgreSQL MCP integration is for evaluation purposes only and is subject to change or removal in future updates. | +| [ASPIREPROBES001](/diagnostics/aspireprobes001/) | (Experimental) Warning | Probe-related types and members are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREPROXYENDPOINTS001](/diagnostics/aspireproxyendpoints001/) | (Experimental) Error | ProxyEndpoint members are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREPUBLISHERS001](/diagnostics/aspirepublishers001/) | Error | Publishers are for evaluation purposes only and are subject to change or removal in future updates. | +| [ASPIREUSERSECRETS001](/diagnostics/aspireusersecrets001/) | (Experimental) Warning | Type is for evaluation purposes only and is subject to change or removal in future updates. | ## Suppress diagnostic diff --git a/src/frontend/src/content/docs/extensibility/custom-resources.mdx b/src/frontend/src/content/docs/extensibility/custom-resources.mdx new file mode 100644 index 000000000..bf83958ea --- /dev/null +++ b/src/frontend/src/content/docs/extensibility/custom-resources.mdx @@ -0,0 +1,292 @@ +--- +title: Aspire custom resources +description: Learn how to create custom resource types for the .NET Aspire app host to model your application's unique infrastructure components. +--- + +import { Aside } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +Creating custom resources allows you to extend Aspire to model components that aren't covered by built-in integrations. This guide covers the patterns and APIs for building your own resource types. + +## Resource fundamentals + +All Aspire resources implement the `IResource` interface, which requires a `Name` property. The base `Resource` class provides a simple implementation you can inherit from. + +### Basic resource definition + +The simplest custom resource is a class that inherits from `Resource`: + +```csharp title="MailDevResource.cs" +public sealed class MailDevResource(string name) : Resource(name); +``` + +This creates a resource that can be added to the app model but doesn't have any special behavior. You'll typically want to implement additional interfaces to add capabilities. + +## Common resource interfaces + +Aspire provides several interfaces that give resources specific capabilities: + +| Interface | Purpose | +|-----------|---------| +| `IResourceWithConnectionString` | Resource exposes a connection string for consumers | +| `IResourceWithEndpoints` | Resource has network endpoints | +| `IResourceWithEnvironment` | Resource can configure environment variables | +| `IResourceWithArgs` | Resource accepts command-line arguments | +| `IResourceWithWaitSupport` | Resource supports `WaitFor` orchestration | +| `IResourceWithParent` | Resource has a parent resource (lifecycle binding) | + +### Implementing IResourceWithConnectionString + +Resources that expose connection strings for client applications should implement `IResourceWithConnectionString`: + +```csharp title="MailDevResource.cs" +public sealed class MailDevResource(string name, EndpointReference smtpEndpoint) + : Resource(name), IResourceWithConnectionString +{ + public ReferenceExpression ConnectionStringExpression => + ReferenceExpression.Create( + $"smtp://{smtpEndpoint.Property(EndpointProperty.Host)}:{smtpEndpoint.Property(EndpointProperty.Port)}"); +} +``` + +For resources with authentication, include credentials in the connection string: + +```csharp title="InfluxDbResource.cs" +public sealed class InfluxDbResource : Resource, IResourceWithConnectionString +{ + private readonly EndpointReference _endpoint; + private readonly ParameterResource _token; + + public InfluxDbResource( + string name, + EndpointReference endpoint, + ParameterResource token) : base(name) + { + _endpoint = endpoint; + _token = token; + } + + public ReferenceExpression ConnectionStringExpression => + ReferenceExpression.Create( + $"Endpoint={_endpoint.Property(EndpointProperty.UriString)};" + + $"Token={_token}"); +} +``` + +## Creating extension methods + +By convention, resources are added to the app model via extension methods on `IDistributedApplicationBuilder`: + +```csharp title="MailDevExtensions.cs" +public static class MailDevExtensions +{ + public static IResourceBuilder AddMailDev( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? smtpPort = null) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(name); + + var resource = new MailDevResource(name); + + return builder.AddResource(resource) + .WithImage("maildev/maildev", "2.1.0") + .WithHttpEndpoint(targetPort: 1080, name: "http") + .WithEndpoint(targetPort: 1025, port: smtpPort, name: "smtp"); + } +} +``` + +The `[ResourceName]` attribute enables IDE tooling and validation for resource names. + +## Adding resource behavior + +Resources are data containers by default. To add runtime behavior, use one of these approaches: + +### Using eventing subscribers + +The recommended approach for adding lifecycle behavior is implementing `IDistributedApplicationEventingSubscriber`: + +```csharp title="MailDevEventingSubscriber.cs" +public sealed class MailDevEventingSubscriber( + ResourceNotificationService notification, + ResourceLoggerService loggerService) + : IDistributedApplicationEventingSubscriber +{ + public Task SubscribeAsync( + IDistributedApplicationEventing eventing, + DistributedApplicationExecutionContext context, + CancellationToken cancellationToken) + { + eventing.Subscribe(async (@event, ct) => + { + foreach (var resource in context.Model.Resources.OfType()) + { + var logger = loggerService.GetLogger(resource); + logger.LogInformation("MailDev server ready at {Name}", resource.Name); + + await notification.PublishUpdateAsync(resource, s => s with + { + State = KnownResourceStates.Running, + StartTimeStamp = DateTime.UtcNow + }); + } + }); + + return Task.CompletedTask; + } +} +``` + + +For the full list of available events and advanced patterns, see [AppHost eventing](/app-host/eventing/). + + +Register the subscriber in your extension method: + +```csharp title="MailDevExtensions.cs" +public static IResourceBuilder AddMailDev( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? smtpPort = null) +{ + builder.Services.TryAddEventingSubscriber(); + + var resource = new MailDevResource(name); + return builder.AddResource(resource); +} +``` + +### Using inline event subscriptions + +For simpler cases, you can subscribe to events directly on the resource builder: + +```csharp title="AppHost.cs" +public static IResourceBuilder AddMailDev( + this IDistributedApplicationBuilder builder, + [ResourceName] string name) +{ + var resource = new MailDevResource(name); + + builder.Eventing.Subscribe(resource, async (@event, ct) => + { + // Initialize mail server, create test mailboxes, etc. + }); + + return builder.AddResource(resource); +} +``` + +## Resource state management + +Use `ResourceNotificationService` to publish state updates that appear in the dashboard: + +```csharp title="Publishing state updates" +await notification.PublishUpdateAsync(resource, state => state with +{ + State = KnownResourceStates.Running, + StartTimeStamp = DateTime.UtcNow +}); +``` + +### Well-known states + +Aspire provides several well-known states in `KnownResourceStates`: + +- `NotStarted` - Resource hasn't started yet +- `Starting` - Resource is initializing +- `Running` - Resource is operational +- `Stopping` - Resource is shutting down +- `Exited` - Resource has stopped +- `FailedToStart` - Resource failed during startup +- `Waiting` - Resource is waiting for dependencies +- `Hidden` - Resource is hidden from the dashboard + +### Custom states + +You can create custom states using `ResourceStateSnapshot`: + +```csharp title="Custom state example" +await notification.PublishUpdateAsync(resource, state => state with +{ + State = new ResourceStateSnapshot("Indexing", KnownResourceStateStyles.Info) +}); +``` + +## Initial state configuration + +Set the initial dashboard appearance using `WithInitialState`: + +```csharp title="Setting initial state" +return builder.AddResource(resource) + .WithInitialState(new CustomResourceSnapshot + { + ResourceType = "MailDev", + CreationTimeStamp = DateTime.UtcNow, + State = KnownResourceStates.NotStarted, + Properties = [ + new(CustomResourceKnownProperties.Source, "MailDev SMTP Server") + ] + }); +``` + +## Excluding from manifest + +If your resource is for local development only, exclude it from deployment manifests: + +```csharp title="Excluding from deployment" +return builder.AddResource(resource) + .ExcludeFromManifest(); +``` + +## Resource relationships + +Use relationships to organize how resources appear in the dashboard: + +### WithRelationship + +Create custom relationships between resources for visual organization: + +```csharp title="AppHost.cs" +var api = builder.AddProject("api"); +var worker = builder.AddProject("worker") + .WithRelationship(api.Resource, "publishes-to"); +``` + +### WithChildRelationship + +Group related resources under a parent in the dashboard: + +```csharp title="AppHost.cs" +var postgres = builder.AddPostgres("postgres"); +var catalogDb = postgres.AddDatabase("catalog"); + +// Custom resources can establish parent-child relationships: +var mailDev = builder.AddMailDev("mail") + .WithChildRelationship(catalogDb); +``` + + +For more on how the Aspire Dashboard displays resources, see [Dashboard overview](/dashboard/overview/). + + +## Custom icons + +Use `WithIconName` to display a custom icon for your resource in the dashboard. Any [Fluent UI system icon](https://github.com/microsoft/fluentui-system-icons/blob/main/icons_filled.md) can be used: + +```csharp title="Setting custom dashboard icons" +return builder.AddResource(resource) + .WithIconName("mail"); // Uses the "mail" Fluent UI icon + +// Or specify a variant (Filled is default, Regular is outline-only) +return builder.AddResource(resource) + .WithIconName("mail", IconVariant.Regular); +``` + +## See also + +- [AppHost eventing](/app-host/eventing/) - Lifecycle events and subscribers +- [Resource annotations](/fundamentals/annotations-overview/) - Creating and using annotations +- [Resource examples](/architecture/resource-examples/) - Real-world custom resource examples +- [Custom resource commands](/fundamentals/custom-resource-commands/) - Adding dashboard commands diff --git a/src/frontend/src/content/docs/fundamentals/annotations-overview.mdx b/src/frontend/src/content/docs/fundamentals/annotations-overview.mdx index 53628ce9a..6675c88bb 100644 --- a/src/frontend/src/content/docs/fundamentals/annotations-overview.mdx +++ b/src/frontend/src/content/docs/fundamentals/annotations-overview.mdx @@ -4,6 +4,7 @@ description: Learn about annotations in Aspire, how they work, and how to create --- import { Aside } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; Annotations are a key extensibility mechanism in Aspire that allow you to attach metadata and behavior to resources. They provide a way to customize how resources are configured, deployed, and managed throughout the application lifecycle. This article explains how annotations work and how to use them effectively in your Aspire applications. @@ -40,6 +41,38 @@ In this example: - `WithCommand` adds a `ResourceCommandAnnotation` that defines a custom command. - `WithUrl` adds a `ResourceUrlAnnotation` that defines a custom URL. +## Adding and managing annotations + +The `WithAnnotation` extension method is the primary way to add annotations to resources. It supports different behaviors when an annotation of the same type already exists: + +```csharp title="AppHost.cs" +// Add only if no annotation of this type exists (default) +builder.AddContainer("mycontainer", "myimage") + .WithAnnotation(new MyAnnotation(), ResourceAnnotationMutationBehavior.None); + +// Replace any existing annotation of this type +builder.AddContainer("mycontainer", "myimage") + .WithAnnotation(new MyAnnotation(), ResourceAnnotationMutationBehavior.Replace); +``` + +### Reading annotations + +To read annotations from a resource, use the `Annotations` collection or helper methods: + +```csharp title="Reading annotations" +// Get all annotations of a type +var endpoints = resource.Annotations.OfType(); + +// Try to get the last annotation of a type (most recently added) +if (resource.TryGetLastAnnotation(out var endpoint)) +{ + Console.WriteLine($"Endpoint: {endpoint.Name}"); +} + +// Check if an annotation exists +bool hasEndpoints = resource.Annotations.OfType().Any(); +``` + ## Built-in annotation types Aspire includes many built-in annotation types for common scenarios. This section covers _some_ of the more commonly used annotations, but there are many more available for specific use cases. @@ -120,6 +153,70 @@ api.Resource.Annotations.Add( For more information about publishing and deploying Aspire apps, see [publishing and deploying](/deployment/overview/). +### `HealthCheckAnnotation` + +The `HealthCheckAnnotation` associates health checks with a resource, used by `WaitFor()` to determine when a resource is ready: + +```csharp title="AppHost.cs" +var api = builder.AddProject("api") + .WithHttpHealthCheck("/health"); // Adds HealthCheckAnnotation +``` + + +Learn more about how Aspire uses health checks for orchestration in the [Health checks guide](/fundamentals/health-checks/). + + +### `WaitAnnotation` + +The `WaitAnnotation` declares a dependency on another resource and controls startup order. The `WaitFor`, `WaitForStart`, and `WaitForCompletion` methods add this annotation: + +```csharp title="AppHost.cs" +var cache = builder.AddRedis("cache"); + +// Wait for cache to be healthy before starting web +var web = builder.AddProject("web") + .WaitFor(cache); // Adds WaitAnnotation with WaitType.WaitForHealthy +``` + +The `WaitType` enum specifies what condition to wait for: + +| Wait type | Description | +|----------|-------------| +| `WaitForStart` | Wait for resource to start (not necessarily healthy) | +| `WaitForHealthy` | Wait for resource to be healthy (default for `WaitFor`) | +| `WaitForCompletion` | Wait for resource to exit (for one-time tasks) | + +### `ReplicaAnnotation` + +The `ReplicaAnnotation` specifies how many instances of a resource should run: + +```csharp title="AppHost.cs" +var api = builder.AddProject("api") + .WithReplicas(3); // Adds ReplicaAnnotation +``` + +### `ContainerLifetimeAnnotation` + +The `ContainerLifetimeAnnotation` controls whether a container persists across app runs: + +```csharp title="AppHost.cs" +var postgres = builder.AddPostgres("postgres") + .WithLifetime(ContainerLifetime.Persistent); // Container survives restarts +``` + + +For details on persistent containers and their use cases, see [Persistent containers](/app-host/persistent-containers/). + + +### `ExplicitStartupAnnotation` + +The `ExplicitStartupAnnotation` prevents a resource from starting automatically. Users must manually start it from the dashboard: + +```csharp title="AppHost.cs" +var worker = builder.AddProject("batch") + .WithExplicitStart(); // Adds ExplicitStartupAnnotation +``` + ## Creating custom annotations Custom annotations in Aspire are designed to capture resource-specific metadata and behavior that can be leveraged throughout the application lifecycle. They're commonly used by: @@ -294,3 +391,9 @@ public sealed class ConfigAnnotation : IResourceAnnotation public SecuritySettings Security { get; set; } } ``` + +## See also + +- [Custom resources](/extensibility/custom-resources/) - Creating custom resource types that use annotations +- [Resource API patterns](/architecture/resource-api-patterns/) - Advanced API patterns for resources +- [AppHost eventing](/app-host/eventing/) - Handling lifecycle events in resources diff --git a/src/frontend/src/content/docs/fundamentals/health-checks.mdx b/src/frontend/src/content/docs/fundamentals/health-checks.mdx index 2f33fb463..574362a72 100644 --- a/src/frontend/src/content/docs/fundamentals/health-checks.mdx +++ b/src/frontend/src/content/docs/fundamentals/health-checks.mdx @@ -3,21 +3,33 @@ title: Health checks description: Explore Aspire health checks --- +import { Aside } from '@astrojs/starlight/components'; import { Image } from 'astro:assets'; import healthChecksDashboardStatus from '@assets/fundamentals/health-checks-dashboard-status.png'; Health checks provide availability and state information about an app. Health checks are often exposed as HTTP endpoints, but can also be used internally by the app to write logs or perform other tasks based on the current health. Health checks are typically used in combination with an external monitoring service or container orchestrator to check the status of an app. -In Aspire, health checks operate in two main contexts: +## Two types of health checks -- **AppHost resource health checks** - Run in the AppHost project to determine resource readiness for orchestration and dependency management. These checks control when dependent resources start and are displayed in the Aspire dashboard. -- **Application health check endpoints** - Run within individual applications and services to expose `/health` and `/alive` endpoints for monitoring and load balancing decisions. +Aspire uses health checks in two distinct contexts. Understanding the difference is crucial: -The data reported by health checks can be used for various scenarios: +| Health check type | Where it runs | What it checks | Used for | +|-------------------|---------------|----------------|----------| +| **AppHost resource checks** | AppHost project | "Is my dependency ready?" | Startup orchestration, `WaitFor()` | +| **Service endpoint checks** | Your application | "Am I healthy?" | Load balancers, Kubernetes probes | -- Influence decisions made by container orchestrators, load balancers, API gateways, and other management services. For instance, if the health check for a containerized app fails, it might be skipped by a load balancer routing traffic. -- Verify that underlying dependencies are available, such as a database or cache, and return an appropriate status message. -- Trigger alerts or notifications when an app isn't responding as expected. + + +## Readiness vs. Liveness + +The two endpoint types serve different purposes: + +- **Readiness (`/health`)** - "Am I ready to receive traffic?" Checks that dependencies are connected, initialization is complete, and the service can handle requests. A failing readiness check means "don't send me traffic yet." + +- **Liveness (`/alive`)** - "Am I still running?" Checks that the process hasn't deadlocked or crashed. A failing liveness check means "restart me." ## Aspire health check endpoints diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx index c61eb04b4..5bfc6a19f 100644 --- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx +++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx @@ -14,6 +14,38 @@ import proxyWithDockerPortMapping from '@assets/fundamentals/networking/proxy-wi One of the advantages of developing with Aspire is that it enables you to develop, test, and debug cloud-native apps locally. Inner-loop networking is a key aspect of Aspire that allows your apps to communicate with each other in your development environment. In this article, you learn how Aspire handles various networking scenarios with proxies, endpoints, endpoint configurations, and launch profiles. +## The proxy mental model + +Think of Aspire's networking like a hotel front desk: + +- **Clients** (your code calling APIs) always talk to the **front desk** (proxy) at a known, stable address +- The front desk routes requests to the **actual room** (your service) wherever it happens to be +- If you have **multiple rooms** (replicas), the front desk handles which one to connect to + +This design solves several problems: + +| Problem | How the proxy helps | +|---------|---------------------| +| **Port conflicts** | Two services can't both use port 5000—but the proxy can allocate different ports for each | +| **Replicas** | Multiple instances of a service need load balancing—the proxy handles this automatically | +| **Service restarts** | When a service restarts on a new port, the proxy's address stays the same | + +```mermaid +flowchart LR + Client["Your Code"] + Proxy["Proxy :5000"] + App1["Service :52847"] + App2["Service :52848"] + + Client --> Proxy + Proxy --> App1 + Proxy --> App2 +``` + + + ## Networking in the inner loop The inner loop is the process of developing and testing your app locally before deploying it to a target environment. Aspire provides several tools and features to simplify and enhance the networking experience in the inner loop, such as: @@ -65,6 +97,29 @@ Containers register themselves on the network using their resource name. Aspire [service discovery](/fundamentals/service-discovery/). +### Container network aliases + +By default, containers are accessible on the container network using their **resource name** as a DNS alias. For example, a container added with `AddContainer("mydb", ...)` is reachable at `mydb:5432` from other containers. + +Sometimes you need additional aliases—for example, when a third-party tool expects a specific hostname, or when migrating from an existing Docker Compose setup. Use `WithContainerNetworkAlias` to add custom DNS names: + +```csharp title="AppHost.cs" +var redis = builder.AddRedis("cache") + .WithContainerNetworkAlias("redis-primary") + .WithContainerNetworkAlias("session-store"); +``` + +Now other containers can connect to Redis using any of these names: +- `cache:6379` (default resource name) +- `redis-primary:6379` (custom alias) +- `session-store:6379` (custom alias) + + + ## Launch profiles When you call `AddProject`, the AppHost looks for _Properties/launchSettings.json_ to determine the default set of endpoints. The AppHost selects a specific launch profile using the following rules: @@ -353,3 +408,61 @@ builder.AddProject("apiservice") ``` The preceding code adds a default HTTPS endpoint, as well as an `admin` endpoint on port 19227. However, the `admin` endpoint is excluded from the environment variables. This is useful when you want to expose an endpoint for internal use only. + +## Troubleshooting + +### Port already in use + +**Symptom**: Error message like `Address already in use` or `Failed to bind to port` + +**Common causes**: +- Another instance of your app is still running +- A previous Aspire session didn't shut down cleanly +- Another application is using the same port + +**Solutions**: +1. Stop any running Aspire sessions with `Ctrl+C` or close the dashboard +2. Check for processes using the port: `netstat -ano | findstr :5000` (Windows) or `lsof -i :5000` (macOS/Linux) +3. Let Aspire assign random ports by removing explicit port numbers from `WithEndpoint` + +### Can't connect to container + +**Symptom**: Timeouts or connection refused when connecting to a container resource + +**Common causes**: +- The container hasn't finished starting +- Missing `WaitFor()` dependency +- Container is on the container network but you're connecting from the host + +**Solutions**: +1. Add `.WaitFor(container)` to ensure the container is ready before dependent services start +2. Add `.WithHttpHealthCheck()` or `.WithHealthCheck()` to the container resource +3. Ensure host services use the **exposed port** (not the container's internal port): + +```csharp +// Container exposes port 5432 to host +var db = builder.AddPostgres("db"); + +// Host service connects via exposed port (handled by WithReference) +var api = builder.AddProject("api") + .WithReference(db); // ✅ Correct - uses exposed port +``` + +### Service not discoverable + +**Symptom**: Service discovery fails with "service not found" or DNS resolution errors + +**Solutions**: +1. Verify `WithReference()` is set up between producer and consumer +2. Check the endpoint name in the URI matches exactly (case-sensitive) +3. Review [service discovery troubleshooting](/fundamentals/service-discovery#troubleshooting) + +### HTTPS certificate errors + +**Symptom**: Certificate validation fails in development + +**Solution**: Trust the ASP.NET Core development certificate: + +```bash +dotnet dev-certs https --trust +``` diff --git a/src/frontend/src/content/docs/fundamentals/service-discovery.mdx b/src/frontend/src/content/docs/fundamentals/service-discovery.mdx index 67e564e65..fb0090905 100644 --- a/src/frontend/src/content/docs/fundamentals/service-discovery.mdx +++ b/src/frontend/src/content/docs/fundamentals/service-discovery.mdx @@ -5,7 +5,22 @@ description: Understand essential service discovery concepts in Aspire. import { Aside } from '@astrojs/starlight/components'; -In this article, you learn how service discovery works within an Aspire project. Aspire includes functionality for configuring service discovery at development and testing time. Service discovery functionality works by providing configuration in the format expected by the _configuration-based endpoint resolver_ from the Aspire AppHost project to the individual service projects added to the application model. For more information, see [Service discovery in .NET](https://learn.microsoft.com/dotnet/core/extensions/service-discovery). +Service discovery is how your services find each other. Instead of hardcoding URLs like `http://localhost:5001`, your frontend can simply reference the `catalog` service by name—and Aspire handles resolving the actual address. + +## How service discovery works + +When you connect services using `WithReference()`, Aspire sets up automatic service discovery: + +1. **AppHost declares resources** and allocates endpoints +2. **Configuration is injected** into each service via environment variables +3. **Your code uses logical names** like `https+http://catalog` +4. **Aspire's resolver** translates names to actual addresses at runtime + +**The key insight**: Your code uses logical service names (like `catalog`), and Aspire's configuration-based endpoint resolver translates those to actual addresses at runtime. + + ## Implicit service discovery by reference @@ -22,7 +37,14 @@ var frontend = builder.AddProject("frontend") .WithReference(catalog); ``` -In the preceding example, the _frontend_ project references the _catalog_ project and the _basket_ project. The two `WithReference` calls instruct the Aspire project to pass service discovery information for the referenced projects (_catalog_, and _basket_) into the _frontend_ project. +In the preceding example, the _frontend_ project references the _catalog_ project and the _basket_ project. The two `WithReference` calls instruct Aspire to: + +1. **Inject configuration** - Pass service discovery information for `catalog` and `basket` into `frontend` +2. **Enable resolution** - Allow `frontend` to use URIs like `https+http://catalog` in HttpClient + + ## Named endpoints @@ -111,3 +133,54 @@ Similarly, the "dashboard" endpoint can be targeted as follows: builder.Services.AddHttpClient( static client => client.BaseAddress = new("https://_dashboard.basket")); ``` + +## Troubleshooting + +### Service not found or "No endpoints resolved" + +**Symptoms**: HttpClient throws an exception like "No endpoints resolved for service 'myservice'" or connection is refused. + +**Common causes**: +1. **Missing `WithReference()`** - The calling service wasn't connected to the target service in AppHost +2. **Wrong service name** - The name in your URI doesn't match the name in `AddProject()` or `AddContainer()` +3. **Service not started** - The target service failed to start or is still starting + +**Solution**: Verify your AppHost connects the services: + +```csharp +var api = builder.AddProject("api"); +var frontend = builder.AddProject("frontend") + .WithReference(api); // ← This is required! +``` + +### Named endpoint doesn't resolve + +**Symptoms**: Using `https://_endpointName.serviceName` returns an error. + +**Solution**: Verify the endpoint is named in your AppHost: + +```csharp +var api = builder.AddProject("api") + .WithHttpEndpoint(port: 9999, name: "dashboard"); // ← Name must match +``` + +Then use the exact name with underscore prefix: + +```csharp +client.BaseAddress = new("https://_dashboard.api"); +``` + +### Understanding the URI format + +The `https+http://` prefix means "prefer HTTPS, fall back to HTTP". Here's the breakdown: + +| URI Format | Meaning | +|------------|---------| +| `https://catalog` | HTTPS only to default endpoint | +| `http://catalog` | HTTP only to default endpoint | +| `https+http://catalog` | Prefer HTTPS, fall back to HTTP | +| `https://_admin.catalog` | HTTPS to named "admin" endpoint | + + diff --git a/src/frontend/src/content/docs/get-started/aspire-sdk.mdx b/src/frontend/src/content/docs/get-started/aspire-sdk.mdx index 440b26f6d..1dc7ead19 100644 --- a/src/frontend/src/content/docs/get-started/aspire-sdk.mdx +++ b/src/frontend/src/content/docs/get-started/aspire-sdk.mdx @@ -82,7 +82,7 @@ For example, if you have two microservices with the same project name (like `Pre This generates `Projects.MicroService1` and `Projects.MicroService2` classes, allowing you to reference each project distinctly in your AppHost: -```csharp +```csharp title="AppHost.cs" var microservice1 = builder.AddProject("micro1"); var microservice2 = builder.AddProject("micro2"); ``` diff --git a/src/frontend/src/content/docs/get-started/first-app.mdx b/src/frontend/src/content/docs/get-started/first-app.mdx index dd69bd024..6c74716ba 100644 --- a/src/frontend/src/content/docs/get-started/first-app.mdx +++ b/src/frontend/src/content/docs/get-started/first-app.mdx @@ -212,8 +212,8 @@ To create your first Aspire application, use the [Aspire CLI](/get-started/insta - `CreateBuilder` creates the distributed application builder - `AddProject` registers your API service and web frontend - - `WithReference` creates a connection between services (the web app can call the API) - - `WaitFor` ensures services start in the correct order + - `WithReference` connects services—it injects the API's URL as an environment variable and sets up service discovery so you can use service names instead of hardcoded URLs + - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors from race conditions - `WithHttpHealthCheck` monitors service health @@ -244,8 +244,8 @@ To create your first Aspire application, use the [Aspire CLI](/get-started/insta - `AddUvicornApp` adds a Uvicorn-based Python app - `AddUv` adds a Uv environment setup task: `uv sync` - `AddViteApp` registers your React frontend - - `WithReference` connects the frontend to the API - - `WaitFor` ensures the API starts before the frontend + - `WithReference` connects the frontend to the API—it injects the API's URL and sets up service discovery + - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors - `PublishWithContainerFiles` bundles the frontend for production deployment @@ -375,4 +375,6 @@ import pythonDashboardDark from '@assets/get-started/python-aspire-dashboard-dar You might be eager to deploy this app next—and we'll show you how Aspire handles that—but you're probably also wondering: "How do I _test_ all this?" Great question! Aspire doesn't just orchestrate locally and deploy, it also helps you test service and resource integrations too. Ready to dive in? [Write your first test](/testing/write-your-first-test/) 💜 + +Having trouble? Check out our [Troubleshooting guide](/get-started/troubleshooting/) for solutions to common problems. \ No newline at end of file diff --git a/src/frontend/src/content/docs/get-started/glossary.mdx b/src/frontend/src/content/docs/get-started/glossary.mdx new file mode 100644 index 000000000..9e8cef92a --- /dev/null +++ b/src/frontend/src/content/docs/get-started/glossary.mdx @@ -0,0 +1,336 @@ +--- +title: Aspire glossary +description: Key terms and concepts used throughout .NET Aspire documentation, including AppHost, resources, service discovery, and orchestration terminology. +--- + +import { Aside } from '@astrojs/starlight/components'; + +This glossary defines the key terms and concepts you'll encounter when working with Aspire. Bookmark this page as a quick reference. + +## Core concepts + +These are the foundational concepts you need to understand when working with Aspire. + +### AppHost + +The **AppHost** is the orchestration project where you define your entire application's architecture in C# code. It's a special Aspire project that: + +- Declares what services, databases, and containers make up your application +- Defines how resources depend on each other +- Configures how resources communicate +- Orchestrates startup order during local development +- Generates deployment manifests for production + +Think of it as the "control tower" for your distributed application. + +```csharp title="AppHost.cs" +// This IS the AppHost - Program.cs in your AppHost project +var builder = DistributedApplication.CreateBuilder(args); + +var db = builder.AddPostgres("db"); +var api = builder.AddProject("api") + .WithReference(db); + +builder.Build().Run(); +``` + +### Resource + +A **resource** is any component that your application depends on. Resources can be: + +| Resource type | Examples | +|--------------|----------| +| **Projects** | .NET applications, services, APIs | +| **Containers** | Docker containers (databases, caches, message brokers) | +| **Executables** | Node.js apps, Python scripts, any executable | +| **Cloud services** | Azure Storage, AWS S3, managed databases | +| **Parameters** | Configuration values, secrets | + +Resources are the building blocks you compose in your AppHost. + +### Distributed application + +A **distributed application**is an application split into multiple independent services that communicate over a network. Instead of one monolithic application, you have: + +- A frontend service +- One or more API services +- Databases +- Caches +- Message queues +- etc. + +Aspire helps you orchestrate all these pieces together. + +### Service defaults + +**Service defaults**are pre-configured settings that Aspire applies to your .NET projects automatically. They include: + +- **OpenTelemetry** - Automatic logging, tracing, and metrics +- **Health checks** - Endpoints for monitoring (`/health`, `/alive`) +- **Service discovery** - Automatic resolution of service URLs +- **Resilience** - Retry policies for HTTP calls + +When you add `builder.AddServiceDefaults()` to a project, you get production-ready observability and resilience out of the box. + +--- + +## APIs and patterns + +These are the key APIs and patterns you'll use when building Aspire applications. + +### WithReference + +`WithReference()` is how you connect resources together. When you call `.WithReference(otherResource)`, Aspire: + +1. Injects the connection information as environment variables +2. Sets up service discovery so your code can find the other resource +3. Creates a dependency relationship for startup ordering + +```csharp title="AppHost.cs" +var db = builder.AddPostgres("db"); +var api = builder.AddProject("api") + .WithReference(db); // API now has DATABASE connection info injected +``` + +The API project will receive environment variables like: +- `ConnectionStrings__db` - The database connection string +- Service discovery configuration for the "db" resource + +### WaitFor + +`WaitFor()` tells Aspire to delay starting a resource until its dependency is ready: + +```csharp title="AppHost.cs" +var db = builder.AddPostgres("db"); +var api = builder.AddProject("api") + .WithReference(db) + .WaitFor(db); // Don't start API until database is healthy +``` + + + +### WaitForCompletion + +`WaitForCompletion()` waits for a resource to finish and exit (not just start). Useful for setup scripts: + +```csharp title="AppHost.cs" +var migrate = builder.AddProject("migrate"); +var api = builder.AddProject("api") + .WaitForCompletion(migrate); // Wait for migrations to complete +``` + +### WaitForStart + +`WaitForStart()` waits only for a resource to reach the running state, without waiting for health checks to pass: + +```csharp title="AppHost.cs" +var db = builder.AddPostgres("db"); +var api = builder.AddProject("api") + .WaitForStart(db); // Start as soon as db is running, don't wait for healthy +``` + + + +--- + +## Key terms + +These terms appear frequently throughout the documentation and in error messages. + +### Connection string + +A **connection string** is a formatted string containing the information needed to connect to a resource (database, cache, message broker, etc.). In Aspire, connection strings are: + +- Automatically generated by the AppHost based on resource configuration +- Injected into your application as environment variables +- Retrieved using `builder.Configuration.GetConnectionString("resource-name")` + +Example: `Host=localhost;Port=5432;Database=mydb;Username=postgres;Password=secret` + +### Service discovery + +**Service discovery**is the mechanism that allows your services to find and communicate with each other by name, without hardcoding addresses. In Aspire: + +- Resources are addressable by their resource name (e.g., `http://apiservice`) +- The AppHost configures DNS/environment variables so services can resolve each other +- Works automatically when you use `WithReference()` + +For details, see [Service Discovery](/fundamentals/service-discovery/). + +### Health check + +A **health check**is a mechanism to determine if a resource is ready and functioning. Aspire uses health checks in two ways: + +1. **AppHost level**: Determines when dependencies are ready (controls `WaitFor()` behavior) +2. **Application level**: Exposes `/health` and `/alive` endpoints for load balancers + +For details, see [Health Checks](/fundamentals/health-checks/). + +### Environment variable + +Aspire uses **environment variables**to pass configuration from the AppHost to your services: + +- Connection strings: `ConnectionStrings__resourcename` +- Service endpoints: `services__servicename__https__0` +- Custom values via `WithEnvironment()` + +Your application reads these using standard .NET configuration (`IConfiguration`). + +--- + +## Resource types + +Aspire uses two types of NuGet packages to work with resources. + +### Hosting integration + +A **hosting integration** is an Aspire package that helps you add and configure resources in your AppHost. Hosting integrations: + +- Add containers or cloud resources to your app model +- Configure networking, health checks, and volumes +- Handle connection string generation + +Example: `Aspire.Hosting.PostgreSQL` adds the `AddPostgres()` method. + +### Client integration + +A **client integration**is an Aspire package that helps your application code connect to resources. Client integrations: + +- Register SDK clients with dependency injection +- Configure connection strings from environment variables +- Add health checks and telemetry + +Example: `Aspire.Npgsql` registers `NpgsqlConnection` for PostgreSQL. + +### The relationship + +``` +┌─────────────────────────────────────────────────────────────┐ +│ AppHost (uses Hosting Integration) │ +│ Aspire.Hosting.PostgreSQL → AddPostgres("db") │ +│ ↓ │ +│ Injects connection info │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ API Project (uses Client Integration) │ +│ Aspire.Npgsql → builder.AddNpgsqlDataSource("db") │ +│ ↓ │ +│ Reads connection from env vars │ +│ Registers NpgsqlConnection in DI │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## Execution modes + +Aspire operates in two distinct modes depending on what you're trying to accomplish. + +### Run mode + +**Run mode** is local development. When you execute `aspire run` or debug your AppHost: + +- Aspire starts all your resources locally +- Containers run in Docker +- The Aspire Dashboard shows logs and traces +- Service discovery uses localhost addresses + +### Publish mode + +**Publish mode**generates deployment artifacts. When you execute `aspire publish`: + +- Aspire generates Kubernetes manifests, Docker Compose files, or cloud infrastructure +- No containers are started locally +- Connection strings reference production endpoints +- Output is ready for CI/CD pipelines + +--- + +## Dashboard and observability + +Aspire provides built-in tools for monitoring and debugging your applications. + +### Aspire dashboard + +The **Aspire Dashboard** is a web UI that automatically runs during local development. It shows: + +- All your resources and their status +- Real-time logs from every service +- Distributed traces across service calls +- Metrics and performance data +- Resource health checks + +Access it at the URL shown when you run `aspire run` (typically `http://localhost:15888`). + +### OpenTelemetry + +**OpenTelemetry** (OTEL) is the observability standard that Aspire uses for: + +- **Logs** - Structured logging with context +- **Traces** - Following requests across services +- **Metrics** - Performance measurements + +Aspire configures OpenTelemetry automatically through service defaults. + +--- + +## Common patterns + +These patterns appear frequently in Aspire applications. + +### Emulator pattern + +Many hosting integrations support running as an **emulator** for local development: + +```csharp title="AppHost.cs" +var storage = builder.AddAzureStorage("storage") + .RunAsEmulator(); // Uses Azurite container locally +``` + +This lets you develop against Azure, AWS, or other cloud services without needing actual cloud accounts during development. + +### Existing resource pattern + +Connect to resources that already exist (not managed by Aspire): + +```csharp title="AppHost.cs" +var existingDb = builder.AddPostgres("db") + .AsExisting(name, resourceGroup); +``` + +Use this for production databases or shared team resources. + +--- + +## API reference terms + +These terms appear frequently in API documentation and advanced usage: + +| Term | Description | +|------|-------------| +| `IResourceAnnotation` | Typed metadata object attached to resources. | +| `WithAnnotation()` | Fluent method to attach typed annotations. | +| `ReferenceExpression` | Structured formatter preserving value references. | +| `ResourceNotificationService` | Publishes observable state updates. | + +| Concept | Definition | +|---------|------------| +| DAG | Directed acyclic graph—the structure of resource dependencies. | +| Heterogeneous DAG | DAG containing varied resource types (projects, containers, cloud). | +| Publisher | Component that emits deployment artifacts from the app model. | +| Hoisting | Leaving a value unresolved for later substitution at runtime. | +| Deferred evaluation | Computing a value only when needed. | +| Lifecycle events | Time-based signals for resource transitions. | + +--- + +## See also + +- [What is Aspire?](/get-started/what-is-aspire/) +- [Create your first Aspire app](/get-started/first-app/) +- [AppHost overview](/get-started/app-host/) diff --git a/src/frontend/src/content/docs/get-started/troubleshooting.mdx b/src/frontend/src/content/docs/get-started/troubleshooting.mdx new file mode 100644 index 000000000..db0a11273 --- /dev/null +++ b/src/frontend/src/content/docs/get-started/troubleshooting.mdx @@ -0,0 +1,164 @@ +--- +title: Aspire troubleshooting guide +description: Solutions to common problems when getting started with .NET Aspire, including Docker issues, port conflicts, and service discovery errors. +--- + +import { Aside } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components'; +import LearnMore from '@components/LearnMore.astro'; +import Expand from '@components/Expand.astro'; + +Having issues getting started with Aspire? This page covers solutions to the most common problems developers encounter. + +## Docker Desktop not running + +**Symptoms**: `aspire run` hangs or shows "waiting for container runtime" messages. + +**Solution**: Start Docker Desktop (or Podman) before running `aspire run`. Check your system tray to confirm Docker is running with a green status indicator. + + + +## Port already in use + +**Symptoms**: Error message like "Address already in use" or "Port 5000 is already bound." + +**Solution**: +- Stop any other applications using the same ports +- If you have another Aspire app running, stop it first with + + + +**Windows:** +```powershell +netstat -ano | findstr :5000 +# Find the PID in the last column, then: +taskkill /PID /F +``` + +**macOS/Linux:** +```bash +lsof -i :5000 +# Then kill the process: +kill -9 +``` + + + +## Service shows "Unhealthy" in dashboard + +**Symptoms**: A service has a red status or shows "Unhealthy" in the Aspire dashboard. + +**Solution**: +1. Click on the service name in the dashboard to view its logs +2. Look for startup errors or exceptions +3. Verify the health check endpoint exists (e.g., `/health` returns a 200 OK) +4. Check that all dependencies started successfully + +## "Connection refused" errors + +**Symptoms**: Your frontend can't connect to the API, showing connection refused errors. + +**Solution**: Make sure you're using `WaitFor()` in your AppHost: + +```csharp title="AppHost.cs" +builder.AddProject("frontend") + .WithReference(apiService) + .WaitFor(apiService); // Add this line! +``` + +## Environment variables not available + +**Symptoms**: Your service can't find connection strings or configuration that should be injected. + +**Solution**: Verify you're using `WithReference()` to connect resources. + + + +In your AppHost: + +```csharp title="AppHost.cs" +var db = builder.AddPostgres("db"); +var api = builder.AddProject("api") + .WithReference(db); // This injects the connection string +``` + +In your service code, access the connection string via configuration: + +```csharp title="Program.cs" +var connectionString = builder.Configuration.GetConnectionString("db"); +``` + +The connection string is injected as an environment variable named `ConnectionStrings__db`. + + + +## Container image pull failures + +**Symptoms**: Error messages about failing to pull container images, or "image not found" errors. + +**Solution**: +- Check your internet connection +- Verify Docker Hub or your container registry is accessible +- If using a corporate network, check proxy settings in Docker Desktop + + + +```bash +# Try pulling the image manually +docker pull redis:latest + +# If behind a proxy, configure Docker Desktop: +# Settings > Resources > Proxies > Manual proxy configuration +``` + + + +## Dashboard not loading + +**Symptoms**: The Aspire dashboard URL doesn't respond or shows a blank page. + +**Solution**: +1. Check the console output for the correct dashboard URL (it may use a different port) +2. Ensure no browser extensions are blocking the page +3. Try a different browser or incognito mode +4. Check if antivirus or firewall is blocking the connection + +## Service discovery not working + +**Symptoms**: Services can't find each other by name (e.g., `http://apiservice` doesn't resolve). + +**Solution**: Ensure you're using the service name exactly as defined in your AppHost. + + + +```csharp title="AppHost.cs" +// In AppHost +var api = builder.AddProject("apiservice"); // Name is "apiservice" +``` + +```csharp title="Program.cs" +// In your consuming service, use exactly this name +var client = new HttpClient { BaseAddress = new Uri("http://apiservice") }; +``` + +Also verify: +- Both services have `AddServiceDefaults()` called +- The consuming service has `.WithReference(api)` in the AppHost + + + + +For a deeper understanding of how service discovery works in Aspire, see [Service discovery](/fundamentals/service-discovery/). + + + +For more help, see [Aspire Support](/support/) or check the [GitHub Discussions](https://github.com/dotnet/aspire/discussions). + + +## See also + +- [Create your first Aspire app](/get-started/first-app/) +- [Health checks](/fundamentals/health-checks/) +- [Service discovery](/fundamentals/service-discovery/) diff --git a/src/frontend/src/content/docs/get-started/what-is-aspire.mdx b/src/frontend/src/content/docs/get-started/what-is-aspire.mdx index 6dba29b61..0b2c1e3a5 100644 --- a/src/frontend/src/content/docs/get-started/what-is-aspire.mdx +++ b/src/frontend/src/content/docs/get-started/what-is-aspire.mdx @@ -5,11 +5,91 @@ tableOfContents: true lastUpdated: true --- -import { Aside } from '@astrojs/starlight/components'; +import { Aside, Steps } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; Aspire streamlines building, running, debugging, and deploying distributed apps. Picture your app as a set of services, databases, and frontends—when they're deployed, they all work together seamlessly, but every time you develop them they need to be individually started and connected. With Aspire, you get a unified toolchain that eliminates complex configs and makes local debugging effortless. Instantly launch and debug your entire app with a single command. Ready to deploy? Aspire lets you publish anywhere—Kubernetes, the cloud, or your own servers. It's also fully extensible, so you can integrate your favorite tools and services with ease. +## Why Aspire? + +Building modern applications means juggling multiple services, databases, and dependencies. Here's what that looks like **without** Aspire: + +### The pain of distributed development + +| Problem | Without Aspire | With Aspire | +|---------|----------------|-------------| +| **Starting services** | Open 5 terminals, run 5 different commands, hope they start in the right order | Run `aspire run` — everything starts automatically. See [AppHost overview](/get-started/app-host/). | +| **Connection strings** | Hardcode `localhost:5432` everywhere, break production deploys | Service discovery handles it — same code works locally and in production. See [Service discovery](/fundamentals/service-discovery/). | +| **"Works on my machine"** | Different team members have different ports, different configs | One AppHost definition, everyone runs the same setup. See [First app tutorial](/get-started/first-app/). | +| **Debugging** | Attach debugger to each service individually | Debug your entire stack with a single F5. See [Debugging overview](/fundamentals/debugging/). | +| **Finding logs** | Check 5 different terminal windows | Aspire Dashboard shows all logs in one place. See [Dashboard overview](/dashboard/overview/). | +| **Adding a database** | Install locally, configure connection, hope versions match | `builder.AddPostgres("db")` — containerized, versioned, consistent. See [Integrations](/integrations/overview/). | + +### Before and after + +**Without Aspire**, your startup routine might look like: + + + +1. Start the database container + + ```bash frame="terminal" data-disable-copy + docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=secret postgres:15 + ``` + +2. Start the C# API service + + ```bash frame="terminal" data-disable-copy + cd api && dotnet run + ``` + +3. Start the Python worker + + ```bash frame="terminal" data-disable-copy + cd worker && source .venv/bin/activate && python main.py + ``` + +4. Start the JavaScript frontend + + ```bash frame="terminal" data-disable-copy + cd frontend && npm run dev + ``` + +5. Manually verify they can all connect... + + Frustration ensues. 🙁 + + + +**With Aspire**, it's just: + +```bash +aspire run +``` + +And your AppHost defines everything in type-safe C#—even for polyglot stacks: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var db = builder.AddPostgres("db"); + +var api = builder.AddProject("api") + .WithReference(db); + +var worker = builder.AddPythonApp("worker", "../worker", "main.py") + .WithReference(db); + +builder.AddNpmApp("frontend", "../frontend") + .WithReference(api); + +builder.Build().Run(); +``` + + + ## Key benefits - **Unified Development Experience**: Launch and debug your entire distributed application with a single command. diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-application-insights.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-application-insights.mdx new file mode 100644 index 000000000..fe2aa3986 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-application-insights.mdx @@ -0,0 +1,260 @@ +--- +title: Azure Application Insights +description: Learn how to use the Azure Application Insights hosting integration to add application performance monitoring and telemetry to your Aspire application. +--- + +import { Aside } from '@astrojs/starlight/components'; +import InstallPackage from '@components/InstallPackage.astro'; +import { Image } from 'astro:assets'; +import appInsightsIcon from '@assets/icons/azure-appinsights-icon.png'; + +Azure Application Insights logo + +[Azure Application Insights](https://azure.microsoft.com/services/monitor/) is an extensible Application Performance Management (APM) service for developers and DevOps professionals. The Aspire Azure Application Insights integration enables you to provision Application Insights resources for collecting telemetry data from your applications. + +## Hosting integration + +The Aspire Azure Application Insights hosting integration models the Application Insights component as the following type: + +- `AzureApplicationInsightsResource`: Represents an Azure Application Insights resource. + +To access this type and APIs, add the [📦 Aspire.Hosting.Azure.ApplicationInsights](https://www.nuget.org/packages/Aspire.Hosting.Azure.ApplicationInsights) NuGet package to your AppHost project. + + + +### Add Azure Application Insights resource + +In your AppHost project, call `AddAzureApplicationInsights` to add and return an Azure Application Insights resource builder: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var appInsights = builder.AddAzureApplicationInsights("app-insights"); + +builder.AddProject() + .WithReference(appInsights); + +// After adding all resources, run the app... +``` + +The preceding code: + +- Adds an Azure Application Insights resource named `app-insights` to the application model. +- Automatically creates a Log Analytics workspace to store the telemetry data. +- References the Application Insights resource in the `ExampleProject`, making the connection string available. + + + +### Use with existing Log Analytics workspace + +If you have an existing Log Analytics workspace that you want to use, you can link Application Insights to it: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var logAnalytics = builder.AddAzureLogAnalyticsWorkspace("log-analytics"); +var appInsights = builder.AddAzureApplicationInsights("app-insights", logAnalytics); + +builder.AddProject() + .WithReference(appInsights); + +// After adding all resources, run the app... +``` + +The preceding code: + +- Adds an Azure Log Analytics workspace resource named `log-analytics`. +- Adds an Azure Application Insights resource named `app-insights` that uses the specified Log Analytics workspace. +- References the Application Insights resource in the `ExampleProject`. + +### Configure Log Analytics workspace after creation + +You can also configure the Log Analytics workspace using the fluent API: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var logAnalytics = builder.AddAzureLogAnalyticsWorkspace("log-analytics"); +var appInsights = builder.AddAzureApplicationInsights("app-insights") + .WithLogAnalyticsWorkspace(logAnalytics); + +builder.AddProject() + .WithReference(appInsights); + +// After adding all resources, run the app... +``` + +### Connection properties + +The Azure Application Insights resource exposes the following connection property: + +| Property name | Description | +|---------------|-------------| +| `appInsightsConnectionString` | The connection string for Application Insights. | + +This connection string is automatically made available to referencing projects as an environment variable named `APPLICATIONINSIGHTS_CONNECTION_STRING` (or based on the resource name). + +### Provisioning-generated Bicep + +If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by-hand—the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Application Insights resource, the following Bicep is generated: + +```bicep title="Generated Bicep — app-insights.bicep" +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param applicationType string = 'web' + +param kind string = 'web' + +param logAnalyticsWorkspaceId string + +resource app_insights 'Microsoft.Insights/components@2020-02-02' = { + name: take('app-insights-${uniqueString(resourceGroup().id)}', 260) + kind: kind + location: location + properties: { + Application_Type: applicationType + WorkspaceResourceId: logAnalyticsWorkspaceId + } + tags: { + 'aspire-resource-name': 'app-insights' + } +} + +output appInsightsConnectionString string = app_insights.properties.ConnectionString +``` + +The preceding Bicep provisions an Azure Application Insights component linked to a Log Analytics workspace for storing telemetry data. + +The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files. + +#### Customize provisioning infrastructure + +All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources using the `ConfigureInfrastructure` API. For example, you can configure the application type, retention settings, and more. The following example demonstrates how to customize the Azure Application Insights resource: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var appInsights = builder.AddAzureApplicationInsights("app-insights") + .ConfigureInfrastructure(infra => + { + var insights = infra.GetProvisionableResources() + .OfType() + .Single(); + + insights.RetentionInDays = 90; + insights.IngestionMode = ComponentIngestionMode.LogAnalytics; + insights.Tags.Add("environment", "production"); + }); + +builder.AddProject() + .WithReference(appInsights); +``` + +The preceding code: + +- Chains a call to the `ConfigureInfrastructure` API: + - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type. + - The provisionable resources are retrieved by calling `GetProvisionableResources`. + - The `ApplicationInsightsComponent` is configured with 90-day retention and a custom tag. + +For more information, see [Customize Azure resources](/integrations/cloud/azure/customize-resources/). For the full list of configurable properties, see the [Azure.Provisioning.ApplicationInsights](https://learn.microsoft.com/dotnet/api/azure.provisioning.applicationinsights) API documentation. + +## Client integration + + + +### Configure Application Insights in your application + +To use Application Insights in your application, configure the OpenTelemetry exporter in your service defaults: + +```csharp title="C# — Extensions.cs" +public static IHostApplicationBuilder AddServiceDefaults( + this IHostApplicationBuilder builder) +{ + builder.ConfigureOpenTelemetry(); + + // ... other configuration + + return builder; +} + +public static IHostApplicationBuilder ConfigureOpenTelemetry( + this IHostApplicationBuilder builder) +{ + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; +} + +private static IHostApplicationBuilder AddOpenTelemetryExporters( + this IHostApplicationBuilder builder) +{ + var useOtlpExporter = !string.IsNullOrWhiteSpace( + builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry() + .UseOtlpExporter(); + } + + // Application Insights will automatically pick up the connection string + // from the APPLICATIONINSIGHTS_CONNECTION_STRING environment variable + + return builder; +} +``` + +Alternatively, you can use the Azure Monitor OpenTelemetry exporter directly: + +```csharp title="C# — Program.cs" +builder.Services.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = builder.Configuration + .GetConnectionString("app-insights"); + }); +``` + +## See also + +- [Application Insights overview](https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview) +- [Azure Monitor OpenTelemetry for .NET](https://learn.microsoft.com/azure/azure-monitor/app/opentelemetry-enable) +- [Azure Log Analytics integration](/integrations/cloud/azure/azure-log-analytics/) +- [Azure integration overview](/integrations/cloud/azure/overview/) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-data-explorer.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-data-explorer.mdx new file mode 100644 index 000000000..28cc66d6d --- /dev/null +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-data-explorer.mdx @@ -0,0 +1,308 @@ +--- +title: Azure Data Explorer (Kusto) +description: Learn how to use the Azure Data Explorer (Kusto) hosting integration to add Kusto clusters and databases to your Aspire application. +--- + +import { Aside } from '@astrojs/starlight/components'; +import InstallPackage from '@components/InstallPackage.astro'; +import { Image } from 'astro:assets'; +import kustoIcon from '@assets/icons/azure-dataexplorer-icon.svg'; + +Azure Data Explorer logo + +[Azure Data Explorer](https://azure.microsoft.com/services/data-explorer/) (also known as Kusto) is a fast and highly scalable data exploration service for log and telemetry data. The Aspire Azure Data Explorer integration enables you to provision Kusto clusters and databases, or run a local emulator during development. + +## Hosting integration + +The Aspire Azure Data Explorer hosting integration models Kusto resources as the following types: + +- `AzureKustoClusterResource`: Represents an Azure Data Explorer (Kusto) cluster resource. +- `AzureKustoReadWriteDatabaseResource`: Represents an Azure Data Explorer database resource. +- `AzureKustoEmulatorResource`: Represents an Azure Data Explorer emulator resource. + +To access these types and APIs, add the [📦 Aspire.Hosting.Azure.Kusto](https://www.nuget.org/packages/Aspire.Hosting.Azure.Kusto) NuGet package to your AppHost project. + + + +### Add Azure Data Explorer cluster resource + +In your AppHost project, call `AddAzureKustoCluster` to add and return an Azure Data Explorer cluster resource builder: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var kusto = builder.AddAzureKustoCluster("kusto"); + +builder.AddProject() + .WithReference(kusto); + +// After adding all resources, run the app... +``` + +The preceding code adds an Azure Data Explorer cluster resource named `kusto` to the application model. + + + +### Add Azure Data Explorer database + +To add a database to a Kusto cluster, call the `AddReadWriteDatabase` method on the cluster resource builder: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var kusto = builder.AddAzureKustoCluster("kusto"); +var database = kusto.AddReadWriteDatabase("analytics"); + +builder.AddProject() + .WithReference(database) + .WaitFor(database); + +// After adding all resources, run the app... +``` + +The preceding code: + +- Adds an Azure Data Explorer cluster resource named `kusto`. +- Adds a database named `analytics` to the cluster. +- References the database in the `ExampleProject` and waits for it to be ready. + +### Run Azure Data Explorer as an emulator + +For local development and testing, you can run Azure Data Explorer as an emulator using the Kustainer container. Call the `RunAsEmulator` method: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var kusto = builder.AddAzureKustoCluster("kusto") + .RunAsEmulator(); + +var database = kusto.AddReadWriteDatabase("analytics"); + +builder.AddProject() + .WithReference(database) + .WaitFor(database); + +// After adding all resources, run the app... +``` + +When running as an emulator: + +- The Kustainer Docker container is used to emulate Azure Data Explorer. +- Databases are automatically created when the emulator starts. +- The connection string is automatically configured for local development. + +### Configure the emulator port + +By default, the emulator uses a dynamic port. To configure a specific host port: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var kusto = builder.AddAzureKustoCluster("kusto") + .RunAsEmulator(emulator => + { + emulator.WithHostPort(8080); + }); + +// After adding all resources, run the app... +``` + +### Add database creation script + +When running as an emulator, you can provide a KQL script to initialize the database with tables and data: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var kusto = builder.AddAzureKustoCluster("kusto") + .RunAsEmulator(); + +var database = kusto.AddReadWriteDatabase("analytics") + .WithCreationScript(""" + .create table Events ( + Timestamp: datetime, + EventType: string, + Message: string + ) + """); + +builder.AddProject() + .WithReference(database) + .WaitFor(database); + +// After adding all resources, run the app... +``` + + + +## Client integration + + + +### Connect to Azure Data Explorer from your application + +To connect to Azure Data Explorer from your application, use the connection string provided by Aspire: + +```csharp title="C# — Program.cs" +var connectionString = builder.Configuration.GetConnectionString("analytics"); + +var kcsb = new KustoConnectionStringBuilder(connectionString) + .WithAadAzureTokenCredentialsAuthentication(new DefaultAzureCredential()); + +using var client = KustoClientFactory.CreateCslQueryProvider(kcsb); +``` + +When running against the emulator, no authentication is required: + +```csharp title="C# — Program.cs" +var connectionString = builder.Configuration.GetConnectionString("analytics"); +var kcsb = new KustoConnectionStringBuilder(connectionString); + +using var client = KustoClientFactory.CreateCslQueryProvider(kcsb); +``` + +## Dashboard commands + +When an Azure Data Explorer cluster resource is running, the Aspire dashboard provides commands to open the Kusto Explorer: + +- **Open in Kusto Explorer (Desktop)**: Opens the desktop Kusto Explorer application (Windows only). +- **Open in Kusto Explorer (Web)**: Opens the web-based Kusto Explorer (Azure deployments only). + +## Connection string and properties + +When you add an Azure Data Explorer resource to your application, the connection properties are made available to consuming resources. The following properties are available: + +### Cluster resource + +| Property | Description | +|----------|-------------| +| `Uri` | The URI of the Azure Data Explorer cluster endpoint. | + +### Database resource + +| Property | Description | +|----------|-------------| +| `Uri` | The URI of the parent cluster endpoint (inherited from cluster). | +| `DatabaseName` | The name of the database. | + +The connection string format is: `Data Source=https://{cluster-uri};Initial Catalog={database-name}` + +### Provisioning-generated Bicep + +If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by-hand—the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Data Explorer resource, the following Bicep is generated: + +```bicep title="Generated Bicep — kusto.bicep" +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param principalId string + +param principalName string + +resource kusto 'Microsoft.Kusto/clusters@2024-04-13' = { + name: take('kusto${uniqueString(resourceGroup().id)}', 22) + location: location + sku: { + name: 'Dev(No SLA)_Standard_E2a_v4' + tier: 'Basic' + capacity: 1 + } + properties: { + enableAutoStop: true + } + tags: { + 'aspire-resource-name': 'kusto' + } +} + +resource analytics 'Microsoft.Kusto/clusters/databases@2024-04-13' = { + name: 'analytics' + location: location + kind: 'ReadWrite' + parent: kusto +} + +resource kusto_principalAssignment 'Microsoft.Kusto/clusters/principalAssignments@2024-04-13' = { + name: guid(kusto.id, principalId, 'AllDatabasesAdmin') + properties: { + principalId: principalId + principalType: 'App' + role: 'AllDatabasesAdmin' + } + parent: kusto +} + +output kustoClusterUri string = kusto.properties.uri +``` + +The preceding Bicep provisions an Azure Data Explorer cluster with a dev/test SKU and a read-write database. + +The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files. + +#### Customize provisioning infrastructure + +All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources using the `ConfigureInfrastructure` API. For example, you can configure the cluster SKU, capacity, and more. The following example demonstrates how to customize the Azure Data Explorer resource: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var kusto = builder.AddAzureKustoCluster("kusto") + .ConfigureInfrastructure(infra => + { + var cluster = infra.GetProvisionableResources() + .OfType() + .Single(); + + cluster.Sku = new KustoSku + { + Name = KustoSkuName.StandardE8aV4, + Tier = KustoSkuTier.Standard, + Capacity = 2 + }; + cluster.IsAutoStopEnabled = false; + cluster.Tags.Add("environment", "production"); + }) + .AddReadWriteDatabase("analytics"); +``` + +The preceding code: + +- Chains a call to the `ConfigureInfrastructure` API: + - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type. + - The provisionable resources are retrieved by calling `GetProvisionableResources`. + - The `KustoCluster` is configured with a Standard SKU, 2-node capacity, and auto-stop disabled. + +For more information, see [Customize Azure resources](/integrations/cloud/azure/customize-resources/). For the full list of configurable properties, see the [Azure.Provisioning.Kusto](https://learn.microsoft.com/dotnet/api/azure.provisioning.kusto) API documentation. + +## Health checks + +The Azure Data Explorer hosting integration automatically adds health checks for both cluster and database resources. The health check verifies that: + +- The cluster is reachable and responding to queries +- When using a database, the database exists and is accessible + +Health check status is displayed in the Aspire dashboard resource list. + +## See also + +- [Azure Data Explorer documentation](https://learn.microsoft.com/azure/data-explorer/) +- [Kusto Query Language (KQL) overview](https://learn.microsoft.com/azure/data-explorer/kusto/query/) +- [Kusto .NET SDK](https://learn.microsoft.com/azure/data-explorer/kusto/api/netfx/about-the-sdk) +- [Azure integration overview](/integrations/cloud/azure/overview/) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-log-analytics.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-log-analytics.mdx new file mode 100644 index 000000000..29dec8cec --- /dev/null +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-log-analytics.mdx @@ -0,0 +1,157 @@ +--- +title: Azure Log Analytics +description: Learn how to use the Azure Log Analytics hosting integration to add Log Analytics workspaces to your Aspire application for centralized logging and monitoring. +--- + +import { Aside } from '@astrojs/starlight/components'; +import InstallPackage from '@components/InstallPackage.astro'; +import { Image } from 'astro:assets'; +import logAnalyticsIcon from '@assets/icons/azure-loganalytics-icon.png'; + +Azure Log Analytics logo + +[Azure Log Analytics](https://azure.microsoft.com/services/monitor/) is a tool in Azure Monitor that allows you to edit and run log queries against data in Azure Monitor Logs. The Aspire Azure Log Analytics integration enables you to provision Log Analytics workspaces for centralized logging and monitoring. + +## Hosting integration + +The Aspire Azure Log Analytics hosting integration models the Log Analytics workspace as the following type: + +- `AzureLogAnalyticsWorkspaceResource`: Represents an Azure Log Analytics workspace resource. + +To access this type and APIs, add the [📦 Aspire.Hosting.Azure.OperationalInsights](https://www.nuget.org/packages/Aspire.Hosting.Azure.OperationalInsights) NuGet package to your AppHost project. + + + +### Add Azure Log Analytics workspace resource + +In your AppHost project, call `AddAzureLogAnalyticsWorkspace` to add and return an Azure Log Analytics workspace resource builder: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var logAnalytics = builder.AddAzureLogAnalyticsWorkspace("log-analytics"); + +// After adding all resources, run the app... +``` + +The preceding code adds an Azure Log Analytics workspace resource named `log-analytics` to the application model. + + + +### Use with Application Insights + +A common pattern is to use a Log Analytics workspace with Application Insights for centralized telemetry collection. You can link an Application Insights resource to a Log Analytics workspace: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var logAnalytics = builder.AddAzureLogAnalyticsWorkspace("log-analytics"); +var appInsights = builder.AddAzureApplicationInsights("app-insights", logAnalytics); + +builder.AddProject() + .WithReference(appInsights); + +// After adding all resources, run the app... +``` + +The preceding code: + +- Adds an Azure Log Analytics workspace resource named `log-analytics`. +- Adds an Azure Application Insights resource named `app-insights` that uses the Log Analytics workspace for log storage. +- References the Application Insights resource in the `ExampleProject`. + +For more information, see [Azure Application Insights integration](/integrations/cloud/azure/azure-application-insights/). + +### Connection properties + +The Azure Log Analytics workspace resource exposes the following connection property: + +| Property name | Description | +|---------------|-------------| +| `logAnalyticsWorkspaceId` | The resource ID of the Log Analytics workspace. | + +### Provisioning-generated Bicep + +If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by-hand—the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Log Analytics workspace resource, the following Bicep is generated: + +```bicep title="Generated Bicep — log-analytics.bicep" +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +resource log_analytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: take('log-analytics-${uniqueString(resourceGroup().id)}', 63) + location: location + properties: { + sku: { + name: 'PerGB2018' + } + } + tags: { + 'aspire-resource-name': 'log-analytics' + } +} + +output logAnalyticsWorkspaceId string = log_analytics.id +``` + +The preceding Bicep provisions an Azure Log Analytics workspace with the pay-per-GB pricing tier. + +The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files. + +#### Customize provisioning infrastructure + +All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources using the `ConfigureInfrastructure` API. For example, you can configure the SKU, retention period, and more. The following example demonstrates how to customize the Azure Log Analytics workspace: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var logAnalytics = builder.AddAzureLogAnalyticsWorkspace("log-analytics") + .ConfigureInfrastructure(infra => + { + var workspace = infra.GetProvisionableResources() + .OfType() + .Single(); + + workspace.Sku = new OperationalInsightsWorkspaceSku( + OperationalInsightsWorkspaceSkuName.PerGB2018); + workspace.RetentionInDays = 90; + workspace.Tags.Add("environment", "production"); + }); + +var appInsights = builder.AddAzureApplicationInsights("app-insights", logAnalytics); +``` + +The preceding code: + +- Chains a call to the `ConfigureInfrastructure` API: + - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type. + - The provisionable resources are retrieved by calling `GetProvisionableResources`. + - The `OperationalInsightsWorkspace` is configured with 90-day retention and a custom tag. + +For more information, see [Customize Azure resources](/integrations/cloud/azure/customize-resources/). For the full list of configurable properties, see the [Azure.Provisioning.OperationalInsights](https://learn.microsoft.com/dotnet/api/azure.provisioning.operationalinsights) API documentation. + +## Client integration + + + +## See also + +- [Azure Monitor Logs overview](https://learn.microsoft.com/azure/azure-monitor/logs/data-platform-logs) +- [Log Analytics workspace overview](https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-workspace-overview) +- [Azure Application Insights integration](/integrations/cloud/azure/azure-application-insights/) +- [Azure integration overview](/integrations/cloud/azure/overview/) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database.mdx index 82675e5df..fc968c619 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-sql-database.mdx @@ -95,6 +95,111 @@ The preceding code configures an Azure SQL Database resource to run locally in a > [!TIP] > The `RunAsContainer` method is useful for local development and testing. The API exposes an optional delegate that enables you to customize the underlying `SqlServerServerResource` configuration. For example, you can add a data volume or data bind mount. For more information, see the [Aspire SQL Server hosting integration](/integrations/databases/sql-server/sql-server-host/#add-sql-server-resource-with-data-volume) section. +### Provisioning-generated Bicep + +If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by-hand—the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure SQL Server resource, the following Bicep is generated: + +```bicep title="Generated Bicep — azuresql.bicep" +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param principalId string + +param principalName string + +resource sqlServerAdminManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: take('azuresql-admin-${uniqueString(resourceGroup().id)}', 63) + location: location +} + +resource azuresql 'Microsoft.Sql/servers@2024-05-01-preview' = { + name: take('azuresql-${uniqueString(resourceGroup().id)}', 63) + location: location + properties: { + administrators: { + administratorType: 'ActiveDirectory' + login: sqlServerAdminManagedIdentity.name + sid: sqlServerAdminManagedIdentity.properties.principalId + tenantId: subscription().tenantId + azureADOnlyAuthentication: true + } + minimalTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + version: '12.0' + } + tags: { + 'aspire-resource-name': 'azuresql' + } +} + +resource sqlFirewallRule_AllowAllAzureIps 'Microsoft.Sql/servers/firewallRules@2024-05-01-preview' = { + name: 'AllowAllAzureIps' + properties: { + endIpAddress: '0.0.0.0' + startIpAddress: '0.0.0.0' + } + parent: azuresql +} + +resource database 'Microsoft.Sql/servers/databases@2024-05-01-preview' = { + name: 'database' + location: location + properties: { + freeLimitExhaustionBehavior: 'AutoPause' + useFreeLimit: true + } + sku: { + name: 'GP_S_Gen5_2' + } + parent: azuresql +} + +output sqlServerFqdn string = azuresql.properties.fullyQualifiedDomainName + +output name string = azuresql.name + +output sqlServerAdminName string = azuresql.properties.administrators.login +``` + +The preceding Bicep provisions an Azure SQL Server with a managed identity administrator, TLS 1.2 minimum, and a General Purpose Serverless database with the Azure free offer enabled. + +The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files. + +#### Customize provisioning infrastructure + +All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources using the `ConfigureInfrastructure` API. For example, you can configure the `sku`, `version`, and more. The following example demonstrates how to customize the Azure SQL Database resource: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var sql = builder.AddAzureSqlServer("sql") + .ConfigureInfrastructure(infra => + { + var sqlServer = infra.GetProvisionableResources() + .OfType() + .Single(); + + sqlServer.MinTlsVersion = SqlMinimalTlsVersion.Tls1_3; + + var database = infra.GetProvisionableResources() + .OfType() + .Single(); + + database.Sku = new SqlSku { Name = "HS_Gen5_2" }; // Hyperscale + }) + .AddDatabase("db"); +``` + +The preceding code: + +- Chains a call to the `ConfigureInfrastructure` API: + - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type. + - The provisionable resources are retrieved by calling `GetProvisionableResources`. + - The `SqlServer` is configured with TLS 1.3 minimum. + - The `SqlDatabase` is configured with a Hyperscale SKU instead of the default serverless. + +For more information, see [Customize Azure resources](/integrations/cloud/azure/customize-resources/). For the full list of configurable properties, see the [Azure.Provisioning.Sql](https://learn.microsoft.com/dotnet/api/azure.provisioning.sql) API documentation. + ### Connection properties When you reference Azure SQL Server resources using `WithReference`, the following connection properties are made available to the consuming project: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs.mdx index b7c013f5c..33c21ba7a 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-blobs.mdx @@ -204,6 +204,93 @@ To connect to the storage resource from Azure Storage Explorer, follow these ste You're free to explore the storage account and its contents using the Azure Storage Explorer. For more information on using the Azure Storage Explorer, see [Get started with Storage Explorer](https://learn.microsoft.com/azure/storage/storage-explorer/vs-azure-tools-storage-manage-with-storage-explorer). +### Provisioning-generated Bicep + +If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by-hand—the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Storage resource with blob storage, the following Bicep is generated: + +```bicep title="Generated Bicep — storage.bicep" +@description('The location for the resource(s) to be deployed.') +param location string = resourceGroup().location + +param principalId string + +param principalType string + +resource storage 'Microsoft.Storage/storageAccounts@2024-01-01' = { + name: take('storage${uniqueString(resourceGroup().id)}', 24) + kind: 'StorageV2' + location: location + sku: { + name: 'Standard_GRS' + } + properties: { + accessTier: 'Hot' + allowSharedKeyAccess: false + minimumTlsVersion: 'TLS1_2' + networkAcls: { + defaultAction: 'Allow' + } + } + tags: { + 'aspire-resource-name': 'storage' + } +} + +resource blobs 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = { + name: 'default' + parent: storage +} + +resource storage_StorageBlobDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')) + properties: { + principalId: principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') + principalType: principalType + } + scope: storage +} + +output blobEndpoint string = storage.properties.primaryEndpoints.blob + +output name string = storage.name +``` + +The preceding Bicep provisions an Azure Storage account with a blob service, Standard GRS redundancy, TLS 1.2 minimum, and role assignments for blob data access. + +The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files. + +#### Customize provisioning infrastructure + +All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources using the `ConfigureInfrastructure` API. For example, you can configure the `sku`, `accessTier`, and more. The following example demonstrates how to customize the Azure Storage resource: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage") + .ConfigureInfrastructure(infra => + { + var storageAccount = infra.GetProvisionableResources() + .OfType() + .Single(); + + storageAccount.Sku = new StorageSku { Name = StorageSkuName.PremiumLrs }; + storageAccount.AccessTier = StorageAccountAccessTier.Premium; + storageAccount.Tags.Add("environment", "production"); + }); + +var blobs = storage.AddBlobs("blobs"); +``` + +The preceding code: + +- Chains a call to the `ConfigureInfrastructure` API: + - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type. + - The provisionable resources are retrieved by calling `GetProvisionableResources`. + - The `StorageAccount` is configured with Premium LRS storage and a custom tag. + +For more information, see [Customize Azure resources](/integrations/cloud/azure/customize-resources/). For the full list of configurable properties, see the [Azure.Provisioning.Storage](https://learn.microsoft.com/dotnet/api/azure.provisioning.storage) API documentation. + ### Connection properties When you reference Azure Storage resources using `WithReference`, the following connection properties are made available to the consuming project: diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-datalake.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-datalake.mdx new file mode 100644 index 000000000..760b1d262 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-storage-datalake.mdx @@ -0,0 +1,278 @@ +--- +title: Azure Data Lake Storage +description: Learn how to use the Aspire Azure Data Lake Storage integration to connect to Azure Data Lake Storage Gen2 for big data analytics workloads. +--- + +import { Aside } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import InstallPackage from '@components/InstallPackage.astro'; +import InstallDotNetPackage from '@components/InstallDotNetPackage.astro'; +import storageIcon from '@assets/icons/azure-storagecontainer-icon.png'; + +Azure Data Lake Storage logo + +[Azure Data Lake Storage Gen2](https://azure.microsoft.com/services/storage/data-lake-storage/) is a set of capabilities built on Azure Blob Storage for big data analytics. The Aspire Azure Data Lake Storage integration enables you to connect to Azure Data Lake Storage instances from your applications. + +## Hosting integration + +The Azure Data Lake Storage hosting integration models a Data Lake resource as a child of an Azure Storage resource. To add a Data Lake resource, install the [📦 Aspire.Hosting.Azure.Storage](https://www.nuget.org/packages/Aspire.Hosting.Azure.Storage) NuGet package in your [AppHost](/get-started/app-host/) project: + + + +### Add Azure Data Lake resource + +In your AppHost project, call `AddDataLake` on an `IResourceBuilder` to add a Data Lake resource: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage"); +var dataLake = storage.AddDataLake("datalake"); + +builder.AddProject() + .WithReference(dataLake); + +builder.Build().Run(); +``` + +The preceding code: + +- Adds an Azure Storage resource named `storage`. +- Adds a Data Lake resource named `datalake` as a child of the storage resource. +- Passes a reference to the Data Lake resource to the `ExampleProject`. + + + +### Add Azure Data Lake file system resource + +You can also add a Data Lake file system resource directly from the storage resource: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage"); +var dataLake = storage.AddDataLake("datalake"); +var fileSystem = storage.AddDataLakeFileSystem("analytics", "analytics-data"); + +builder.AddProject() + .WithReference(dataLake) + .WithReference(fileSystem); + +builder.Build().Run(); +``` + +The `AddDataLakeFileSystem` method takes: +- `name`: The resource name used in Aspire +- `dataLakeFileSystemName` (optional): The actual file system name in Azure. Defaults to the resource name if not specified. + + + +### Customize provisioning infrastructure + +The Data Lake resource is part of the Azure Storage resource, which is a subclass of `AzureProvisioningResource`. You can customize the generated Bicep using the `ConfigureInfrastructure` API on the storage resource. For example, you can configure the storage SKU, access tier, and other properties: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var storage = builder.AddAzureStorage("storage") + .ConfigureInfrastructure(infra => + { + var storageAccount = infra.GetProvisionableResources() + .OfType() + .Single(); + + storageAccount.Sku = new StorageSku { Name = StorageSkuName.PremiumLrs }; + storageAccount.Tags.Add("workload", "analytics"); + }); + +var dataLake = storage.AddDataLake("datalake"); + +builder.AddProject() + .WithReference(dataLake); +``` + +For more information on customizing Azure Storage provisioning, see [Azure Blob Storage: Customize provisioning infrastructure](/integrations/cloud/azure/azure-storage-blobs/#customize-provisioning-infrastructure). + +## Client integration + +To get started with the Aspire Azure Data Lake Storage client integration, install the [📦 Aspire.Azure.Storage.Files.DataLake](https://www.nuget.org/packages/Aspire.Azure.Storage.Files.DataLake) NuGet package in your client-consuming project: + + + +### Add Azure Data Lake service client + +In the `Program.cs` file of your client-consuming project, call `AddAzureDataLakeServiceClient` to register a `DataLakeServiceClient` for dependency injection: + +```csharp +builder.AddAzureDataLakeServiceClient("datalake"); +``` + +You can then retrieve the `DataLakeServiceClient` instance using dependency injection: + +```csharp +public class ExampleService(DataLakeServiceClient client) +{ + // Use client... +} +``` + +### Add Azure Data Lake file system client + +You can also register a `DataLakeFileSystemClient` for accessing a specific file system: + +```csharp +builder.AddAzureDataLakeFileSystemClient("analytics"); +``` + +You can then retrieve the `DataLakeFileSystemClient` instance using dependency injection: + +```csharp +public class ExampleService(DataLakeFileSystemClient client) +{ + // Use client... +} +``` + +### Keyed services + +Both client methods have keyed variants for registering multiple clients: + +```csharp +builder.AddKeyedAzureDataLakeServiceClient("datalake1"); +builder.AddKeyedAzureDataLakeServiceClient("datalake2"); + +builder.AddKeyedAzureDataLakeFileSystemClient("analytics"); +builder.AddKeyedAzureDataLakeFileSystemClient("archive"); +``` + +### Configuration + +The Azure Data Lake Storage client integration supports multiple configuration approaches. + +#### Use a connection string + +Provide the connection name when calling `AddAzureDataLakeServiceClient`: + +```csharp +builder.AddAzureDataLakeServiceClient("datalake"); +``` + +The connection string is retrieved from the `ConnectionStrings` section. Two formats are supported: + +**Service URI (recommended)**: + +```json +{ + "ConnectionStrings": { + "datalake": "https://{account_name}.dfs.core.windows.net/" + } +} +``` + +When using a service URI, the `DefaultAzureCredential` is used for authentication. + +**For file system clients**, include the file system name: + +```json +{ + "ConnectionStrings": { + "analytics": "https://{account_name}.dfs.core.windows.net/;FileSystemName=analytics-data" + } +} +``` + +**Azure Storage connection string**: + +```json +{ + "ConnectionStrings": { + "datalake": "DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey;EndpointSuffix=core.windows.net" + } +} +``` + +#### Use configuration providers + +The integration loads settings from the `Aspire:Azure:Storage:Files:DataLake` configuration section: + +```json +{ + "Aspire": { + "Azure": { + "Storage": { + "Files": { + "DataLake": { + "ServiceUri": "https://{account_name}.dfs.core.windows.net/", + "DisableHealthChecks": false, + "DisableTracing": false + } + } + } + } + } +} +``` + +#### Use inline delegates + +Configure settings programmatically: + +```csharp +builder.AddAzureDataLakeServiceClient( + "datalake", + settings => settings.DisableHealthChecks = true); +``` + +Configure client options: + +```csharp +builder.AddAzureDataLakeServiceClient( + "datalake", + configureClientBuilder: clientBuilder => + clientBuilder.ConfigureOptions( + options => options.Diagnostics.ApplicationId = "myapp")); +``` + +### Client integration health checks + +By default, the integration adds a health check that verifies connectivity to Azure Data Lake Storage. The health check: + +- Is enabled when `DisableHealthChecks` is `false` (the default) +- Integrates with the `/health` HTTP endpoint + +### Observability and telemetry + +#### Logging + +The integration uses these log categories: + +- `Azure.Core` +- `Azure.Identity` + +#### Tracing + +The integration emits OpenTelemetry tracing activities: + +- `Azure.Storage.Files.DataLake.DataLakeServiceClient` +- `Azure.Storage.Files.DataLake.DataLakeFileSystemClient` + +#### Metrics + +The Azure SDK for Data Lake Storage doesn't currently emit metrics. + +## See also + +- [Azure.Storage.Files.DataLake SDK documentation](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Files.DataLake/README.md) +- [Azure Data Lake Storage Gen2](https://learn.microsoft.com/azure/storage/blobs/data-lake-storage-introduction) +- [Azure Storage Blobs integration](/integrations/cloud/azure/azure-storage-blobs/) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx index a5b93b834..332207bc2 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx @@ -9,7 +9,13 @@ When working with Azure integrations in Aspire, you often need to customize the ## Azure.Provisioning customization -The `ConfigureInfrastructure` API provides a strongly-typed, C#-based way to customize Azure resources. This is the recommended approach for most customizations. +The `ConfigureInfrastructure` API provides a strongly-typed, C#-based way to customize Azure resources. This is the recommended approach for most customizations. It uses the [Azure.Provisioning](https://www.nuget.org/packages/Azure.Provisioning) library to generate Bicep from C# code. + + ### Basic infrastructure customization diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-ps.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-ps.mdx new file mode 100644 index 000000000..1a15d024a --- /dev/null +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-ps.mdx @@ -0,0 +1,85 @@ +--- +title: aspire ps command +description: Learn about the aspire ps command which lists all running Aspire AppHost processes with their process IDs and dashboard URLs. +--- + +import Include from '@components/Include.astro'; + +## Name + +`aspire ps` - List running Aspire AppHosts. + +## Synopsis + +```bash title="Aspire CLI" +aspire ps [options] +``` + +## Description + +The `aspire ps` command lists all running Aspire AppHost processes. The output includes the AppHost project path, process IDs, and dashboard URLs for each running instance. + +The command scans for running AppHosts by checking the backchannel connections in the `~/.aspire/backchannels/` directory. This approach is fast because it doesn't need to recursively search for project files. + +The default output is a human-readable table with the following columns: + +| Column | Description | +|--------|-------------| +| `PATH` | The file path to the AppHost project | +| `PID` | The process ID of the running AppHost | +| `CLI_PID` | The process ID of the CLI that started the AppHost | +| `DASHBOARD` | The dashboard URL with login token | + +In-scope AppHosts (those within the current directory) are displayed first, followed by out-of-scope AppHosts. + +## Options + +The following options are available: + +- **`--json`** + + Output results in JSON format. This is useful for scripting and automation scenarios. The JSON output includes an array of AppHost objects with `appHostPath`, `appHostPid`, `cliPid`, and `dashboardUrl` properties. + +- + +- + +## Examples + +- List all running AppHosts in table format: + + ```bash title="Aspire CLI" + aspire ps + ``` + + Example output: + + ```text title="Output" + PATH PID CLI_PID DASHBOARD + ./src/MyApp.AppHost/MyApp.AppHost.csproj 12345 12340 https://localhost:17244/login?t=abc123 + /home/user/other/OtherApp.AppHost.csproj 67890 67885 https://localhost:17250/login?t=def456 + ``` + +- Output running AppHosts as JSON for scripting: + + ```bash title="Aspire CLI" + aspire ps --json + ``` + + Example output: + + ```json title="Output" + [ + { + "appHostPath": "./src/MyApp.AppHost/MyApp.AppHost.csproj", + "appHostPid": 12345, + "cliPid": 12340, + "dashboardUrl": "https://localhost:17244/login?t=abc123" + } + ] + ``` + +## See also + +- [aspire run](/reference/cli/commands/aspire-run/) +- [aspire stop](/reference/cli/commands/aspire-stop/) diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire-stop.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire-stop.mdx new file mode 100644 index 000000000..d0dd33841 --- /dev/null +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire-stop.mdx @@ -0,0 +1,60 @@ +--- +title: aspire stop command +description: Learn about the aspire stop command which stops a running Aspire AppHost process. +--- + +import Include from '@components/Include.astro'; + +## Name + +`aspire stop` - Stop a running Aspire AppHost. + +## Synopsis + +```bash title="Aspire CLI" +aspire stop [options] +``` + +## Description + +The `aspire stop` command stops a running Aspire AppHost process. The CLI scans for running AppHosts and terminates the selected instance along with all its child processes. + +When executed without the `--project` option, the command: + +1. Scans for all running AppHost processes. +2. If multiple AppHosts are running within the current directory scope, prompts you to select which one to stop. +3. If only one AppHost is running in scope, stops it directly. +4. If no in-scope AppHosts are found but out-of-scope AppHosts exist, displays all running AppHosts for selection. + +The command sends a stop signal to the CLI process that started the AppHost, which ensures a clean shutdown of all resources including the dashboard and any containers or processes that were started. + +## Options + +The following options are available: + +- **`--project `** + + The path to the Aspire AppHost project file. When specified, the command stops only the AppHost running from that project file without prompting for selection. + +- + +- + +## Examples + +- Stop the AppHost running in the current directory scope: + + ```bash title="Aspire CLI" + aspire stop + ``` + +- Stop a specific AppHost project: + + ```bash title="Aspire CLI" + aspire stop --project './src/MyApp.AppHost/MyApp.AppHost.csproj' + ``` + +## See also + +- [aspire run](/reference/cli/commands/aspire-run/) +- [aspire ps](/reference/cli/commands/aspire-ps/) diff --git a/src/frontend/src/content/docs/reference/cli/commands/aspire.mdx b/src/frontend/src/content/docs/reference/cli/commands/aspire.mdx index 0ee19f161..fec9ab1fe 100644 --- a/src/frontend/src/content/docs/reference/cli/commands/aspire.mdx +++ b/src/frontend/src/content/docs/reference/cli/commands/aspire.mdx @@ -51,8 +51,10 @@ The following commands are available: | [`aspire init`](../aspire-init/) | Stable | Initialize Aspire support in an existing solution or create a single-file AppHost. | | [`aspire mcp`](../aspire-mcp/) | Stable | Manage MCP (Model Context Protocol) server. | | [`aspire new`](../aspire-new/) | Stable | Create an Aspire sample project from a template. | +| [`aspire ps`](../aspire-ps/) | Stable | List running Aspire AppHost processes. | | [`aspire publish`](../aspire-publish/) | Preview | Generates deployment artifacts for an Aspire apphost project. | | [`aspire run`](../aspire-run/) | Stable | Run an Aspire apphost for local development. | +| [`aspire stop`](../aspire-stop/) | Stable | Stop a running Aspire AppHost. | | [`aspire update`](../aspire-update/) | Preview | Update Aspire packages and templates in your project. | ## Examples diff --git a/src/frontend/src/content/docs/reference/cli/configuration.mdx b/src/frontend/src/content/docs/reference/cli/configuration.mdx index 1d9ace4d3..6edf3bbcf 100644 --- a/src/frontend/src/content/docs/reference/cli/configuration.mdx +++ b/src/frontend/src/content/docs/reference/cli/configuration.mdx @@ -92,17 +92,17 @@ The following is an example with all supported settings: { "appHostPath": "../AspireShop/AspireShop.AppHost/AspireShop.AppHost.csproj", "features": { - "deployCommandEnabled": "true", - "doCommandEnabled": "true", + "defaultWatchEnabled": "true", + "dotnetSdkInstallationEnabled": "true", "execCommandEnabled": "true", "minimumSdkCheckEnabled": "true", "orphanDetectionWithTimestampEnabled": "true", "packageSearchDiskCachingEnabled": "true", - "publishCommandEnabled": "true", + "polyglotSupportEnabled": "true", + "runningInstanceDetectionEnabled": "true", + "showAllTemplates": "true", "showDeprecatedPackages": "true", - "singleFileAppHostEnabled": "true", "stagingChannelEnabled": "true", - "updateCommandEnabled": "true", "updateNotificationsEnabled": "true" } } diff --git a/src/frontend/src/content/docs/reference/cli/includes/config-settings-table.md b/src/frontend/src/content/docs/reference/cli/includes/config-settings-table.md index a86823276..a14d4391a 100644 --- a/src/frontend/src/content/docs/reference/cli/includes/config-settings-table.md +++ b/src/frontend/src/content/docs/reference/cli/includes/config-settings-table.md @@ -11,6 +11,7 @@ title: Config Settings Table | `features.minimumSdkCheckEnabled` | Enforce minimum SDK version. | | `features.orphanDetectionWithTimestampEnabled` | Use timestamp-based orphan detection. | | `features.packageSearchDiskCachingEnabled` | Cache package search results on disk. | +| `features.polyglotSupportEnabled` | Enable polyglot (non-.NET) project support. | | `features.runningInstanceDetectionEnabled` | Enable detection of already running instances. | | `features.showAllTemplates` | Show all templates including experimental ones. | | `features.showDeprecatedPackages` | Show deprecated packages. | diff --git a/src/frontend/src/data/integration-docs.json b/src/frontend/src/data/integration-docs.json index 29ab9d207..85dc517a5 100644 --- a/src/frontend/src/data/integration-docs.json +++ b/src/frontend/src/data/integration-docs.json @@ -43,6 +43,10 @@ "match": "Aspire.Azure.Storage.Blobs", "href": "/integrations/cloud/azure/azure-storage-blobs/" }, + { + "match": "Aspire.Azure.Storage.Files.DataLake", + "href": "/integrations/cloud/azure/azure-storage-datalake/" + }, { "match": "Aspire.Azure.Storage.Queues", "href": "/integrations/cloud/azure/azure-storage-queues/" @@ -55,10 +59,18 @@ "match": "Aspire.Elastic.Clients.Elasticsearch", "href": "/integrations/databases/elasticsearch/elasticsearch-get-started/" }, + { + "match": "Aspire.Hosting", + "href": "/architecture/overview/" + }, { "match": "Aspire.Hosting.AWS", "href": "https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/aspire-integrations.html" }, + { + "match": "Aspire.Hosting.Azure", + "href": "/integrations/cloud/azure/overview/" + }, { "match": "Aspire.Hosting.Azure.AIFoundry", "href": "/integrations/cloud/azure/azure-ai-foundry/" @@ -73,7 +85,7 @@ }, { "match": "Aspire.Hosting.Azure.ApplicationInsights", - "href": "/integrations/cloud/azure/overview/" + "href": "/integrations/cloud/azure/azure-application-insights/" }, { "match": "Aspire.Hosting.Azure.AppService", @@ -105,11 +117,11 @@ }, { "match": "Aspire.Hosting.Azure.Kusto", - "href": "/integrations/cloud/azure/overview/" + "href": "/integrations/cloud/azure/azure-data-explorer/" }, { "match": "Aspire.Hosting.Azure.OperationalInsights", - "href": "/integrations/cloud/azure/overview/" + "href": "/integrations/cloud/azure/azure-log-analytics/" }, { "match": "Aspire.Hosting.Azure.PostgreSQL", From 7a8724d95ed5f96412d05d5156e9e6de1d4fb094 Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Sun, 25 Jan 2026 12:19:43 -0600 Subject: [PATCH 04/90] Remove run_git_commands.ps1 script and associated documentation for CLI commands and diagnostics --- run_git_commands.ps1 | 58 -------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 run_git_commands.ps1 diff --git a/run_git_commands.ps1 b/run_git_commands.ps1 deleted file mode 100644 index 4dc0e4a77..000000000 --- a/run_git_commands.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -# Change to the repository directory -Set-Location "E:\GitHub\aspire.dev" - -# 1. Stage all changes -Write-Host "===== Step 1: git add -A =====" -git add -A -if ($LASTEXITCODE -eq 0) { - Write-Host "Successfully staged all changes" -} else { - Write-Host "Error staging changes (exit code: $LASTEXITCODE)" -} - -# 2. Check status -Write-Host "`n===== Step 2: git status =====" -git status - -# 3. Commit with the provided message -Write-Host "`n===== Step 3: git commit =====" -$commitMessage = @" -Documentation coverage audit: CLI commands, diagnostics, and config updates - -## New CLI command documentation -- aspire-stop.mdx: Stop a running Aspire AppHost -- aspire-ps.mdx: List running Aspire AppHost processes - -## New diagnostic pages (experimental APIs) -- ASPIREINTERACTION001: Interaction service experimental API -- ASPIREDOTNETTOOL: .NET tool resource experimental API -- ASPIREPOSTGRES001: PostgreSQL MCP experimental API -- ASPIREEXTENSION001: Extension debugging experimental API -- ASPIRECONTAINERSHELLEXECUTION001: Container shell execution experimental API - -## Configuration updates -- Added missing polyglotSupportEnabled feature flag to config-settings-table.md -- Fixed stale feature flags in example settings.json - -## Navigation updates -- Updated sidebar with aspire ps and aspire stop commands -- Updated aspire.mdx commands table with new commands - -Note: aspire doctor command is covered by PR #270 -"@ - -git commit -m $commitMessage -if ($LASTEXITCODE -eq 0) { - Write-Host "Successfully committed changes" -} else { - Write-Host "Error during commit (exit code: $LASTEXITCODE)" -} - -# 4. Push changes -Write-Host "`n===== Step 4: git push =====" -git push -if ($LASTEXITCODE -eq 0) { - Write-Host "Successfully pushed changes" -} else { - Write-Host "Error during push (exit code: $LASTEXITCODE)" -} From 6e86dc5bbef0006cae405417f334c1435f9c8632 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 26 Jan 2026 09:22:04 -0600 Subject: [PATCH 05/90] Remove obsolete aspire-doctor documentation as it is covered by PR #270 --- .netlify/state.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .netlify/state.json diff --git a/.netlify/state.json b/.netlify/state.json new file mode 100644 index 000000000..a3049dc51 --- /dev/null +++ b/.netlify/state.json @@ -0,0 +1,3 @@ +{ + "siteId": "d69ecd1a-0e08-45b4-8572-0046462d26bc" +} \ No newline at end of file From 3565ce77c31e6a7301697a7bccf5e0fc4ac4ad17 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 26 Jan 2026 09:30:51 -0600 Subject: [PATCH 06/90] Update VSCode settings for Prettier and enhance troubleshooting documentation --- .vscode/settings.json | 16 ++-- .../content/docs/get-started/first-app.mdx | 6 +- .../docs/get-started/troubleshooting.mdx | 74 +++++++++++-------- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2114e504a..119c31a4b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,27 +1,27 @@ { "prettier.documentSelectors": ["**/*.astro"], "[astro]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[markdown]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[mdx]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascriptreact]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[yaml]": { - "editor.defaultFormatter": "prettier.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode" } } diff --git a/src/frontend/src/content/docs/get-started/first-app.mdx b/src/frontend/src/content/docs/get-started/first-app.mdx index 6c74716ba..87b1d61ed 100644 --- a/src/frontend/src/content/docs/get-started/first-app.mdx +++ b/src/frontend/src/content/docs/get-started/first-app.mdx @@ -375,6 +375,8 @@ import pythonDashboardDark from '@assets/get-started/python-aspire-dashboard-dar You might be eager to deploy this app next—and we'll show you how Aspire handles that—but you're probably also wondering: "How do I _test_ all this?" Great question! Aspire doesn't just orchestrate locally and deploy, it also helps you test service and resource integrations too. Ready to dive in? [Write your first test](/testing/write-your-first-test/) 💜 + -Having trouble? Check out our [Troubleshooting guide](/get-started/troubleshooting/) for solutions to common problems. - \ No newline at end of file +## See also + +- Having trouble? Check out our [Troubleshooting guide](/get-started/troubleshooting/) for solutions to common problems. \ No newline at end of file diff --git a/src/frontend/src/content/docs/get-started/troubleshooting.mdx b/src/frontend/src/content/docs/get-started/troubleshooting.mdx index db0a11273..dab4e27cf 100644 --- a/src/frontend/src/content/docs/get-started/troubleshooting.mdx +++ b/src/frontend/src/content/docs/get-started/troubleshooting.mdx @@ -3,10 +3,10 @@ title: Aspire troubleshooting guide description: Solutions to common problems when getting started with .NET Aspire, including Docker issues, port conflicts, and service discovery errors. --- -import { Aside } from '@astrojs/starlight/components'; +import { Aside, Steps } from '@astrojs/starlight/components'; import { Kbd } from 'starlight-kbd/components'; import LearnMore from '@components/LearnMore.astro'; -import Expand from '@components/Expand.astro'; +import OsAwareTabs from '@components/OsAwareTabs.astro'; Having issues getting started with Aspire? This page covers solutions to the most common problems developers encounter. @@ -17,45 +17,57 @@ Having issues getting started with Aspire? This page covers solutions to the mos **Solution**: Start Docker Desktop (or Podman) before running `aspire run`. Check your system tray to confirm Docker is running with a green status indicator. ## Port already in use **Symptoms**: Error message like "Address already in use" or "Port 5000 is already bound." -**Solution**: +**Solution**: + - Stop any other applications using the same ports - If you have another Aspire app running, stop it first with - +### How to find processes using a port -**Windows:** -```powershell -netstat -ano | findstr :5000 -# Find the PID in the last column, then: -taskkill /PID /F -``` + +
+ + ```powershell + netstat -ano | findstr :5000 + # Find the PID in the last column, then: + taskkill /PID /F + ``` -**macOS/Linux:** -```bash -lsof -i :5000 -# Then kill the process: -kill -9 -``` +
+
- + ```bash + lsof -i :5000 + # Then kill the process: + kill -9 + ``` +
+ +
## Service shows "Unhealthy" in dashboard **Symptoms**: A service has a red status or shows "Unhealthy" in the Aspire dashboard. **Solution**: + + + 1. Click on the service name in the dashboard to view its logs 2. Look for startup errors or exceptions 3. Verify the health check endpoint exists (e.g., `/health` returns a 200 OK) 4. Check that all dependencies started successfully + + ## "Connection refused" errors **Symptoms**: Your frontend can't connect to the API, showing connection refused errors. @@ -74,7 +86,7 @@ builder.AddProject("frontend") **Solution**: Verify you're using `WithReference()` to connect resources. - +### Example: Connecting a database to your service In your AppHost: @@ -92,18 +104,17 @@ var connectionString = builder.Configuration.GetConnectionString("db"); The connection string is injected as an environment variable named `ConnectionStrings__db`. - - ## Container image pull failures **Symptoms**: Error messages about failing to pull container images, or "image not found" errors. **Solution**: + - Check your internet connection - Verify Docker Hub or your container registry is accessible - If using a corporate network, check proxy settings in Docker Desktop - +### How to manually pull and verify an image ```bash # Try pulling the image manually @@ -113,25 +124,28 @@ docker pull redis:latest # Settings > Resources > Proxies > Manual proxy configuration ``` - - ## Dashboard not loading **Symptoms**: The Aspire dashboard URL doesn't respond or shows a blank page. **Solution**: + + + 1. Check the console output for the correct dashboard URL (it may use a different port) 2. Ensure no browser extensions are blocking the page 3. Try a different browser or incognito mode 4. Check if antivirus or firewall is blocking the connection + + ## Service discovery not working **Symptoms**: Services can't find each other by name (e.g., `http://apiservice` doesn't resolve). **Solution**: Ensure you're using the service name exactly as defined in your AppHost. - +### Example: Correct service discovery setup ```csharp title="AppHost.cs" // In AppHost @@ -144,17 +158,13 @@ var client = new HttpClient { BaseAddress = new Uri("http://apiservice") }; ``` Also verify: + - Both services have `AddServiceDefaults()` called - The consuming service has `.WithReference(api)` in the AppHost - - - -For a deeper understanding of how service discovery works in Aspire, see [Service discovery](/fundamentals/service-discovery/). - - -For more help, see [Aspire Support](/support/) or check the [GitHub Discussions](https://github.com/dotnet/aspire/discussions). + For a deeper understanding of how service discovery works in Aspire, see + [Service discovery](/fundamentals/service-discovery/). ## See also From b31cec2126211e6540658b8567e01189abd40f16 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 26 Jan 2026 09:41:34 -0600 Subject: [PATCH 07/90] Add new diagnostic topic for container shell execution --- src/frontend/config/sidebar/diagnostic.topics.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/frontend/config/sidebar/diagnostic.topics.ts b/src/frontend/config/sidebar/diagnostic.topics.ts index 318fa2f5c..87bb8c9b3 100644 --- a/src/frontend/config/sidebar/diagnostic.topics.ts +++ b/src/frontend/config/sidebar/diagnostic.topics.ts @@ -47,6 +47,10 @@ export const diagnosticTopics: StarlightSidebarTopicsUserConfig = { label: 'ASPIRECONTAINERRUNTIME001', link: '/diagnostics/aspirecontainerruntime001', }, + { + label: 'ASPIRECONTAINERSHELLEXECUTION001', + link: '/diagnostics/aspirecontainershellexecution001', + }, { label: 'ASPIREDOCKERFILEBUILDER001', link: '/diagnostics/aspiredockerfilebuilder001', From 380d1fe4b6b7a3a53fbccac334ccf66b21d4ca90 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 26 Jan 2026 09:53:27 -0600 Subject: [PATCH 08/90] Add new diagnostic topics for .NET tool and extensions --- src/frontend/config/sidebar/diagnostic.topics.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/frontend/config/sidebar/diagnostic.topics.ts b/src/frontend/config/sidebar/diagnostic.topics.ts index 87bb8c9b3..96070a331 100644 --- a/src/frontend/config/sidebar/diagnostic.topics.ts +++ b/src/frontend/config/sidebar/diagnostic.topics.ts @@ -55,6 +55,14 @@ export const diagnosticTopics: StarlightSidebarTopicsUserConfig = { label: 'ASPIREDOCKERFILEBUILDER001', link: '/diagnostics/aspiredockerfilebuilder001', }, + { + label: 'ASPIREDOTNETTOOL', + link: '/diagnostics/aspiredotnettool', + }, + { + label: 'ASPIREEXTENSION001', + link: '/diagnostics/aspireextension001', + }, { label: 'ASPIREFILESYSTEM001', link: '/diagnostics/aspirefilesystem001', @@ -71,6 +79,10 @@ export const diagnosticTopics: StarlightSidebarTopicsUserConfig = { label: 'ASPIREPROBES001', link: '/diagnostics/aspireprobes001', }, + { + label: 'ASPIREPOSTGRES001', + link: '/diagnostics/aspirepostgres001', + }, { label: 'ASPIREUSERSECRETS001', link: '/diagnostics/aspireusersecrets001', From 5f264885a4cd460ef7dc448424ab05def0496382 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:17:04 -0600 Subject: [PATCH 09/90] Update ASPIRE008 diagnostic page for GenerateAssemblyInfo requirement (#288) * Initial plan * Update ASPIRE008 diagnostic page for GenerateAssemblyInfo requirement Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> * Update project file samples to modern 13.x format Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --- .../content/docs/diagnostics/aspire008.mdx | 50 +++++++++---------- .../src/content/docs/diagnostics/overview.mdx | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/frontend/src/content/docs/diagnostics/aspire008.mdx b/src/frontend/src/content/docs/diagnostics/aspire008.mdx index c6bc1f457..5c97a333b 100644 --- a/src/frontend/src/content/docs/diagnostics/aspire008.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspire008.mdx @@ -1,65 +1,63 @@ --- title: Compiler Error ASPIRE008 -description: Learn more about compiler Error ASPIRE008. The installed Aspire workload is deprecated. It is recommended to migrate to the new format. +description: Learn more about compiler Error ASPIRE008. The project requires GenerateAssemblyInfo to be enabled for the AppHost to function correctly. --- -import { Aside, Badge, Steps } from '@astrojs/starlight/components'; +import { Aside, Badge } from '@astrojs/starlight/components'; - + -> The Aspire workload that this project depends on is now deprecated. +> '[ProjectName]' project requires GenerateAssemblyInfo to be enabled. The Aspire AppHost relies on assembly metadata attributes to locate required dependencies. -This error appears when a project uses a version of Aspire that relies on the SDK workload, which is now deprecated. The error guides you to migrate your project to a supported version of Aspire that uses the SDK approach instead of the workload. +This error appears when an Aspire AppHost project has `GenerateAssemblyInfo` set to `false`. The Aspire AppHost relies on `AssemblyMetadataAttribute` to embed DCP (Developer Control Plane) and Dashboard paths during compilation. When `GenerateAssemblyInfo` is disabled, these attributes aren't generated, causing runtime failures about missing orchestration dependencies. ## Example -The following AppHost project file uses the deprecated Aspire workload: +The following AppHost project file has `GenerateAssemblyInfo` disabled, which causes `ASPIRE008`: ```xml title="C# project file" - + Exe - net8.0 + net10.0 enable enable - true 98048c9c-bf28-46ba-a98e-63767ee5e3a8 + false - - - - ``` -For more information on the Aspire SDK, see [Aspire SDK](https://learn.microsoft.com/dotnet/aspire/fundamentals/dotnet-aspire-sdk/). - ## To correct this error -Follow the migration guide at [https://aka.ms/aspire/update-to-sdk](https://aka.ms/aspire/update-to-sdk) to upgrade your project to a supported version of Aspire that uses the SDK approach. - -The migration typically involves: +Remove the `false` line from your project file, or set it to `true`: - +```xml title="C# project file" + -1. Updating your AppHost project file to use the `Aspire.AppHost.Sdk`. -1. Removing references to the deprecated workload. -1. Updating package references to supported versions. + + Exe + net10.0 + enable + enable + 98048c9c-bf28-46ba-a98e-63767ee5e3a8 + - + +``` ## Suppress the error -If you need to temporarily suppress this error, add the following property to your project file: +If you must temporarily suppress this error, add the following property to your project file: ```xml title="C# project file" - true + $(NoWarn);ASPIRE008 ``` diff --git a/src/frontend/src/content/docs/diagnostics/overview.mdx b/src/frontend/src/content/docs/diagnostics/overview.mdx index 834421f71..7be284bfa 100644 --- a/src/frontend/src/content/docs/diagnostics/overview.mdx +++ b/src/frontend/src/content/docs/diagnostics/overview.mdx @@ -15,7 +15,7 @@ The following table lists the possible MSBuild and analyzer warnings and errors | [ASPIRE004](/diagnostics/aspire004/) | Warning | 'Project' is referenced by an Aspire Host project, but it is not an executable. | | [ASPIRE006](/diagnostics/aspire006/) | (Experimental) Error | Application model items must have valid names. | | [ASPIRE007](/diagnostics/aspire007/) | Error | 'Project' requires a reference to "Aspire.AppHost.Sdk" with version "9.0.0" or greater to work correctly. | -| [ASPIRE008](/diagnostics/aspire008/) | Error | The Aspire workload that this project depends on is now deprecated. | +| [ASPIRE008](/diagnostics/aspire008/) | Error | 'Project' requires GenerateAssemblyInfo to be enabled for the AppHost to function correctly. | | [ASPIREACADOMAINS001](/diagnostics/aspireacadomains001/) | (Experimental) Error | `ConfigureCustomDomain` is for evaluation purposes only and is subject to change or removal in future updates. | | [ASPIREAZURE001](/diagnostics/aspireazure001/) | (Experimental) Error | Publishers are for evaluation purposes only and are subject to change or removal in future updates. | | [ASPIREAZURE002](/diagnostics/aspireazure002/) | (Experimental) Error | Azure Container App Jobs are for evaluation purposes only and are subject to change or removal in future updates. | From e91a02d6328b22a855d8dee46274ef3346ff1f21 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 26 Jan 2026 12:35:17 -0600 Subject: [PATCH 10/90] Add note about search functionality during local development in contributor guide --- src/frontend/config/sidebar/diagnostic.topics.ts | 1 + src/frontend/src/content/docs/community/contributor-guide.mdx | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/frontend/config/sidebar/diagnostic.topics.ts b/src/frontend/config/sidebar/diagnostic.topics.ts index 96070a331..c82c87393 100644 --- a/src/frontend/config/sidebar/diagnostic.topics.ts +++ b/src/frontend/config/sidebar/diagnostic.topics.ts @@ -26,6 +26,7 @@ export const diagnosticTopics: StarlightSidebarTopicsUserConfig = { { label: 'Overview', link: '/diagnostics/overview' }, { label: 'Warnings', + collapsed: true, items: [ { label: 'ASPIRE001', link: '/diagnostics/aspire001' }, { label: 'ASPIRE002', link: '/diagnostics/aspire002' }, diff --git a/src/frontend/src/content/docs/community/contributor-guide.mdx b/src/frontend/src/content/docs/community/contributor-guide.mdx index 12b814651..29b866d03 100644 --- a/src/frontend/src/content/docs/community/contributor-guide.mdx +++ b/src/frontend/src/content/docs/community/contributor-guide.mdx @@ -118,6 +118,10 @@ Before you begin, ensure you have the following installed: Open your browser to `http://localhost:4321` (or the port shown in your terminal) + :::tip + During local development, the site search functionality is disabled. This is normal behavior as the search index is built during the production build process. To test search functionality, run a production build locally using `pnpm build` and then preview it with `pnpm preview`. + ::: + ### Known formatting limitations From ab6afc51ab517f35c2c968e8ba503321b6311178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Mon, 26 Jan 2026 13:13:33 -0800 Subject: [PATCH 11/90] =?UTF-8?q?Add=20polyglot=20AppHost=20documentation?= =?UTF-8?q?=20for=20TypeScript,=20Python,=20Go,=20Rust,=20=E2=80=A6=20(#27?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add polyglot AppHost documentation for TypeScript, Python, Go, Rust, and Java * feat: enhance PivotSelector component with marginTop prop for better layout control (#302) docs: update Polyglot AppHost documentation with new features and usage examples docs: add link to Polyglot AppHost in resource model documentation docs: include Polyglot AppHost reference in get-started guide for broader language support style: import utility classes for padding and margin in site CSS style: create utils.css for reusable padding and margin utility classes * fix: format project structure in polyglot AppHost documentation for clarity --------- Co-authored-by: David Pine --- src/frontend/config/sidebar/docs.topics.ts | 4 + .../src/components/PivotSelector.astro | 8 +- .../docs/app-host/polyglot-apphost.mdx | 835 ++++++++++++++++++ .../docs/architecture/resource-model.mdx | 4 + .../src/content/docs/get-started/app-host.mdx | 5 + src/frontend/src/styles/site.css | 3 +- src/frontend/src/styles/utils.css | 507 +++++++++++ 7 files changed, 1362 insertions(+), 4 deletions(-) create mode 100644 src/frontend/src/content/docs/app-host/polyglot-apphost.mdx create mode 100644 src/frontend/src/styles/utils.css diff --git a/src/frontend/config/sidebar/docs.topics.ts b/src/frontend/config/sidebar/docs.topics.ts index d8cd34189..42c0b8d76 100644 --- a/src/frontend/config/sidebar/docs.topics.ts +++ b/src/frontend/config/sidebar/docs.topics.ts @@ -794,6 +794,10 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { ja: '構成', }, }, + { + label: 'Polyglot AppHost', + slug: 'app-host/polyglot-apphost', + }, { label: 'Certificate configuration', slug: 'app-host/certificate-configuration', diff --git a/src/frontend/src/components/PivotSelector.astro b/src/frontend/src/components/PivotSelector.astro index ce4836b68..e0af92c4d 100644 --- a/src/frontend/src/components/PivotSelector.astro +++ b/src/frontend/src/components/PivotSelector.astro @@ -9,9 +9,10 @@ type Props = { options: Option[]; key: string; title?: string; + marginTop?: number | null; }; -const { options, key, title } = Astro.props; +const { options, key, title, marginTop } = Astro.props; ---
@@ -58,14 +59,14 @@ const { options, key, title } = Astro.props;
- diff --git a/src/frontend/src/components/FooterSocials.astro b/src/frontend/src/components/FooterSocials.astro new file mode 100644 index 000000000..383a5041e --- /dev/null +++ b/src/frontend/src/components/FooterSocials.astro @@ -0,0 +1,94 @@ +--- +import { Icon } from '@astrojs/starlight/components'; +import { socialConfig, type SocialLink } from '../../config/socials.config'; +--- + + + + diff --git a/src/frontend/src/components/TestimonialCarousel.astro b/src/frontend/src/components/TestimonialCarousel.astro index 5b1514b9d..e2901cf83 100644 --- a/src/frontend/src/components/TestimonialCarousel.astro +++ b/src/frontend/src/components/TestimonialCarousel.astro @@ -97,7 +97,7 @@ function getColorForIndex(index: number): { bg: string; fg: string } { diff --git a/src/frontend/src/components/starlight/Footer.astro b/src/frontend/src/components/starlight/Footer.astro index 60cbab2de..44c18e35a 100644 --- a/src/frontend/src/components/starlight/Footer.astro +++ b/src/frontend/src/components/starlight/Footer.astro @@ -3,6 +3,8 @@ import DefaultFooter from '@astrojs/starlight/components/Footer.astro'; import FooterLinks from '@components/FooterLinks.astro'; import FooterLegal from '@components/FooterLegal.astro'; import FooterResources from '@components/FooterResources.astro'; +import FooterPreferences from '@components/FooterPreferences.astro'; +import FooterSocials from '@components/FooterSocials.astro'; import AspireMap from '@components/AspireMap.astro'; import Expand from '@components/Expand.astro'; @@ -15,6 +17,9 @@ const showMap = isHomepage(Astro); + {floatingIcons.length > 0 && ( + + )} @@ -220,6 +247,50 @@ const accentColor = accentVarMap[accent]; pointer-events: none; } + /* Floating topic icons */ + .topic-hero-floating-icons { + position: absolute; + inset: 0; + pointer-events: none; + overflow: hidden; + } + + .floating-icon { + position: absolute; + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--topic-accent); + opacity: 0.1; + animation: float-icon 7s ease-in-out infinite; + filter: blur(0.5px); + } + + .floating-icon :global(svg) { + width: 1em; + height: 1em; + } + + @keyframes float-icon { + 0%, + 100% { + transform: translateY(0) rotate(0deg) scale(1); + opacity: 0.1; + } + 25% { + transform: translateY(-6px) rotate(3deg) scale(1.05); + opacity: 0.15; + } + 50% { + transform: translateY(-12px) rotate(-2deg) scale(1.1); + opacity: 0.18; + } + 75% { + transform: translateY(-5px) rotate(1deg) scale(1.02); + opacity: 0.12; + } + } + @media (prefers-reduced-motion: reduce) { .topic-btn { transition: none; @@ -227,6 +298,10 @@ const accentColor = accentVarMap[accent]; .topic-btn-primary:hover { transform: none; } + .floating-icon { + animation: none; + opacity: 0.08; + } } @media (max-width: 640px) { diff --git a/src/frontend/src/content/docs/community/index.mdx b/src/frontend/src/content/docs/community/index.mdx index 1deb0c058..69f40119a 100644 --- a/src/frontend/src/content/docs/community/index.mdx +++ b/src/frontend/src/content/docs/community/index.mdx @@ -23,6 +23,7 @@ import CTABanner from '@components/CTABanner.astro'; highlight="in the open." subtitle="Join thousands of developers building, contributing, and learning together across social channels, live streams, and open-source repos." accent="magenta" + floatingIcons={['github', 'comment-alt', 'pencil', 'discord', 'add-document']} primaryCta={{ label: 'Start contributing', href: '/community/contributor-guide/' }} secondaryCta={{ label: 'Watch videos', href: '/community/videos/' }} /> diff --git a/src/frontend/src/content/docs/dashboard/index.mdx b/src/frontend/src/content/docs/dashboard/index.mdx index f3c7af649..f4dff9792 100644 --- a/src/frontend/src/content/docs/dashboard/index.mdx +++ b/src/frontend/src/content/docs/dashboard/index.mdx @@ -28,6 +28,7 @@ import mcpDialogImage from '@assets/dashboard/mcp-server/mcp-dialog.png'; highlight="Fully observable." subtitle="Real-time visibility into every resource, log, trace, and metric in your distributed app — right from your dev environment." accent="blue" + floatingIcons={['magnifier', 'document', 'setting', 'open-book', 'random']} primaryCta={{ label: 'Explore features', href: '/dashboard/explore/' }} secondaryCta={{ label: 'Read dashboard overview', diff --git a/src/frontend/src/content/docs/deployment/index.mdx b/src/frontend/src/content/docs/deployment/index.mdx index bae2f4247..2ad815e02 100644 --- a/src/frontend/src/content/docs/deployment/index.mdx +++ b/src/frontend/src/content/docs/deployment/index.mdx @@ -20,6 +20,7 @@ import CTABanner from '@components/CTABanner.astro'; highlight="seamlessly." subtitle="Generate deployment artifacts with aspire publish, then deploy anywhere — Azure, Docker, Kubernetes, or your own pipeline." accent="orange" + floatingIcons={['cloud-download', 'seti:docker', 'laptop', 'seti:config', 'setting']} primaryCta={{ label: 'Deploy your first app', href: '/get-started/deploy-first-app/', diff --git a/src/frontend/src/content/docs/integrations/index.mdx b/src/frontend/src/content/docs/integrations/index.mdx index 73da2c38a..19693f79d 100644 --- a/src/frontend/src/content/docs/integrations/index.mdx +++ b/src/frontend/src/content/docs/integrations/index.mdx @@ -19,6 +19,7 @@ import CTABanner from '@components/CTABanner.astro'; highlight="Ship faster." subtitle="Snap databases, caches, messaging, and cloud services into your AppHost with one line — health checks, telemetry, and resiliency included." accent="green" + floatingIcons={['seti:db', 'seti:config', 'random', 'cloud-download', 'setting']} primaryCta={{ label: 'Browse integrations', href: '/integrations/gallery/' }} secondaryCta={{ label: 'What are integrations?', href: '/integrations/overview/' }} /> diff --git a/src/frontend/src/content/docs/reference/overview.mdx b/src/frontend/src/content/docs/reference/overview.mdx index 758a08dfe..dc5d76984 100644 --- a/src/frontend/src/content/docs/reference/overview.mdx +++ b/src/frontend/src/content/docs/reference/overview.mdx @@ -20,6 +20,7 @@ import CTABanner from '@components/CTABanner.astro'; highlight="at your fingertips." subtitle="From the interactive CLI to the full API surface — everything you need to build, run, and deploy Aspire applications is documented here." accent="cyan" + floatingIcons={['seti:powershell', 'document', 'open-book', 'magnifier', 'laptop']} primaryCta={{ label: 'CLI overview', href: '/reference/cli/overview/' }} secondaryCta={{ label: 'Browse APIs', href: '/reference/api/browser/' }} /> From 44e24271919c37d4321450d337b67efafc80825e Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 10:56:36 -0600 Subject: [PATCH 72/90] feat: implement dynamic positioning for floating icons in HeroSection and TopicHero components --- src/frontend/src/components/HeroSection.astro | 68 +++++++++++++++--- src/frontend/src/components/TopicHero.astro | 72 ++++++++++++++++--- .../src/content/docs/integrations/index.mdx | 2 +- 3 files changed, 123 insertions(+), 19 deletions(-) diff --git a/src/frontend/src/components/HeroSection.astro b/src/frontend/src/components/HeroSection.astro index b7b3c2fc5..1604c095a 100644 --- a/src/frontend/src/components/HeroSection.astro +++ b/src/frontend/src/components/HeroSection.astro @@ -13,14 +13,60 @@ interface Props { const { title, highlight, subtitle, primaryCta, secondaryCta, logo } = Astro.props; +// Simple hash from the title string to seed per-page randomness +function hashStr(s: string): number { + let h = 0; + for (let i = 0; i < s.length; i++) { + h = ((h << 5) - h + s.charCodeAt(i)) | 0; + } + return Math.abs(h); +} + +function seededRandom(seed: number) { + let s = seed | 0; + return () => { + s = (s + 0x6d2b79f5) | 0; + let t = Math.imul(s ^ (s >>> 15), 1 | s); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + // Floating icons relevant to docs: distributed apps, config, building, deploying -const floatingIcons = [ - { icon: 'open-book', top: '12%', right: '10%', size: '1.35rem', delay: '0s', duration: '7.2s' }, - { icon: 'puzzle', top: '65%', right: '24%', size: '1.15rem', delay: '1.6s', duration: '8.8s' }, - { icon: 'rocket', top: '22%', right: '48%', size: '1.4rem', delay: '3.8s', duration: '6.6s' }, - { icon: 'setting', top: '76%', right: '7%', size: '1.05rem', delay: '4.4s', duration: '7.8s' }, - { icon: 'seti:config', top: '40%', right: '4%', size: '1.1rem', delay: '2.4s', duration: '9.2s' }, -] as const; +const iconNames = ['open-book', 'puzzle', 'rocket', 'setting', 'seti:config'] as const; +const rand = seededRandom(hashStr(title)); +const MIN_DIST = 22; +const placed: { top: number; right: number }[] = []; + +function generateSpacedPosition() { + for (let attempt = 0; attempt < 50; attempt++) { + const top = Math.round(5 + rand() * 80); + const right = Math.round(3 + rand() * 55); + const tooClose = placed.some( + (p) => Math.hypot(p.top - top, p.right - right) < MIN_DIST + ); + if (!tooClose) { + placed.push({ top, right }); + return { top, right }; + } + } + const top = Math.round(5 + rand() * 80); + const right = Math.round(3 + rand() * 55); + placed.push({ top, right }); + return { top, right }; +} + +const floatingIcons = iconNames.map((icon) => { + const pos = generateSpacedPosition(); + return { + icon, + top: `${pos.top}%`, + right: `${pos.right}%`, + size: `${(1.5 + rand() * 0.825).toFixed(2)}rem`, + delay: `${(rand() * 6).toFixed(1)}s`, + duration: `${(8.5 + rand() * 6).toFixed(1)}s`, + }; +}); ---
@@ -224,7 +270,10 @@ const floatingIcons = [ /* Floating topic icons */ .hero-floating-icons { position: absolute; - inset: 0; + top: 0; + bottom: 0; + right: 0; + width: 40%; pointer-events: none; overflow: hidden; } @@ -285,5 +334,8 @@ const floatingIcons = [ .hero-content { padding-left: 0.5rem; } + .hero-floating-icons { + width: 35%; + } } diff --git a/src/frontend/src/components/TopicHero.astro b/src/frontend/src/components/TopicHero.astro index 90b30e2a4..c964968b1 100644 --- a/src/frontend/src/components/TopicHero.astro +++ b/src/frontend/src/components/TopicHero.astro @@ -37,15 +37,61 @@ const accentVarMap: Record = { const accentColor = accentVarMap[accent]; -// Predefined positions and animation configs for floating icons -const floatingConfigs = [ - { top: '10%', right: '8%', size: '1.35rem', delay: '0s', duration: '7.2s' }, - { top: '62%', right: '28%', size: '1.15rem', delay: '1.4s', duration: '9s' }, - { top: '25%', right: '45%', size: '1.5rem', delay: '3.6s', duration: '6.8s' }, - { top: '78%', right: '6%', size: '1.05rem', delay: '4.2s', duration: '8.4s' }, - { top: '14%', right: '58%', size: '1.25rem', delay: '2.5s', duration: '7.6s' }, - { top: '44%', right: '3%', size: '1.1rem', delay: '5.2s', duration: '6.2s' }, -]; +// Simple hash from the title string to seed per-page randomness +function hashStr(s: string): number { + let h = 0; + for (let i = 0; i < s.length; i++) { + h = ((h << 5) - h + s.charCodeAt(i)) | 0; + } + return Math.abs(h); +} + +// Seeded pseudo-random number generator (mulberry32) +function seededRandom(seed: number) { + let s = seed | 0; + return () => { + s = (s + 0x6d2b79f5) | 0; + let t = Math.imul(s ^ (s >>> 15), 1 | s); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +// Generate unique positions per page based on the title +// Enforces minimum distance between icons so they don't cluster +const rand = seededRandom(hashStr(title)); +const MIN_DIST = 22; // minimum % distance between any two icons +const placed: { top: number; right: number }[] = []; + +function generateSpacedPosition() { + for (let attempt = 0; attempt < 50; attempt++) { + const top = Math.round(5 + rand() * 80); + const right = Math.round(3 + rand() * 85); + const tooClose = placed.some( + (p) => Math.hypot(p.top - top, p.right - right) < MIN_DIST + ); + if (!tooClose) { + placed.push({ top, right }); + return { top, right }; + } + } + // fallback: use as-is if we can't find a spaced position + const top = Math.round(5 + rand() * 80); + const right = Math.round(3 + rand() * 85); + placed.push({ top, right }); + return { top, right }; +} + +const floatingConfigs = floatingIcons.map(() => { + const pos = generateSpacedPosition(); + return { + top: `${pos.top}%`, + right: `${pos.right}%`, + size: `${(1.5 + rand() * 0.825).toFixed(2)}rem`, + delay: `${(rand() * 6).toFixed(1)}s`, + duration: `${(8.5 + rand() * 6).toFixed(1)}s`, + }; +}); ---
@@ -250,7 +296,10 @@ const floatingConfigs = [ /* Floating topic icons */ .topic-hero-floating-icons { position: absolute; - inset: 0; + top: 0; + bottom: 0; + right: 0; + width: 40%; pointer-events: none; overflow: hidden; } @@ -311,5 +360,8 @@ const floatingConfigs = [ .topic-hero-content { padding-left: 0.5rem; } + .topic-hero-floating-icons { + width: 35%; + } } diff --git a/src/frontend/src/content/docs/integrations/index.mdx b/src/frontend/src/content/docs/integrations/index.mdx index 19693f79d..c413646da 100644 --- a/src/frontend/src/content/docs/integrations/index.mdx +++ b/src/frontend/src/content/docs/integrations/index.mdx @@ -19,7 +19,7 @@ import CTABanner from '@components/CTABanner.astro'; highlight="Ship faster." subtitle="Snap databases, caches, messaging, and cloud services into your AppHost with one line — health checks, telemetry, and resiliency included." accent="green" - floatingIcons={['seti:db', 'seti:config', 'random', 'cloud-download', 'setting']} + floatingIcons={['seti:db', 'approve-check-circle', 'random', 'cloud-download', 'setting']} primaryCta={{ label: 'Browse integrations', href: '/integrations/gallery/' }} secondaryCta={{ label: 'What are integrations?', href: '/integrations/overview/' }} /> From 794419563bc3060e8284dcb59eb42cf388a63391 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 11:42:27 -0600 Subject: [PATCH 73/90] feat: disable telemetry during CI/CD documentation testing and update Aspire 13.2 release notes --- .github/skills/doc-writer/SKILL.md | 2 + .github/workflows/frontend-build.yml | 1 + .github/workflows/integration.yml | 1 + .../content/docs/whats-new/aspire-13-2.mdx | 191 ++++++++---------- 4 files changed, 93 insertions(+), 102 deletions(-) diff --git a/.github/skills/doc-writer/SKILL.md b/.github/skills/doc-writer/SKILL.md index da78f36c9..9decc4220 100644 --- a/.github/skills/doc-writer/SKILL.md +++ b/.github/skills/doc-writer/SKILL.md @@ -51,6 +51,8 @@ src/frontend/src/content/docs/ ## Astro and MDX Conventions +When calling `pnpm dev` or `aspire run` to test documentation in the context of CI/CD, or from an LLM, call `astro telemetry disable` to disable telemetry. + ### Frontmatter Every documentation file requires frontmatter: diff --git a/.github/workflows/frontend-build.yml b/.github/workflows/frontend-build.yml index 597f0f6d1..0e1d24144 100644 --- a/.github/workflows/frontend-build.yml +++ b/.github/workflows/frontend-build.yml @@ -40,6 +40,7 @@ jobs: - name: Build frontend env: MODE: production + ASTRO_TELEMETRY_DISABLED: 1 run: pnpm build:production - name: Check dist diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 619798e55..c2a2eab62 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -41,6 +41,7 @@ jobs: - name: Build frontend env: MODE: production + ASTRO_TELEMETRY_DISABLED: 1 run: pnpm build:production - name: Build AppHost 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 376d5c651..db36c672f 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 @@ -9,9 +9,9 @@ tableOfContents: maxHeadingLevel: 2 --- +import { Aside, Steps } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; import OsAwareTabs from '@components/OsAwareTabs.astro'; -import { Aside } from '@astrojs/starlight/components'; import ThemeImage from '@components/ThemeImage.astro'; import resourcesDark from '@assets/whats-new/aspire-13.2/resources-dark.png'; @@ -23,6 +23,59 @@ import structuredLogsLight from '@assets/whats-new/aspire-13.2/structured-logs-l Aspire 13.2 brings significant improvements to the developer experience with enhanced CLI capabilities, dashboard improvements, new AI agent integrations, and better polyglot support. This release focuses on making local development more streamlined while maintaining the robust cloud-native foundation that Aspire is known for. +## 🆙 Upgrade to Aspire 13.2 + + + + + +For general purpose upgrade guidance, see [Upgrade Aspire](/whats-new/upgrade-aspire/). + +The easiest way to upgrade to Aspire 13.2 is using the `aspire update` command: + + + + + +1. Update your Aspire project using the [`aspire update` command](/reference/cli/commands/aspire-update/): + + ```bash title="Aspire CLI — Update all Aspire packages" + aspire update + ``` + +2. Update the Aspire CLI itself: + + ```bash title="Aspire CLI — Update the CLI" + aspire update --self + ``` + + + +Or install the CLI from scratch: + + + + ```bash title="Aspire CLI — Install Aspire CLI" + curl -sSL https://aspire.dev/install.sh | bash + ``` + + + ```powershell title="Aspire CLI — Install Aspire CLI" + irm https://aspire.dev/install.ps1 | iex + ``` + + + + + For more details on installing the Aspire CLI, see [Install the CLI](/get-started/install-cli/). + + ## 🛠️ Aspire CLI enhancements ### Detached mode and process management @@ -101,13 +154,19 @@ aspire agent init This enables AI agents to interact with your Aspire applications through a standardized protocol, opening up new possibilities for AI-assisted development workflows. -Command reference: [`aspire agent`](/reference/cli/commands/aspire-agent/). +Command reference: [`aspire agent`](/reference/cli/commands/aspire-agent/), [`aspire agent mcp`](/reference/cli/commands/aspire-agent-mcp/), and [`aspire agent init`](/reference/cli/commands/aspire-agent-init/). + +To learn how to configure AI agents with Aspire, see [Configure the MCP server](/get-started/configure-mcp/). -### Browse documentation from the CLI (`aspire docs`) +### Documentation commands from the CLI (`aspire docs`) The new `aspire docs` command brings the official [aspire.dev](https://aspire.dev) documentation directly into your terminal. Built on the same [MCP (Model Context Protocol) documentation tools](https://davidpine.dev/posts/aspire-docs-mcp-tools/) that power the Aspire agent integration, these commands let you browse, search, and read documentation without leaving your development workflow. +:::note +These commands are intended for use by AI agents, it's not really expected that developers will use these directly. +::: + ```bash title="Aspire CLI — Browse and search documentation" # List all available documentation pages aspire docs list @@ -125,7 +184,7 @@ aspire docs get redis-integration --section "Add Redis resource" Each command supports `--format Json` for machine-readable output, making them useful for scripting and automation. The `aspire docs search` command also accepts a `--limit` option to control the number of results returned. -Command reference: [`aspire docs`](/reference/cli/commands/aspire-docs/). +Command reference: [`aspire docs`](/reference/cli/commands/aspire-docs/), [`aspire docs list`](/reference/cli/commands/aspire-docs-list/), [`aspire docs search`](/reference/cli/commands/aspire-docs-search/), and [`aspire docs get`](/reference/cli/commands/aspire-docs-get/). ### Improved configuration management @@ -146,66 +205,19 @@ aspire config set Configuration is now clearly separated into local and global settings, with feature flags displayed in an organized manner. -Command reference: [`aspire config`](/reference/cli/commands/aspire-config/). +Command reference: [`aspire config`](/reference/cli/commands/aspire-config/), [`aspire config list`](/reference/cli/commands/aspire-config-list/), [`aspire config get`](/reference/cli/commands/aspire-config-get/), and [`aspire config set`](/reference/cli/commands/aspire-config-set/). ### CLI telemetry Aspire CLI now includes optional telemetry to help improve the developer experience. Telemetry data is version-consistent with the dashboard, providing a unified approach to usage analytics. All telemetry follows standard privacy practices and can be controlled through configuration. -## 🆙 Upgrade to Aspire 13.2 - - - - - -For comprehensive upgrade guidance, see [Upgrade Aspire](/whats-new/upgrade-aspire/). - -The easiest way to upgrade to Aspire 13.2 is using the `aspire update` command: - - - -1. Update your Aspire project using the [`aspire update` command](/reference/cli/commands/aspire-update/): - - ```bash title="Aspire CLI — Update all Aspire packages" - aspire update - ``` - -2. Update the Aspire CLI itself: - - ```bash title="Aspire CLI — Update the CLI" - aspire update --self - ``` - -Or install the CLI from scratch: - - - - ```bash title="Aspire CLI — Install Aspire CLI" - curl -sSL https://aspire.dev/install.sh | bash - ``` - - - ```powershell title="Aspire CLI — Install Aspire CLI" - irm https://aspire.dev/install.ps1 | iex - ``` - - + +For more information, see [Microsoft-collected CLI telemetry](/reference/cli/microsoft-collected-cli-telemetry/). + ## 📊 Dashboard improvements - - ### Enhanced data export The dashboard now provides comprehensive export capabilities: @@ -217,12 +229,6 @@ The dashboard now provides comprehensive export capabilities: ### Improved telemetry visualization - - - **Download JSON for Traces, Spans, and Logs**: Each telemetry view now includes options to export data - **OTLP/JSON Support**: The dashboard now supports OTLP over JSON in addition to gRPC - **Environment Variable Highlighting**: Environment variables are now highlighted for better visibility @@ -234,12 +240,6 @@ The resource graph layout has been significantly improved with adaptive force-di ### Persistent UI state - - The dashboard now remembers: - Collapsed/expanded state of resources - Filter preferences across sessions @@ -252,6 +252,10 @@ The dashboard now remembers: - Copy button visibility improvements even when values are hidden - Toggle button for secret visibility in input dialogs + +For more details, see [Explore the Aspire dashboard](/dashboard/explore/) and [Dashboard configuration](/dashboard/configuration/). + + ## 🧩 App model and resource improvements ### Enhanced debugging experience @@ -271,9 +275,13 @@ This makes it easier to inspect your Aspire application state during debugging s - Improved `ResourceNotificationService.WaitFor` exception messages with more detailed information - `BeforeResourceStartedEvent` now only fires when actually starting a resource (breaking change) + +For more details on eventing, see [AppHost eventing APIs](/app-host/eventing/). + + ### Docker and container enhancements -- **`WithBun()` Support for Vite Apps**: Use Bun as an alternative to npm for Vite applications +- **`WithBun()` Support for Vite Apps**: Use Bun as an alternative to npm for Vite applications — see the [Bun integration](/integrations/frameworks/bun-apps/) docs - **`WithYarn` Fixes**: Improved reliability when using Yarn with `AddViteApp` - **'Never' Pull Policy**: Exposed image pull policy option for scenarios requiring local images - **PullPolicy for Docker Compose**: Added `PullPolicy` property to Docker Compose Service class @@ -293,19 +301,27 @@ The `Aspire.Azure.AI.Inference` integration now includes: - `EmbeddingClient` for accessing Azure AI embedding models - `EmbeddingGenerator` for generating embeddings + +For more details, see [Azure AI Inference integration](/integrations/cloud/azure/azure-ai-inference/). + + ### Azure App Service enhancements - Deployment slot support with new extension methods - Sticky slot app settings fixes - Configuration naming improvements + +For more details, see [Azure App Service integration](/integrations/cloud/azure/azure-app-service/). + + ### Database integrations - **MongoDB**: Connection string options now correctly prepend forward slash - **MongoDB Entity Framework Core**: New client integration `Aspire.MongoDB.EntityFrameworkCore` - **Oracle EF Core**: Multi-targeting support added - **SQL Server**: New `Aspire.Hosting.SqlServer` exports -- **Azure Data Lake Storage**: Initial integration for data lake scenarios +- **Azure Data Lake Storage**: Initial integration for data lake scenarios — see [Azure Data Lake Storage](/integrations/cloud/azure/azure-storage-datalake/) ### Emulator updates @@ -329,6 +345,10 @@ Aspire 13.2 continues to expand polyglot capabilities with improved TypeScript s - TypeScript AppHost testing infrastructure - Polyglot AppHost refactoring for better extensibility + +For more details, see [Polyglot AppHost](/app-host/polyglot-apphost/). + + ### Code generation - Go, Java, and Rust code generation test projects added @@ -367,39 +387,6 @@ This release includes numerous bug fixes across all areas: - Improved search highlight contrast in CLI interactive prompts - Fixed tooltip for view options button in resource details panel -## 🎯 Getting started - -To update to Aspire 13.2: - -```bash title="Aspire CLI — Update to Aspire 13.2" -# Update the Aspire CLI -aspire update --self - -# Update integrations in your project -aspire update -``` - -Or install the CLI from scratch: - - - - ```bash title="Aspire CLI — Install Aspire CLI" - curl -sSL https://aspire.dev/install.sh | bash - ``` - - - ```powershell title="Aspire CLI — Install Aspire CLI" - irm https://aspire.dev/install.ps1 | iex - ``` - - - -For more information, visit [aspire.dev](https://aspire.dev). - ---- - -*This document covers the key changes in Aspire 13.2. For a complete list of changes, see the [GitHub milestone](https://github.com/dotnet/aspire/milestone/25).* - ## ⚠️ Breaking changes From 6b907e4f76d2670d7bd31ce2b5f2ad088c1c093e Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 15:27:40 -0600 Subject: [PATCH 74/90] feat: update mcp configuration, add playwright-cli support, and enhance documentation --- .github/skills/playwright-cli/SKILL.md | 273 +++++++++++++++++++++++++ .playwright/cli.config.json | 8 + .vscode/mcp.json | 12 +- src/frontend/package.json | 3 +- src/frontend/pnpm-lock.yaml | 44 ++++ 5 files changed, 329 insertions(+), 11 deletions(-) create mode 100644 .github/skills/playwright-cli/SKILL.md create mode 100644 .playwright/cli.config.json diff --git a/.github/skills/playwright-cli/SKILL.md b/.github/skills/playwright-cli/SKILL.md new file mode 100644 index 000000000..5a9bcc901 --- /dev/null +++ b/.github/skills/playwright-cli/SKILL.md @@ -0,0 +1,273 @@ +--- +name: playwright-cli +description: Automates browser interactions for web testing, form filling, screenshots, and data extraction. Use when the user needs to navigate websites, interact with web pages, fill forms, take screenshots, test web applications, or extract information from web pages. +--- + +# Browser Automation with playwright-cli + +This skills relies on the `playwright-cli` tool, which provides a command-line interface for automating browser interactions using Playwright. Verify that this tool is installed and accessible in the system PATH before using this skill. + +```bash +playwright-cli --help +``` + +## Quick start + +```bash +# open new browser +playwright-cli open +# navigate to a page +playwright-cli goto https://playwright.dev +# interact with the page using refs from the snapshot +playwright-cli click e15 +playwright-cli type "page.click" +playwright-cli press Enter +# take a screenshot (rarely used, as snapshot is more common) +playwright-cli screenshot +# close the browser +playwright-cli close +``` + +## Commands + +### Core + +```bash +playwright-cli open +# open and navigate right away +playwright-cli open https://example.com/ +playwright-cli goto https://playwright.dev +playwright-cli type "search query" +playwright-cli click e3 +playwright-cli dblclick e7 +playwright-cli fill e5 "user@example.com" +playwright-cli drag e2 e8 +playwright-cli hover e4 +playwright-cli select e9 "option-value" +playwright-cli upload ./document.pdf +playwright-cli check e12 +playwright-cli uncheck e12 +playwright-cli snapshot +playwright-cli snapshot --filename=after-click.yaml +playwright-cli eval "document.title" +playwright-cli eval "el => el.textContent" e5 +playwright-cli dialog-accept +playwright-cli dialog-accept "confirmation text" +playwright-cli dialog-dismiss +playwright-cli resize 1920 1080 +playwright-cli close +``` + +### Navigation + +```bash +playwright-cli go-back +playwright-cli go-forward +playwright-cli reload +``` + +### Keyboard + +```bash +playwright-cli press Enter +playwright-cli press ArrowDown +playwright-cli keydown Shift +playwright-cli keyup Shift +``` + +### Mouse + +```bash +playwright-cli mousemove 150 300 +playwright-cli mousedown +playwright-cli mousedown right +playwright-cli mouseup +playwright-cli mouseup right +playwright-cli mousewheel 0 100 +``` + +### Save as + +```bash +playwright-cli screenshot +playwright-cli screenshot e5 +playwright-cli screenshot --filename=page.png +playwright-cli pdf --filename=page.pdf +``` + +### Tabs + +```bash +playwright-cli tab-list +playwright-cli tab-new +playwright-cli tab-new https://example.com/page +playwright-cli tab-close +playwright-cli tab-close 2 +playwright-cli tab-select 0 +``` + +### Storage + +```bash +playwright-cli state-save +playwright-cli state-save auth.json +playwright-cli state-load auth.json + +# Cookies +playwright-cli cookie-list +playwright-cli cookie-list --domain=example.com +playwright-cli cookie-get session_id +playwright-cli cookie-set session_id abc123 +playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure +playwright-cli cookie-delete session_id +playwright-cli cookie-clear + +# LocalStorage +playwright-cli localstorage-list +playwright-cli localstorage-get theme +playwright-cli localstorage-set theme dark +playwright-cli localstorage-delete theme +playwright-cli localstorage-clear + +# SessionStorage +playwright-cli sessionstorage-list +playwright-cli sessionstorage-get step +playwright-cli sessionstorage-set step 3 +playwright-cli sessionstorage-delete step +playwright-cli sessionstorage-clear +``` + +### Network + +```bash +playwright-cli route "**/*.jpg" --status=404 +playwright-cli route "https://api.example.com/**" --body='{"mock": true}' +playwright-cli route-list +playwright-cli unroute "**/*.jpg" +playwright-cli unroute +``` + +### DevTools + +```bash +playwright-cli console +playwright-cli console warning +playwright-cli network +playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])" +playwright-cli tracing-start +playwright-cli tracing-stop +playwright-cli video-start +playwright-cli video-stop video.webm +``` + +## Open parameters +```bash +# Use specific browser when creating session +playwright-cli open --browser=chrome +playwright-cli open --browser=firefox +playwright-cli open --browser=webkit +playwright-cli open --browser=msedge +# Connect to browser via extension +playwright-cli open --extension + +# Use persistent profile (by default profile is in-memory) +playwright-cli open --persistent +# Use persistent profile with custom directory +playwright-cli open --profile=/path/to/profile + +# Start with config file +playwright-cli open --config=my-config.json + +# Close the browser +playwright-cli close +# Delete user data for the default session +playwright-cli delete-data +``` + +## Snapshots + +After each command, playwright-cli provides a snapshot of the current browser state. + +```bash +> playwright-cli goto https://example.com +### Page +- Page URL: https://example.com/ +- Page Title: Example Domain +### Snapshot +[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml) +``` + +You can also take a snapshot on demand using `playwright-cli snapshot` command. + +If `--filename` is not provided, a new snapshot file is created with a timestamp. Default to automatic file naming, use `--filename=` when artifact is a part of the workflow result. + +## Browser Sessions + +```bash +# create new browser session named "mysession" with persistent profile +playwright-cli -s=mysession open example.com --persistent +# same with manually specified profile directory (use when requested explicitly) +playwright-cli -s=mysession open example.com --profile=/path/to/profile +playwright-cli -s=mysession click e6 +playwright-cli -s=mysession close # stop a named browser +playwright-cli -s=mysession delete-data # delete user data for persistent session + +playwright-cli list +# Close all browsers +playwright-cli close-all +# Forcefully kill all browser processes +playwright-cli kill-all +``` + +## Local installation + +In some cases user might want to install playwright-cli locally. If running globally available `playwright-cli` binary fails, use `npx playwright-cli` to run the commands. For example: + +```bash +npx playwright-cli open https://example.com +npx playwright-cli click e1 +``` + +## Example: Form submission + +```bash +playwright-cli open https://example.com/form +playwright-cli snapshot + +playwright-cli fill e1 "user@example.com" +playwright-cli fill e2 "password123" +playwright-cli click e3 +playwright-cli snapshot +playwright-cli close +``` + +## Example: Multi-tab workflow + +```bash +playwright-cli open https://example.com +playwright-cli tab-new https://example.com/other +playwright-cli tab-list +playwright-cli tab-select 0 +playwright-cli snapshot +playwright-cli close +``` + +## Example: Debugging with DevTools + +```bash +playwright-cli open https://example.com +playwright-cli click e4 +playwright-cli fill e7 "test" +playwright-cli console +playwright-cli network +playwright-cli close +``` + +```bash +playwright-cli open https://example.com +playwright-cli tracing-start +playwright-cli click e4 +playwright-cli fill e7 "test" +playwright-cli tracing-stop +playwright-cli close +``` \ No newline at end of file diff --git a/.playwright/cli.config.json b/.playwright/cli.config.json new file mode 100644 index 000000000..b93a2cab0 --- /dev/null +++ b/.playwright/cli.config.json @@ -0,0 +1,8 @@ +{ + "browser": { + "browserName": "chromium", + "launchOptions": { + "channel": "msedge" + } + } +} \ No newline at end of file diff --git a/.vscode/mcp.json b/.vscode/mcp.json index 17d6ad584..7be43f582 100644 --- a/.vscode/mcp.json +++ b/.vscode/mcp.json @@ -4,16 +4,8 @@ "type": "stdio", "command": "aspire", "args": [ - "mcp", - "start" - ] - }, - "playwright": { - "type": "stdio", - "command": "npx", - "args": [ - "-y", - "@playwright/mcp@latest" + "agent", + "mcp" ] } } diff --git a/src/frontend/package.json b/src/frontend/package.json index b11c730d9..c485f59f9 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -77,7 +77,8 @@ "node-fetch": "^3.3.2", "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", - "typescript-eslint": "^8.54.0" + "typescript-eslint": "^8.54.0", + "@playwright/cli": "^0.1.1" }, "pnpm": { "overrides": { diff --git a/src/frontend/pnpm-lock.yaml b/src/frontend/pnpm-lock.yaml index 81858056a..d71a2f073 100644 --- a/src/frontend/pnpm-lock.yaml +++ b/src/frontend/pnpm-lock.yaml @@ -115,6 +115,9 @@ importers: '@eslint/js': specifier: ^9.39.2 version: 9.39.2 + '@playwright/cli': + specifier: ^0.1.1 + version: 0.1.1 astro-embed: specifier: ^0.12.0 version: 0.12.0(astro@5.16.15(@types/node@24.10.1)(jiti@1.21.7)(rollup@4.53.3)(typescript@5.9.3)(yaml@2.8.2)) @@ -866,6 +869,11 @@ packages: peerDependencies: parse5: 7.x || 8.x + '@playwright/cli@0.1.1': + resolution: {integrity: sha512-9k11ZfDwAfMVDDIuEVW1Wvs8SoDNXIY1dNQ+9C9/SS8ZmElkcxesu5eoL7vNa96ntibUGaq1TM2qQoqvdl/I9g==} + engines: {node: '>=18'} + hasBin: true + '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} @@ -2062,6 +2070,11 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2598,6 +2611,9 @@ packages: resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==} engines: {node: 20 || >=22} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -2779,6 +2795,16 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + playwright-core@1.59.0-alpha-1771104257000: + resolution: {integrity: sha512-YiXup3pnpQUCBMSIW5zx8CErwRx4K6O5Kojkw2BzJui8MazoMUDU6E3xGsb1kzFviEAE09LFQ+y1a0RhIJQ5SA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.59.0-alpha-1771104257000: + resolution: {integrity: sha512-6SCMMMJaDRsSqiKVLmb2nhtLES7iTYawTWWrQK6UdIGNzXi8lka4sLKRec3L4DnTWwddAvCuRn8035dhNiHzbg==} + engines: {node: '>=18'} + hasBin: true + points-on-curve@0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} @@ -4486,6 +4512,11 @@ snapshots: dependencies: parse5: 8.0.0 + '@playwright/cli@0.1.1': + dependencies: + minimist: 1.2.8 + playwright: 1.59.0-alpha-1771104257000 + '@popperjs/core@2.11.8': {} '@rollup/pluginutils@5.3.0(rollup@4.53.3)': @@ -5887,6 +5918,9 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -6833,6 +6867,8 @@ snapshots: dependencies: brace-expansion: 5.0.2 + minimist@1.2.8: {} + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -7011,6 +7047,14 @@ snapshots: mlly: 1.8.0 pathe: 2.0.3 + playwright-core@1.59.0-alpha-1771104257000: {} + + playwright@1.59.0-alpha-1771104257000: + dependencies: + playwright-core: 1.59.0-alpha-1771104257000 + optionalDependencies: + fsevents: 2.3.2 + points-on-curve@0.2.0: {} points-on-path@0.2.1: From 018748fa9b9077fc2ee7e5a147e983efbf8ba61c Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 15:42:35 -0600 Subject: [PATCH 75/90] feat: add MongoDB integration support with EF Core, including documentation and sidebar updates - closes #419 (work around merge conflicts) --- .../config/sidebar/integrations.topics.ts | 14 + .../efcore/mongodb/mongodb-efcore-client.mdx | 255 ++++++++++++++++++ .../mongodb/mongodb-efcore-get-started.mdx | 105 ++++++++ .../databases/efcore/overview.mdx | 9 +- .../content/docs/whats-new/aspire-13-2.mdx | 2 +- 5 files changed, 383 insertions(+), 2 deletions(-) create mode 100644 src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx create mode 100644 src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index b2e27277c..5a17ad800 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -624,6 +624,20 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { }, ], }, + { + label: 'MongoDB', + collapsed: true, + items: [ + { + label: 'Get started', + slug: 'integrations/databases/efcore/mongodb/mongodb-efcore-get-started', + }, + { + label: 'Client integration (Your app)', + slug: 'integrations/databases/efcore/mongodb/mongodb-efcore-client', + }, + ], + }, { label: 'Oracle', collapsed: true, diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx new file mode 100644 index 000000000..708d2a650 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx @@ -0,0 +1,255 @@ +--- +title: MongoDB Entity Framework Core client integration +description: Learn how to use the MongoDB Entity Framework Core client integration to interact with MongoDB instances. +next: false +--- + +import { Image } from 'astro:assets'; +import InstallDotNetPackage from '@components/InstallDotNetPackage.astro'; +import { Aside } from '@astrojs/starlight/components'; +import mongodbIcon from '@assets/icons/mongodb-icon.png'; + +MongoDB logo + +To get started with the Aspire MongoDB Entity Framework Core (EF Core) client integration, install the [📦 Aspire.MongoDB.EntityFrameworkCore](https://www.nuget.org/packages/Aspire.MongoDB.EntityFrameworkCore) NuGet package in the client-consuming project, that is, the project for the application that uses the MongoDB client. The Aspire MongoDB EF Core client integration registers your desired `DbContext` subclass instances that you can use to interact with MongoDB. + + + +For an introduction to the MongoDB EF Core integration, see [Get started with the MongoDB Entity Framework Core integrations](/integrations/databases/efcore/mongodb/mongodb-efcore-get-started/). + +## 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. + +```csharp title="C# — Program.cs" +builder.AddMongoDbContext( + connectionName: "mydb"); +``` + + + +After adding `MyDbContext` to the builder, you can get the `MyDbContext` instance using dependency injection. For example, to retrieve your data source object from an example service, define it as a constructor parameter and ensure the `ExampleService` class is registered with the dependency injection container: + +```csharp +public class ExampleService(MyDbContext context) +{ + // Use context... +} +``` + +For more information on dependency injection, see [.NET dependency injection](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection). + +### 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: + +1. **Explicit parameter**: Pass `databaseName` as the second parameter to `AddMongoDbContext`. +2. **Configuration**: Set the `DatabaseName` property in the `Aspire:MongoDB:EntityFrameworkCore` configuration section. +3. **Connection string**: If the connection string includes a database name (e.g., `mongodb://server:port/mydb`), it's extracted automatically. + +```csharp title="C# — Explicit database name" +builder.AddMongoDbContext("mongodb", "mydb"); +``` + + + +## 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: + +```csharp title="C# — Program.cs" +builder.Services.AddDbContextPool(options => + options.UseMongoDB( + builder.Configuration.GetConnectionString("mydb")!, + "mydb")); +``` + + + +You have more flexibility when you create the database context in this way, for example: + +- You can reuse existing configuration code for the database context without rewriting it for Aspire. +- You can use Entity Framework Core interceptors to modify database operations. +- You can choose not to use Entity Framework Core context pooling, which may perform better in some circumstances. + +If you use this method, you can enhance the database context with Aspire-style health checks, logging, and telemetry features by calling the `EnrichMongoDbContext` method: + +```csharp title="C# — Program.cs" +builder.EnrichMongoDbContext( + configureSettings: settings => + { + settings.DisableHealthChecks = false; + settings.DisableTracing = false; + }); +``` + +The `settings` parameter is an instance of the `MongoDBEntityFrameworkCoreSettings` class. + +## 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 + +When using a connection string from the `ConnectionStrings` configuration section, you provide the name of the connection string when calling the `AddMongoDbContext` method: + +```csharp title="C# — Program.cs" +builder.AddMongoDbContext("mydb"); +``` + +The connection string is retrieved from the `ConnectionStrings` configuration section: + +```json title="JSON — appsettings.json" +{ + "ConnectionStrings": { + "mydb": "mongodb://server:port/mydb" + } +} +``` + +If your connection string doesn't include a database name, you can provide it as the second parameter: + +```csharp title="C# — Program.cs" +builder.AddMongoDbContext("mongodb", "mydb"); +``` + +The `EnrichMongoDbContext` won't make use of the `ConnectionStrings` configuration section since it expects a `DbContext` to be registered at the point it's called. + +For more information, see the [MongoDB connection string documentation](https://www.mongodb.com/docs/v3.0/reference/connection-string/). + +### 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. + +The following example shows an `appsettings.json` file that configures some of the available options: + +```json title="JSON — appsettings.json" +{ + "Aspire": { + "MongoDB": { + "EntityFrameworkCore": { + "DatabaseName": "mydb", + "DisableHealthChecks": true, + "DisableTracing": false, + "HealthCheckTimeout": 5000 + } + } + } +} +``` + +For the complete MongoDB EF Core client integration JSON schema, see [Aspire.MongoDB.EntityFrameworkCore/ConfigurationSchema.json](https://github.com/dotnet/aspire/blob/main/src/Components/Aspire.MongoDB.EntityFrameworkCore/ConfigurationSchema.json). + +### 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: + +```csharp title="C# — Program.cs" +builder.AddMongoDbContext( + "mydb", + configureSettings: static settings => + settings.DisableHealthChecks = true); +``` + +or + +```csharp title="C# — Program.cs" +builder.EnrichMongoDbContext( + settings => settings.DisableHealthChecks = true); +``` + +### 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: + +```json title="JSON — appsettings.json" +{ + "Aspire": { + "MongoDB": { + "EntityFrameworkCore": { + "ConnectionString": "mongodb://server:port/mydb", + "DatabaseName": "mydb", + "DisableHealthChecks": true, + "AnotherDbContext": { + "ConnectionString": "mongodb://server:port/anotherdb", + "DatabaseName": "anotherdb", + "DisableTracing": false + } + } + } + } +} +``` + +Then calling the `AddMongoDbContext` method with `AnotherDbContext` type parameter would load the settings from `AnotherDbContext` section. + +```csharp title="C# — Program.cs" +builder.AddMongoDbContext("mongodb"); +``` + +## MongoDB Driver integration vs. EF Core integration + +The Aspire MongoDB integration comes in two flavors: + +- **[Aspire.MongoDB.Driver](/integrations/databases/mongodb/mongodb-client/)**: Provides direct access to the MongoDB driver via `IMongoClient`. Use this when you want full control over MongoDB queries, need features not supported by EF Core (such as aggregation pipelines), or prefer the native MongoDB programming model. +- **Aspire.MongoDB.EntityFrameworkCore** (this page): Provides an EF Core `DbContext` backed by MongoDB. Use this when you want to leverage EF Core's familiar patterns—change tracking, LINQ queries, and `DbSet` abstractions—with MongoDB as the data store. + +Both integrations use the same hosting integration ([Aspire.Hosting.MongoDB](/integrations/databases/mongodb/mongodb-host/)) in the AppHost. + +## 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 + +The Aspire MongoDB Entity Framework Core integration uses the following log categories: + +- `Microsoft.EntityFrameworkCore.ChangeTracking` +- `Microsoft.EntityFrameworkCore.Database.Command` +- `Microsoft.EntityFrameworkCore.Database.Connection` +- `Microsoft.EntityFrameworkCore.Database.Transaction` +- `Microsoft.EntityFrameworkCore.Infrastructure` +- `Microsoft.EntityFrameworkCore.Migrations` +- `Microsoft.EntityFrameworkCore.Model` +- `Microsoft.EntityFrameworkCore.Model.Validation` +- `Microsoft.EntityFrameworkCore.Query` +- `Microsoft.EntityFrameworkCore.Update` + +### Tracing + +The Aspire MongoDB EF Core integration will emit the following tracing activities using OpenTelemetry: + +- `MongoDB.Driver.Core.Extensions.DiagnosticSources` + +### Metrics + +The Aspire MongoDB EF Core integration will emit the following metrics using OpenTelemetry: + +- Microsoft.EntityFrameworkCore: + - `ec_Microsoft_EntityFrameworkCore_active_db_contexts` + - `ec_Microsoft_EntityFrameworkCore_total_queries` + - `ec_Microsoft_EntityFrameworkCore_queries_per_second` + - `ec_Microsoft_EntityFrameworkCore_total_save_changes` + - `ec_Microsoft_EntityFrameworkCore_save_changes_per_second` + - `ec_Microsoft_EntityFrameworkCore_compiled_query_cache_hit_rate` + - `ec_Microsoft_Entity_total_execution_strategy_operation_failures` + - `ec_Microsoft_E_execution_strategy_operation_failures_per_second` + - `ec_Microsoft_EntityFramew_total_optimistic_concurrency_failures` + - `ec_Microsoft_EntityF_optimistic_concurrency_failures_per_second` + \ No newline at end of file diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx new file mode 100644 index 000000000..19d8b87f1 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx @@ -0,0 +1,105 @@ +--- +title: Get started with the MongoDB Entity Framework Core integrations +description: Learn how to set up the Aspire MongoDB Hosting and Entity Framework Core Client integrations simply. +prev: false +--- + +import { Image } from 'astro:assets'; +import InstallPackage from '@components/InstallPackage.astro'; +import InstallDotNetPackage from '@components/InstallDotNetPackage.astro'; +import { Aside, CardGrid, LinkCard } from '@astrojs/starlight/components'; +import mongodbIcon from '@assets/icons/mongodb-icon.png'; + +MongoDB logo + +[MongoDB](https://www.mongodb.com/) is a popular, open-source NoSQL document database that offers high performance, scalability, and flexible data modeling. The Aspire MongoDB Entity Framework Core (EF Core) client integration provides a way to connect to existing MongoDB databases, or create new instances from the [`docker.io/library/mongo` container image](https://hub.docker.com/_/mongo). + +In this introduction, you'll see how to install and use the Aspire MongoDB Entity Framework Core integrations in a simple configuration. The same hosting integration is used with both the EF Core and the non-EF Core client integrations. If you already have this knowledge, see [MongoDB Hosting integration](/integrations/databases/mongodb/mongodb-host/) and [MongoDB EF Core client integration](/integrations/databases/efcore/mongodb/mongodb-efcore-client/) for full reference details. + + + +## Set up hosting integration + +To begin, install the Aspire MongoDB Hosting integration in your Aspire AppHost project. This integration allows you to create and manage MongoDB database instances from your Aspire hosting projects: + + + +Next, in the AppHost project, create instances of MongoDB server and database resources, then pass the database to the consuming client projects: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var mongodb = builder.AddMongoDB("mongodb"); +var mydb = mongodb.AddDatabase("mydb"); + +var exampleProject = builder.AddProject("apiservice") + .WaitFor(mydb) + .WithReference(mydb); +``` + + + +## Use the integration in client projects + +Now that the hosting integration is ready, the next step is to install and configure the EF Core client integration in any projects that need to use it. + +### Set up client projects + +In each of these consuming client projects, install the Aspire MongoDB EF Core client integration: + + + +In the `Program.cs` file of your client-consuming project, call the `AddMongoDbContext` extension method on any `IHostApplicationBuilder` to register your `DbContext` subclass for use through the dependency injection container. The method takes a connection name parameter. + +```csharp title="C# — Program.cs" +builder.AddMongoDbContext(connectionName: "mydb"); +``` + + + + + +### Use MongoDB resources in client code + +Now that you've added the `DbContext` to the builder in the consuming project, you can use the MongoDB resource to get and store data. Get the `DbContext` instance using dependency injection. For example, to retrieve your database context object from an example service define it as a constructor parameter and ensure the `ExampleService` class is registered with the dependency injection container: + +```csharp title="C# — ExampleService.cs" +public class ExampleService(MyDbContext context) +{ + // Use context to interact with the database... +} +``` + +Having obtained the database context, you can work with the MongoDB database as you would in any other C# application using EF Core. + +## Next steps + +Now that you have an Aspire app with MongoDB EF Core integrations up and running, you can use the following reference documents to learn how to configure and interact with the MongoDB resources: + + + + + diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/overview.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/overview.mdx index 45bd560f9..285153c2b 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/overview.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/overview.mdx @@ -31,6 +31,7 @@ Developers use O/RMs to work with databases using code objects instead of SQL qu import IconLinkCard from '@components/IconLinkCard.astro'; import azureIcon from '@assets/icons/azure-cosmosdb-icon.png'; +import mongodbIcon from '@assets/icons/mongodb-icon.png'; import mysqlIcon from '@assets/icons/mysqlconnector-icon.png'; import oracleIcon from '@assets/icons/oracle-o-icon.png'; import postgresIcon from '@assets/icons/postgresql-icon.png'; @@ -43,6 +44,12 @@ import sqlIcon from '@assets/icons/sql-icon.png'; icon={azureIcon} href="/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-get-started/" /> + [!IMPORTANT] > In Aspire, EF Core is implemented by client integrations, not hosting integrations. The centralized management of the database in the AppHost doesn't involve EF Core, which runs in consuming microservice projects instead. -- Providing EF Core-aware integrations that make it easy to create contexts in microservice projects. There are EF Core integrations for SQL Server, MySQL, PostgreSQL, Oracle, Cosmos DB, and other popular database systems. +- Providing EF Core-aware integrations that make it easy to create contexts in microservice projects. There are EF Core integrations for SQL Server, MySQL, PostgreSQL, Oracle, MongoDB, Cosmos DB, and other popular database systems. To use EF Core in your microservice, you must: 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 db36c672f..500b7af0a 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 @@ -318,7 +318,7 @@ For more details, see [Azure App Service integration](/integrations/cloud/azure/ ### Database integrations - **MongoDB**: Connection string options now correctly prepend forward slash -- **MongoDB Entity Framework Core**: New client integration `Aspire.MongoDB.EntityFrameworkCore` +- **MongoDB Entity Framework Core**: [New client integration `Aspire.MongoDB.EntityFrameworkCore`](/integrations/databases/efcore/mongodb/mongodb-efcore-get-started/) - **Oracle EF Core**: Multi-targeting support added - **SQL Server**: New `Aspire.Hosting.SqlServer` exports - **Azure Data Lake Storage**: Initial integration for data lake scenarios — see [Azure Data Lake Storage](/integrations/cloud/azure/azure-storage-datalake/) From 8ceecaa0cc2d45636998d083e8945c321b741d9b Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Mon, 23 Feb 2026 20:47:13 -0600 Subject: [PATCH 76/90] Refactor documentation frontmatter to remove unnecessary 'prev' and 'next' fields across multiple integration pages; implement custom route middleware for pagination rules in the documentation sidebar. --- src/frontend/astro.config.mjs | 1 + src/frontend/src/content/docs/404.mdx | 2 + .../src/content/docs/aspireconf/index.mdx | 4 +- .../src/content/docs/community/index.mdx | 6 +- src/frontend/src/content/docs/da/index.mdx | 1 + .../src/content/docs/dashboard/index.mdx | 8 +- ...icrosoft-collected-dashboard-telemetry.mdx | 1 + src/frontend/src/content/docs/de/index.mdx | 1 + .../azure/azure-security-best-practices.mdx | 1 + .../src/content/docs/deployment/index.mdx | 8 +- .../content/docs/diagnostics/aspire004.mdx | 1 - .../content/docs/diagnostics/aspire006.mdx | 1 - .../src/content/docs/diagnostics/overview.mdx | 2 - src/frontend/src/content/docs/docs.mdx | 5 +- src/frontend/src/content/docs/es/index.mdx | 1 + src/frontend/src/content/docs/fr/index.mdx | 1 + .../docs/get-started/deploy-first-app.mdx | 1 - .../docs/get-started/prerequisites.mdx | 1 - src/frontend/src/content/docs/hi/index.mdx | 1 + src/frontend/src/content/docs/id/index.mdx | 1 + src/frontend/src/content/docs/index.mdx | 1 + .../docs/integrations/ai/github-models.mdx | 1 - .../content/docs/integrations/ai/openai.mdx | 1 - .../docs/integrations/caching/garnet.mdx | 1 - .../docs/integrations/caching/valkey.mdx | 1 - .../cloud/azure/ai-compatibility-matrix.mdx | 1 - .../azure-postgresql-client.mdx | 1 - .../azure-postgresql-get-started.mdx | 1 - .../cloud/azure/user-assigned-identity.mdx | 1 - .../docs/integrations/compute/docker.mdx | 1 - .../docs/integrations/compute/kubernetes.mdx | 1 - .../hosting-integrations.mdx | 1 - .../azure-cosmos-db-client.mdx | 1 - .../azure-cosmos-db-get-started.mdx | 1 - .../azure-postgresql-client.mdx | 1 - .../azure-postgresql-get-started.mdx | 1 - .../efcore/azure-sql/azure-sql-client.mdx | 1 - .../azure-sql/azure-sql-get-started.mdx | 1 - .../efcore/mongodb/mongodb-efcore-client.mdx | 1 - .../mongodb/mongodb-efcore-get-started.mdx | 1 - .../databases/efcore/mysql/mysql-client.mdx | 1 - .../efcore/mysql/mysql-get-started.mdx | 1 - .../databases/efcore/oracle/oracle-client.mdx | 1 - .../efcore/oracle/oracle-get-started.mdx | 1 - .../efcore/postgres/postgresql-client.mdx | 1 - .../postgres/postgresql-get-started.mdx | 1 - .../efcore/sql-server/sql-server-client.mdx | 1 - .../sql-server/sql-server-get-started.mdx | 1 - .../elasticsearch/elasticsearch-client.mdx | 1 - .../elasticsearch-get-started.mdx | 1 - .../databases/milvus/milvus-client.mdx | 1 - .../databases/milvus/milvus-get-started.mdx | 1 - .../databases/mongodb/mongodb-client.mdx | 1 - .../databases/mongodb/mongodb-get-started.mdx | 1 - .../databases/mysql/mysql-extensions.mdx | 1 - .../databases/mysql/mysql-get-started.mdx | 1 - .../postgres/postgres-get-started.mdx | 1 - .../postgres/postgresql-extensions.mdx | 1 - .../databases/qdrant/qdrant-client.mdx | 1 - .../databases/qdrant/qdrant-get-started.mdx | 1 - .../sql-server/sql-server-extensions.mdx | 1 - .../sql-server/sql-server-get-started.mdx | 1 - .../databases/sqlite/sqlite-client.mdx | 1 - .../databases/sqlite/sqlite-get-started.mdx | 1 - .../docs/integrations/devtools/dab.mdx | 1 - .../docs/integrations/frameworks/bun-apps.mdx | 1 - .../integrations/frameworks/powershell.mdx | 1 - .../docs/integrations/frameworks/rust.mdx | 1 - .../src/content/docs/integrations/index.mdx | 8 +- .../integrations/messaging/apache-kafka.mdx | 1 - .../docs/integrations/messaging/rabbitmq.mdx | 1 - .../docs/integrations/observability/seq.mdx | 2 - .../content/docs/integrations/overview.mdx | 2 - .../integrations/reverse-proxies/yarp.mdx | 2 - .../docs/integrations/security/keycloak.mdx | 2 - src/frontend/src/content/docs/it/index.mdx | 1 + .../src/content/docs/ja/aspireconf/index.mdx | 1 + src/frontend/src/content/docs/ja/index.mdx | 1 + src/frontend/src/content/docs/ko/index.mdx | 1 + src/frontend/src/content/docs/pt-br/index.mdx | 1 + src/frontend/src/content/docs/pt-pt/index.mdx | 1 + .../content/docs/reference/api/browser.mdx | 2 - .../content/docs/reference/cli/overview.mdx | 1 - .../src/content/docs/reference/overview.mdx | 8 +- src/frontend/src/content/docs/ru/index.mdx | 1 + src/frontend/src/content/docs/support.mdx | 2 + src/frontend/src/content/docs/tr/index.mdx | 1 + src/frontend/src/content/docs/uk/index.mdx | 1 + src/frontend/src/content/docs/zh-cn/index.mdx | 1 + src/frontend/src/route-data-middleware.ts | 138 ++++++++++++++++++ 90 files changed, 196 insertions(+), 79 deletions(-) create mode 100644 src/frontend/src/route-data-middleware.ts diff --git a/src/frontend/astro.config.mjs b/src/frontend/astro.config.mjs index 0be4bbed8..20972a735 100644 --- a/src/frontend/astro.config.mjs +++ b/src/frontend/astro.config.mjs @@ -35,6 +35,7 @@ export default defineConfig({ }), starlight({ title: 'Aspire', + routeMiddleware: ['./src/route-data-middleware'], defaultLocale: 'root', locales, logo: { diff --git a/src/frontend/src/content/docs/404.mdx b/src/frontend/src/content/docs/404.mdx index edc6f05db..f3b41700e 100644 --- a/src/frontend/src/content/docs/404.mdx +++ b/src/frontend/src/content/docs/404.mdx @@ -1,5 +1,7 @@ --- title: '404' +prev: false +next: false template: splash editUrl: false giscus: false diff --git a/src/frontend/src/content/docs/aspireconf/index.mdx b/src/frontend/src/content/docs/aspireconf/index.mdx index 057f297b7..caed189ad 100644 --- a/src/frontend/src/content/docs/aspireconf/index.mdx +++ b/src/frontend/src/content/docs/aspireconf/index.mdx @@ -1,5 +1,7 @@ --- title: Save the date! +prev: false +next: false giscus: false head: - tag: title @@ -7,8 +9,6 @@ head: description: Save the date and tune in for Aspire Conf on March 23! A free livestream event. Discover Aspire and learn how it can transform the way you build and deploy your distributed apps and agents. template: splash editUrl: false -next: false -prev: false hero: tagline: Aspire Conf
March 23, 9:00 PT

Save the date and tune in for our free, livestream event.

Discover Aspire and learn how it can transform the way you build and deploy your distributed apps and agents.

image: diff --git a/src/frontend/src/content/docs/community/index.mdx b/src/frontend/src/content/docs/community/index.mdx index 69f40119a..59cc2c4fa 100644 --- a/src/frontend/src/content/docs/community/index.mdx +++ b/src/frontend/src/content/docs/community/index.mdx @@ -1,11 +1,13 @@ --- title: Aspire Community +prev: + link: /reference/overview/ + label: Reference +next: false description: Connect with the Aspire team and community across social channels, streams, and contribution platforms. banner: content: | 📅 Aspire Conf — March 23. Tune in for our free, livestream event.
Save the date! -prev: false -next: false editUrl: false giscus: false tableOfContents: false diff --git a/src/frontend/src/content/docs/da/index.mdx b/src/frontend/src/content/docs/da/index.mdx index d014068f8..d09a8bbd9 100644 --- a/src/frontend/src/content/docs/da/index.mdx +++ b/src/frontend/src/content/docs/da/index.mdx @@ -7,6 +7,7 @@ head: description: Tilføj Aspire til din stack og strømlin din udviklingsworkflow med kode-først kontrol, modularitet og observability. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/dashboard/index.mdx b/src/frontend/src/content/docs/dashboard/index.mdx index f4dff9792..babd8b642 100644 --- a/src/frontend/src/content/docs/dashboard/index.mdx +++ b/src/frontend/src/content/docs/dashboard/index.mdx @@ -1,9 +1,13 @@ --- title: Aspire Dashboard +prev: + link: /integrations/ + label: Integrations +next: + link: /deployment/ + label: Deployment description: Monitor, debug, and manage your distributed applications with the Aspire Dashboard — real-time telemetry, structured logs, traces, and AI-powered insights. editUrl: false -prev: false -next: false tableOfContents: false pageActions: false --- diff --git a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx index 83012200f..17cc01f66 100644 --- a/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx +++ b/src/frontend/src/content/docs/dashboard/microsoft-collected-dashboard-telemetry.mdx @@ -1,5 +1,6 @@ --- title: Microsoft-collected dashboard telemetry +next: false description: Learn about what telemetry the Aspire dashboard sends and how to opt out. --- diff --git a/src/frontend/src/content/docs/de/index.mdx b/src/frontend/src/content/docs/de/index.mdx index 6690343ac..dd0747d89 100644 --- a/src/frontend/src/content/docs/de/index.mdx +++ b/src/frontend/src/content/docs/de/index.mdx @@ -7,6 +7,7 @@ head: description: Füge Aspire zu deinem Stack hinzu und optimiere deinen Entwicklungs-Workflow mit Code-zentrierter Steuerung, Modularität und Observability. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/deployment/azure/azure-security-best-practices.mdx b/src/frontend/src/content/docs/deployment/azure/azure-security-best-practices.mdx index 03eaab8c2..7d564768b 100644 --- a/src/frontend/src/content/docs/deployment/azure/azure-security-best-practices.mdx +++ b/src/frontend/src/content/docs/deployment/azure/azure-security-best-practices.mdx @@ -1,5 +1,6 @@ --- title: Azure security best practices for Aspire deployments +next: false description: Learn about the default security posture of Aspire deployments to Azure Container Apps and additional steps to enhance security. --- diff --git a/src/frontend/src/content/docs/deployment/index.mdx b/src/frontend/src/content/docs/deployment/index.mdx index 2ad815e02..a6175e163 100644 --- a/src/frontend/src/content/docs/deployment/index.mdx +++ b/src/frontend/src/content/docs/deployment/index.mdx @@ -1,9 +1,13 @@ --- title: Aspire Deployment +prev: + link: /dashboard/ + label: Dashboard +next: + link: /reference/overview/ + label: Reference description: Ship your Aspire applications to Azure, Docker, Kubernetes, and beyond — with confidence and consistency. editUrl: false -prev: false -next: false tableOfContents: false pageActions: false --- diff --git a/src/frontend/src/content/docs/diagnostics/aspire004.mdx b/src/frontend/src/content/docs/diagnostics/aspire004.mdx index 82571fb85..be906f0d2 100644 --- a/src/frontend/src/content/docs/diagnostics/aspire004.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspire004.mdx @@ -1,7 +1,6 @@ --- title: Compiler Warning ASPIRE004 description: Learn more about compiler Warning ASPIRE004. Project is referenced by an Aspire Host project, but it is not an executable. -next: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/diagnostics/aspire006.mdx b/src/frontend/src/content/docs/diagnostics/aspire006.mdx index 542d6828b..f01f659fc 100644 --- a/src/frontend/src/content/docs/diagnostics/aspire006.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspire006.mdx @@ -1,7 +1,6 @@ --- title: Compiler Error ASPIRE006 description: Learn more about compiler Error ASPIRE006. The resource name is invalid. -prev: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/diagnostics/overview.mdx b/src/frontend/src/content/docs/diagnostics/overview.mdx index 7be284bfa..fdba47f24 100644 --- a/src/frontend/src/content/docs/diagnostics/overview.mdx +++ b/src/frontend/src/content/docs/diagnostics/overview.mdx @@ -1,8 +1,6 @@ --- title: Diagnostics overview description: Learn about the diagnostics tools and features available in Aspire. -prev: false -next: false --- The following table lists the possible MSBuild and analyzer warnings and errors you might encounter with Aspire: diff --git a/src/frontend/src/content/docs/docs.mdx b/src/frontend/src/content/docs/docs.mdx index 8c466a84d..b0b6d2fc2 100644 --- a/src/frontend/src/content/docs/docs.mdx +++ b/src/frontend/src/content/docs/docs.mdx @@ -1,11 +1,14 @@ --- title: Welcome to Aspire +prev: false +next: + link: /integrations/ + label: Integrations description: Learn how Aspire simplifies the development, deployment, and debugging of distributed applications. banner: content: | 🆕 Aspire 13.2 is here! TypeScript AppHost, detached mode, new CLI commands, and more. See what's new editUrl: false -next: false tableOfContents: false pageActions: false --- diff --git a/src/frontend/src/content/docs/es/index.mdx b/src/frontend/src/content/docs/es/index.mdx index cb42ff9f1..c51442ccd 100644 --- a/src/frontend/src/content/docs/es/index.mdx +++ b/src/frontend/src/content/docs/es/index.mdx @@ -7,6 +7,7 @@ head: description: Añade Aspire a tu stack y agiliza tu flujo de trabajo de desarrollo con control centrado en el código, modularidad y observabilidad. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/fr/index.mdx b/src/frontend/src/content/docs/fr/index.mdx index a7d324595..8e596a7be 100644 --- a/src/frontend/src/content/docs/fr/index.mdx +++ b/src/frontend/src/content/docs/fr/index.mdx @@ -7,6 +7,7 @@ head: description: Ajoutez Aspire à votre stack et optimisez votre flux de développement avec un contrôle centré sur le code, la modularité et l'observabilité. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/get-started/deploy-first-app.mdx b/src/frontend/src/content/docs/get-started/deploy-first-app.mdx index 752f092c0..76eb6b399 100644 --- a/src/frontend/src/content/docs/get-started/deploy-first-app.mdx +++ b/src/frontend/src/content/docs/get-started/deploy-first-app.mdx @@ -1,7 +1,6 @@ --- title: Deploy your first Aspire app description: Learn how to deploy your first Aspire application to the cloud. -next: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/get-started/prerequisites.mdx b/src/frontend/src/content/docs/get-started/prerequisites.mdx index aead8a281..ce9d4f209 100644 --- a/src/frontend/src/content/docs/get-started/prerequisites.mdx +++ b/src/frontend/src/content/docs/get-started/prerequisites.mdx @@ -6,7 +6,6 @@ tableOfContents: minHeadingLevel: 1 maxHeadingLevel: 4 lastUpdated: true -prev: false --- import { Aside, Icon, Code, CardGrid, Card, LinkCard, LinkButton, Steps } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/hi/index.mdx b/src/frontend/src/content/docs/hi/index.mdx index edc2dcabe..19578dacc 100644 --- a/src/frontend/src/content/docs/hi/index.mdx +++ b/src/frontend/src/content/docs/hi/index.mdx @@ -7,6 +7,7 @@ head: description: अपने स्टैक में Aspire जोड़ें और कोड-प्रथम नियंत्रण, मॉड्युलैरिटी और ऑब्ज़र्वेबिलिटी के साथ विकास वर्कफ़्लो को सुव्यवस्थित करें। template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/id/index.mdx b/src/frontend/src/content/docs/id/index.mdx index 353fba940..56771deae 100644 --- a/src/frontend/src/content/docs/id/index.mdx +++ b/src/frontend/src/content/docs/id/index.mdx @@ -7,6 +7,7 @@ head: description: Tambahkan Aspire ke stack Anda dan sederhanakan alur kerja pengembangan dengan kontrol berbasis kode, modularitas, dan observabilitas. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/index.mdx b/src/frontend/src/content/docs/index.mdx index db0001157..786c8b29f 100644 --- a/src/frontend/src/content/docs/index.mdx +++ b/src/frontend/src/content/docs/index.mdx @@ -7,6 +7,7 @@ head: description: Add Aspire to your stack and streamline your development workflow with code-first control, modularity, and observability. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/integrations/ai/github-models.mdx b/src/frontend/src/content/docs/integrations/ai/github-models.mdx index afb767c6d..2f00e9584 100644 --- a/src/frontend/src/content/docs/integrations/ai/github-models.mdx +++ b/src/frontend/src/content/docs/integrations/ai/github-models.mdx @@ -1,7 +1,6 @@ --- title: GitHub Models integration description: Learn how to integrate Aspire with GitHub Models for AI model access and management. -prev: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/ai/openai.mdx b/src/frontend/src/content/docs/integrations/ai/openai.mdx index f5b6daefa..2db944489 100644 --- a/src/frontend/src/content/docs/integrations/ai/openai.mdx +++ b/src/frontend/src/content/docs/integrations/ai/openai.mdx @@ -1,7 +1,6 @@ --- title: OpenAI integration description: Learn how to use the OpenAI integration, which includes both hosting and client integrations. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/caching/garnet.mdx b/src/frontend/src/content/docs/integrations/caching/garnet.mdx index 126e97d14..acaf95476 100644 --- a/src/frontend/src/content/docs/integrations/caching/garnet.mdx +++ b/src/frontend/src/content/docs/integrations/caching/garnet.mdx @@ -1,7 +1,6 @@ --- title: Garnet integration description: Learn how to use the Garnet integration, a Redis-compatible high-performance cache from Microsoft Research. -prev: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/caching/valkey.mdx b/src/frontend/src/content/docs/integrations/caching/valkey.mdx index ed5c76d54..a622e2c18 100644 --- a/src/frontend/src/content/docs/integrations/caching/valkey.mdx +++ b/src/frontend/src/content/docs/integrations/caching/valkey.mdx @@ -1,7 +1,6 @@ --- title: Valkey integration description: Learn how to use the Valkey integration, a Redis fork that is a high-performance key/value datastore. -next: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/ai-compatibility-matrix.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/ai-compatibility-matrix.mdx index 2a4b2a688..79019e23d 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/ai-compatibility-matrix.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/ai-compatibility-matrix.mdx @@ -1,7 +1,6 @@ --- title: AI integrations compatibility matrix description: View the compatibility matrix for Aspire AI integrations including Azure OpenAI, Azure AI Inference, and IChatClient support. -prev: false --- import { Aside, Card } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-client.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-client.mdx index 8a3315e7a..713ef2e49 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-client.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-client.mdx @@ -1,7 +1,6 @@ --- title: Azure PostgreSQL client integration description: Learn how to use the Aspire Azure PostgreSQL client integration to connect to Azure PostgreSQL databases. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-get-started.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-get-started.mdx index b19b0441e..ccd7645f1 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Azure PostgreSQL integrations description: Learn how to set up the Aspire Azure PostgreSQL Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/user-assigned-identity.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/user-assigned-identity.mdx index d143dcf5e..0d6573264 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/user-assigned-identity.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/user-assigned-identity.mdx @@ -1,7 +1,6 @@ --- title: User-assigned managed identity description: Learn how to configure user-assigned managed identities for Aspire applications in Azure. -next: false --- import { Aside, Steps } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/compute/docker.mdx b/src/frontend/src/content/docs/integrations/compute/docker.mdx index 8d346e10d..7728d0f55 100644 --- a/src/frontend/src/content/docs/integrations/compute/docker.mdx +++ b/src/frontend/src/content/docs/integrations/compute/docker.mdx @@ -1,7 +1,6 @@ --- title: Docker integration description: Learn how to use the Aspire Docker hosting integration to deploy your app with Docker Compose. -prev: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx b/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx index 6a0bc5f37..68e483cbc 100644 --- a/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx +++ b/src/frontend/src/content/docs/integrations/compute/kubernetes.mdx @@ -1,7 +1,6 @@ --- title: Kubernetes integration description: Learn how to add Kubernetes resources to your Aspire application. -next: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/custom-integrations/hosting-integrations.mdx b/src/frontend/src/content/docs/integrations/custom-integrations/hosting-integrations.mdx index 79fb34acd..002229749 100644 --- a/src/frontend/src/content/docs/integrations/custom-integrations/hosting-integrations.mdx +++ b/src/frontend/src/content/docs/integrations/custom-integrations/hosting-integrations.mdx @@ -1,7 +1,6 @@ --- title: Create custom hosting integrations description: Learn how to create a custom Aspire hosting integration for an existing containerized application. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-client.mdx index 7ffe91647..2231f3553 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-client.mdx @@ -1,7 +1,6 @@ --- title: Azure Cosmos DB client integration description: Learn how to use the Azure Cosmos DB client integration to interact with Azure Cosmos DB instances. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-get-started.mdx index a076361f6..f5ab88aa0 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-cosmos-db/azure-cosmos-db-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Azure Cosmos DB Entity Framework Core integrations description: Learn how to set up the Aspire Azure Cosmos DB Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-client.mdx index 2fa1a9569..a4c7886fe 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-client.mdx @@ -1,7 +1,6 @@ --- title: Azure PostgreSQL EF Core Client integration reference description: Learn how to use the Aspire Azure PostgreSQL EF Core Client integration to interact with Azure PostgreSQL databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-get-started.mdx index bc07a5843..9e233546e 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-postgresql/azure-postgresql-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Azure PostgreSQL EF Core integrations description: Learn how to set up the Aspire Azure PostgreSQL Hosting and EF Core Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-client.mdx index c09cca484..e2f1b748a 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-client.mdx @@ -1,7 +1,6 @@ --- title: Azure SQL EF Core Client integration reference description: Learn how to use the Aspire Azure SQL EF Core Client integration to interact with Azure SQL databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-get-started.mdx index 0d4cafa79..aed76d728 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/azure-sql/azure-sql-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Azure SQL EF Core integrations description: Learn how to set up the Aspire Azure SQL Hosting and EF Core Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx index 708d2a650..413e2a0ce 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-client.mdx @@ -1,7 +1,6 @@ --- title: MongoDB Entity Framework Core client integration description: Learn how to use the MongoDB Entity Framework Core client integration to interact with MongoDB instances. -next: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx index 19d8b87f1..2dd9ad839 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mongodb/mongodb-efcore-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the MongoDB Entity Framework Core integrations description: Learn how to set up the Aspire MongoDB Hosting and Entity Framework Core Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-client.mdx index c510d3960..281f3e226 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-client.mdx @@ -1,7 +1,6 @@ --- title: MySQL Pomelo Entity Framework Core Client integration reference description: Learn how to use the Aspire MySQL Pomelo Entity Framework Core Client integration to interact with MySQL databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-get-started.mdx index 8750e33e9..cf90ebdd8 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/mysql/mysql-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the MySQL Pomelo Entity Framework Core integrations description: Learn how to set up the Aspire MySQL Pomelo Entity Framework Core Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-client.mdx index 0030fc8a6..426e43303 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-client.mdx @@ -1,7 +1,6 @@ --- title: Oracle Client integration reference description: Learn how to use the Aspire Oracle Client integration to interact with Oracle databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-get-started.mdx index 89ebbaf89..edd3a8df4 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/oracle/oracle-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Oracle integrations description: Learn how to set up the Aspire Oracle Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-client.mdx index b284c8076..27ad88b38 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-client.mdx @@ -1,7 +1,6 @@ --- title: PostgreSQL client integration description: Learn how to use the PostgreSQL client integration to interact with PostgreSQL instances. -next: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-get-started.mdx index 5b3bf026c..3cbb26fd4 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/postgres/postgresql-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the PostgreSQL Entity Framework Core integrations description: Learn how to set up the Aspire PostgreSQL Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-client.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-client.mdx index e7a4729fa..e12df2008 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-client.mdx @@ -1,7 +1,6 @@ --- title: SQL Server Entity Framework Core client integration description: Learn how to use the Aspire SQL Server EF Core client integration to connect to SQL Server databases. -next: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-get-started.mdx index d90737b58..f1dc1073f 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/sql-server/sql-server-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the SQL Server Entity Framework Core integrations description: Learn how to set up the Aspire SQL Server EF Core Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-client.mdx b/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-client.mdx index 270246485..2586b5d4e 100644 --- a/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-client.mdx @@ -1,7 +1,6 @@ --- title: Elasticsearch client integration description: Learn how to use the Elasticsearch client integration to interact with Elasticsearch instances. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-get-started.mdx index 9171cf95f..2308c62b7 100644 --- a/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/elasticsearch/elasticsearch-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Elasticsearch integrations description: Learn how to set up the Aspire Elasticsearch Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/milvus/milvus-client.mdx b/src/frontend/src/content/docs/integrations/databases/milvus/milvus-client.mdx index 55670b0cb..fa3ea7b9e 100644 --- a/src/frontend/src/content/docs/integrations/databases/milvus/milvus-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/milvus/milvus-client.mdx @@ -1,7 +1,6 @@ --- title: Milvus Client integration reference description: Learn how to use the Aspire Milvus Client integration to interact with Milvus vector databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/milvus/milvus-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/milvus/milvus-get-started.mdx index 12be446c7..b335e1265 100644 --- a/src/frontend/src/content/docs/integrations/databases/milvus/milvus-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/milvus/milvus-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Milvus integrations description: Learn how to set up the Aspire Milvus Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-client.mdx b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-client.mdx index 2be81bc1e..87ac77494 100644 --- a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-client.mdx @@ -1,7 +1,6 @@ --- title: MongoDB Client integration reference description: Learn how to use the Aspire MongoDB Client integration to interact with MongoDB databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-get-started.mdx index 28a500495..957a6c4d8 100644 --- a/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mongodb/mongodb-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the MongoDB integrations description: Learn how to set up the Aspire MongoDB Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-extensions.mdx b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-extensions.mdx index ffc1a5346..d0475f54d 100644 --- a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-extensions.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-extensions.mdx @@ -1,6 +1,5 @@ --- title: MySQL hosting extensions -next: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-get-started.mdx index 5d745642f..26c89c42c 100644 --- a/src/frontend/src/content/docs/integrations/databases/mysql/mysql-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/mysql/mysql-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the MySQL integrations description: Learn how to set up the Aspire MySQL Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/postgres/postgres-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/postgres/postgres-get-started.mdx index 78300b7f5..c586c2d61 100644 --- a/src/frontend/src/content/docs/integrations/databases/postgres/postgres-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/postgres/postgres-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the PostgreSQL integrations description: Learn how to set up the Aspire PostgreSQL Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/postgres/postgresql-extensions.mdx b/src/frontend/src/content/docs/integrations/databases/postgres/postgresql-extensions.mdx index 27fe42ada..b5e6b36ee 100644 --- a/src/frontend/src/content/docs/integrations/databases/postgres/postgresql-extensions.mdx +++ b/src/frontend/src/content/docs/integrations/databases/postgres/postgresql-extensions.mdx @@ -1,6 +1,5 @@ --- title: PostgreSQL hosting extensions -next: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-client.mdx b/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-client.mdx index 26800de7a..625e1f51e 100644 --- a/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-client.mdx @@ -1,7 +1,6 @@ --- title: Qdrant Client integration reference description: Learn how to use the Aspire Qdrant Client integration to interact with Qdrant vector databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-get-started.mdx index c6060f4b5..91215e31c 100644 --- a/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/qdrant/qdrant-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the Qdrant integrations description: Learn how to set up the Aspire Qdrant Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-extensions.mdx b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-extensions.mdx index f30426252..78f9a849b 100644 --- a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-extensions.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-extensions.mdx @@ -1,6 +1,5 @@ --- title: SQL Server hosting extensions -next: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-get-started.mdx index 4a6fd8166..10b2b7d40 100644 --- a/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sql-server/sql-server-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the SQL Server integrations description: Learn how to set up the Aspire SQL Server Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-client.mdx b/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-client.mdx index 5c7dca3ab..df6b9ebf8 100644 --- a/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-client.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-client.mdx @@ -1,7 +1,6 @@ --- title: SQLite Client integration reference description: Learn how to use the Aspire SQLite Client integration to query SQLite databases from your Aspire projects. -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-get-started.mdx b/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-get-started.mdx index 3d1881505..7682c14a1 100644 --- a/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-get-started.mdx +++ b/src/frontend/src/content/docs/integrations/databases/sqlite/sqlite-get-started.mdx @@ -1,7 +1,6 @@ --- title: Get started with the SQLite integrations description: Learn how to set up the Aspire SQLite Hosting and Client integrations simply. -prev: false --- import { Image } from 'astro:assets'; diff --git a/src/frontend/src/content/docs/integrations/devtools/dab.mdx b/src/frontend/src/content/docs/integrations/devtools/dab.mdx index 9aa7f6d90..b293b5ada 100644 --- a/src/frontend/src/content/docs/integrations/devtools/dab.mdx +++ b/src/frontend/src/content/docs/integrations/devtools/dab.mdx @@ -1,7 +1,6 @@ --- title: Data API builder integration description: Learn how to use Data API builder with Aspire. -prev: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/frameworks/bun-apps.mdx b/src/frontend/src/content/docs/integrations/frameworks/bun-apps.mdx index c028e50cd..9b2dfdcad 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/bun-apps.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/bun-apps.mdx @@ -1,7 +1,6 @@ --- title: Bun integration description: Learn about the Aspire hosting integration for Bun apps. -prev: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/frameworks/powershell.mdx b/src/frontend/src/content/docs/integrations/frameworks/powershell.mdx index 0c25b3bbf..1f393bf0f 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/powershell.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/powershell.mdx @@ -1,7 +1,6 @@ --- title: PowerShell integration description: Learn about the Aspire hosting integration for PowerShell scripts. -next: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/frameworks/rust.mdx b/src/frontend/src/content/docs/integrations/frameworks/rust.mdx index af1920a5c..439a9893a 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/rust.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/rust.mdx @@ -1,7 +1,6 @@ --- title: Rust integration description: Learn about the Aspire hosting integration for Rust apps. -next: false --- import { Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/index.mdx b/src/frontend/src/content/docs/integrations/index.mdx index c413646da..9a42198da 100644 --- a/src/frontend/src/content/docs/integrations/index.mdx +++ b/src/frontend/src/content/docs/integrations/index.mdx @@ -1,9 +1,13 @@ --- title: Aspire Integrations +prev: + link: /docs/ + label: Docs +next: + link: /dashboard/ + label: Dashboard description: Connect your distributed applications to 150+ services — databases, caches, messaging, cloud platforms, and more — with a single line in your AppHost. editUrl: false -prev: false -next: false tableOfContents: false pageActions: false --- diff --git a/src/frontend/src/content/docs/integrations/messaging/apache-kafka.mdx b/src/frontend/src/content/docs/integrations/messaging/apache-kafka.mdx index 54701fb2d..f3a827f5e 100644 --- a/src/frontend/src/content/docs/integrations/messaging/apache-kafka.mdx +++ b/src/frontend/src/content/docs/integrations/messaging/apache-kafka.mdx @@ -1,7 +1,6 @@ --- title: Apache Kafka integration description: Learn how to use the Apache Kafka integration, which includes both hosting and client integrations. -prev: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/messaging/rabbitmq.mdx b/src/frontend/src/content/docs/integrations/messaging/rabbitmq.mdx index 52a220f6a..574edae62 100644 --- a/src/frontend/src/content/docs/integrations/messaging/rabbitmq.mdx +++ b/src/frontend/src/content/docs/integrations/messaging/rabbitmq.mdx @@ -1,6 +1,5 @@ --- title: RabbitMQ Integration -next: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/observability/seq.mdx b/src/frontend/src/content/docs/integrations/observability/seq.mdx index b464c2bf8..90279db32 100644 --- a/src/frontend/src/content/docs/integrations/observability/seq.mdx +++ b/src/frontend/src/content/docs/integrations/observability/seq.mdx @@ -1,8 +1,6 @@ --- title: Seq integration description: Learn how to use the Seq integration for centralized structured logging and diagnostics. -prev: false -next: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/overview.mdx b/src/frontend/src/content/docs/integrations/overview.mdx index 26b3a65d6..94afee4e5 100644 --- a/src/frontend/src/content/docs/integrations/overview.mdx +++ b/src/frontend/src/content/docs/integrations/overview.mdx @@ -2,10 +2,8 @@ title: Integrations Overview description: Aspire integrations overview page, showcasing how Aspire works with various tools and platforms. tableOfContents: true -prev: false lastUpdated: false editUrl: false -next: false --- import { Aside } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx b/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx index c1e88e626..d0000fac8 100644 --- a/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx +++ b/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx @@ -1,8 +1,6 @@ --- title: YARP integration description: Learn how to use the YARP (Yet Another Reverse Proxy) integration for reverse proxy functionality. -prev: false -next: false --- import InstallPackage from '@components/InstallPackage.astro'; diff --git a/src/frontend/src/content/docs/integrations/security/keycloak.mdx b/src/frontend/src/content/docs/integrations/security/keycloak.mdx index 4a684d227..ef5d720b6 100644 --- a/src/frontend/src/content/docs/integrations/security/keycloak.mdx +++ b/src/frontend/src/content/docs/integrations/security/keycloak.mdx @@ -1,8 +1,6 @@ --- title: Keycloak integration description: Learn how to use the Keycloak integration, which includes both hosting and client integrations. -prev: false -next: false --- import { Aside, Badge } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/it/index.mdx b/src/frontend/src/content/docs/it/index.mdx index d67c6d1d3..643a827af 100644 --- a/src/frontend/src/content/docs/it/index.mdx +++ b/src/frontend/src/content/docs/it/index.mdx @@ -7,6 +7,7 @@ head: description: Aggiungi Aspire al tuo stack e snellisci il flusso di sviluppo con controllo code-first, modularità e osservabilità. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/ja/aspireconf/index.mdx b/src/frontend/src/content/docs/ja/aspireconf/index.mdx index 1923fda26..2743cc346 100644 --- a/src/frontend/src/content/docs/ja/aspireconf/index.mdx +++ b/src/frontend/src/content/docs/ja/aspireconf/index.mdx @@ -7,6 +7,7 @@ head: description: 3月23日に開催される Aspire Conf に向けて、ぜひ予定を確保のうえご参加ください。無料のライブ配信イベントです。Aspire を体験し、分散アプリやエージェントの構築・デプロイ方法をどのように変革できるのかをご覧ください。 template: splash editUrl: false +prev: false next: false hero: tagline: Aspire Conf
3月 23日, 9:00 PT

日程を確保のうえ、無料のライブ配信イベントにぜひご参加ください。

Aspire を体験し、分散アプリやエージェントの構築・デプロイ方法をどのように変革できるのかをご覧ください。

diff --git a/src/frontend/src/content/docs/ja/index.mdx b/src/frontend/src/content/docs/ja/index.mdx index 2b5495166..2d566df42 100644 --- a/src/frontend/src/content/docs/ja/index.mdx +++ b/src/frontend/src/content/docs/ja/index.mdx @@ -7,6 +7,7 @@ head: description: スタックに Aspire を追加し、コードファーストな制御・モジュール性・可観測性で開発ワークフローを効率化します。 template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/ko/index.mdx b/src/frontend/src/content/docs/ko/index.mdx index 7d75eff50..33a2e6c28 100644 --- a/src/frontend/src/content/docs/ko/index.mdx +++ b/src/frontend/src/content/docs/ko/index.mdx @@ -7,6 +7,7 @@ head: description: 스택에 Aspire를 추가하여 코드 중심 제어, 모듈성, 가시성으로 개발 워크플로를 간소화하세요. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/pt-br/index.mdx b/src/frontend/src/content/docs/pt-br/index.mdx index 12fc8f58b..da7f772a3 100644 --- a/src/frontend/src/content/docs/pt-br/index.mdx +++ b/src/frontend/src/content/docs/pt-br/index.mdx @@ -7,6 +7,7 @@ head: description: Adicione Aspire ao seu stack e otimize o fluxo de desenvolvimento com controle orientado a código, modularidade e observabilidade. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/pt-pt/index.mdx b/src/frontend/src/content/docs/pt-pt/index.mdx index 97e4e52e7..8f4a8be6a 100644 --- a/src/frontend/src/content/docs/pt-pt/index.mdx +++ b/src/frontend/src/content/docs/pt-pt/index.mdx @@ -7,6 +7,7 @@ head: description: Adiciona o Aspire à tua stack e agiliza o fluxo de desenvolvimento com controlo orientado ao código, modularidade e observabilidade. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/reference/api/browser.mdx b/src/frontend/src/content/docs/reference/api/browser.mdx index e6adeed8f..62065fb72 100644 --- a/src/frontend/src/content/docs/reference/api/browser.mdx +++ b/src/frontend/src/content/docs/reference/api/browser.mdx @@ -1,8 +1,6 @@ --- title: API browser description: Search and explore Aspire's APIs from Microsoft using the Aspire API browser. -prev: false -next: false editUrl: false tableOfContents: false pageActions: false diff --git a/src/frontend/src/content/docs/reference/cli/overview.mdx b/src/frontend/src/content/docs/reference/cli/overview.mdx index 9151b35b3..b62d52bf9 100644 --- a/src/frontend/src/content/docs/reference/cli/overview.mdx +++ b/src/frontend/src/content/docs/reference/cli/overview.mdx @@ -1,6 +1,5 @@ --- title: Aspire CLI overview -prev: false --- import { Aside, CardGrid, LinkCard } from "@astrojs/starlight/components"; diff --git a/src/frontend/src/content/docs/reference/overview.mdx b/src/frontend/src/content/docs/reference/overview.mdx index dc5d76984..f4f1516a9 100644 --- a/src/frontend/src/content/docs/reference/overview.mdx +++ b/src/frontend/src/content/docs/reference/overview.mdx @@ -1,8 +1,12 @@ --- title: Aspire Reference +prev: + link: /deployment/ + label: Deployment +next: + link: /community/ + label: Community description: Comprehensive reference documentation for Aspire — CLI tools, APIs, and command-line reference materials. -prev: false -next: false editUrl: false tableOfContents: false pageActions: false diff --git a/src/frontend/src/content/docs/ru/index.mdx b/src/frontend/src/content/docs/ru/index.mdx index b51a7b26d..67c99ab77 100644 --- a/src/frontend/src/content/docs/ru/index.mdx +++ b/src/frontend/src/content/docs/ru/index.mdx @@ -7,6 +7,7 @@ head: description: Добавьте Aspire в свой стек и упростите рабочий процесс разработки с управлением через код, модульностью и наблюдаемостью. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/support.mdx b/src/frontend/src/content/docs/support.mdx index 840faec2c..b28fe1fa7 100644 --- a/src/frontend/src/content/docs/support.mdx +++ b/src/frontend/src/content/docs/support.mdx @@ -1,5 +1,7 @@ --- title: Aspire support policy +prev: false +next: false description: Official support policy for Aspire - lifecycle, release cadence, and support guidelines. template: splash editUrl: false diff --git a/src/frontend/src/content/docs/tr/index.mdx b/src/frontend/src/content/docs/tr/index.mdx index 4fef4d526..d56d42769 100644 --- a/src/frontend/src/content/docs/tr/index.mdx +++ b/src/frontend/src/content/docs/tr/index.mdx @@ -7,6 +7,7 @@ head: description: Aspire'ı yığınına ekle ve iş akışını kod ile yönetim, modülerlik ve gözlemlenebilirlik ile sadeleştir. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/uk/index.mdx b/src/frontend/src/content/docs/uk/index.mdx index 7e156b27c..e5536d2b7 100644 --- a/src/frontend/src/content/docs/uk/index.mdx +++ b/src/frontend/src/content/docs/uk/index.mdx @@ -7,6 +7,7 @@ head: description: Додайте Aspire у свій стек і спростіть робочий процес завдяки керуванню кодом, модульності та спостережуваності. template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/content/docs/zh-cn/index.mdx b/src/frontend/src/content/docs/zh-cn/index.mdx index d0a6bc268..f6a0f24ad 100644 --- a/src/frontend/src/content/docs/zh-cn/index.mdx +++ b/src/frontend/src/content/docs/zh-cn/index.mdx @@ -7,6 +7,7 @@ head: description: 将 Aspire 加入你的技术栈,通过“代码即配置”、模块化与可观测性简化开发工作流。 template: splash editUrl: false +prev: false next: false banner: content: | diff --git a/src/frontend/src/route-data-middleware.ts b/src/frontend/src/route-data-middleware.ts new file mode 100644 index 000000000..ec444403c --- /dev/null +++ b/src/frontend/src/route-data-middleware.ts @@ -0,0 +1,138 @@ +import { defineRouteMiddleware } from '@astrojs/starlight/route-data'; + +/** + * Custom route middleware that applies implicit pagination rules: + * + * 1. Group boundary rules — within each topic's sidebar, pages only navigate + * to immediately adjacent link siblings in the same parent group. + * If the immediate previous sibling is a group or absent → disable prev. + * If the immediate next sibling is a group or absent → disable next. + * + * 2. Splash page rules — support, root/locale index pages, aspireconf pages, + * and 404 never show prev/next navigation. + * + * 3. Frontmatter overrides — explicit `{ link, label }` or `false` values in + * frontmatter always take precedence over implicit rules. + * + * Runs after the starlight-sidebar-topics plugin (order 'default' vs 'pre'). + */ +export const onRequest = defineRouteMiddleware((context) => { + const routeData = context.locals.starlightRoute; + if (!routeData) return; + + const { entry, pagination, sidebar } = routeData; + + // --- Step 1: Group boundary rules --- + const location = findCurrentPage(sidebar as SidebarEntry[]); + if (location) { + const { siblings, index } = location; + const prevSibling = index > 0 ? siblings[index - 1] : undefined; + const nextSibling = + index < siblings.length - 1 ? siblings[index + 1] : undefined; + + if (!prevSibling || prevSibling.type !== 'link') { + pagination.prev = undefined; + } + if (!nextSibling || nextSibling.type !== 'link') { + pagination.next = undefined; + } + } + + // --- Step 2: Splash page rules --- + if (isSplashPage(entry.id)) { + pagination.prev = undefined; + pagination.next = undefined; + } + + // --- Step 3: Frontmatter overrides (highest priority) --- + const prevConfig = entry.data.prev; + const nextConfig = entry.data.next; + + if (prevConfig === false) { + pagination.prev = undefined; + } else if (isExplicitLink(prevConfig)) { + pagination.prev = { + type: 'link', + label: prevConfig.label, + href: prevConfig.link, + isCurrent: false, + badge: undefined, + attrs: {}, + }; + } + + if (nextConfig === false) { + pagination.next = undefined; + } else if (isExplicitLink(nextConfig)) { + pagination.next = { + type: 'link', + label: nextConfig.label, + href: nextConfig.link, + isCurrent: false, + badge: undefined, + attrs: {}, + }; + } +}); + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +interface SidebarEntry { + type: string; + label: string; + isCurrent?: boolean; + entries?: SidebarEntry[]; +} + +/** + * Recursively find the current page (`isCurrent === true`) in the sidebar tree + * and return its sibling entries along with its index within them. + */ +function findCurrentPage( + entries: SidebarEntry[], +): { siblings: SidebarEntry[]; index: number } | undefined { + for (let i = 0; i < entries.length; i++) { + const entry = entries[i]!; + if (entry.type === 'link' && entry.isCurrent) { + return { siblings: entries, index: i }; + } + if (entry.type === 'group' && entry.entries) { + const result = findCurrentPage(entry.entries); + if (result) return result; + } + } + return undefined; +} + +/** + * Identify pages that should never display prev/next navigation: + * root/locale index pages, aspireconf, support, and 404. + */ +function isSplashPage(id: string): boolean { + const normalized = id.replace(/\\/g, '/'); + // Root and locale index pages (index.mdx, da/index.mdx, zh-cn/index.mdx …) + if (/^([a-z]{2}(-[a-z]{2,4})?\/)?index\.mdx?$/i.test(normalized)) return true; + // Aspire conf pages + if (/aspireconf/i.test(normalized)) return true; + // Support page (any locale) + if (/^([a-z]{2}(-[a-z]{2,4})?\/)?support\.mdx?$/i.test(normalized)) return true; + // 404 page + if (/^([a-z]{2}(-[a-z]{2,4})?\/)?404\.mdx?$/i.test(normalized)) return true; + return false; +} + +/** Check whether a frontmatter prev/next value is an explicit link override. */ +function isExplicitLink( + config: unknown, +): config is { link: string; label: string } { + return ( + typeof config === 'object' && + config !== null && + 'link' in config && + 'label' in config && + typeof (config as Record).link === 'string' && + typeof (config as Record).label === 'string' + ); +} From c8bc3770420fdc47ac9981e0b384779656fe4502 Mon Sep 17 00:00:00 2001 From: IEvangelist Date: Mon, 23 Feb 2026 20:58:09 -0600 Subject: [PATCH 77/90] chore: update screenshots (add support for theme-awareness.) --- .../new-repository-from-template-dark.png | Bin 0 -> 57235 bytes .../new-repository-from-template-light.png | Bin 0 -> 57257 bytes .../content/docs/get-started/dev-containers.mdx | 9 ++++++--- .../docs/get-started/github-codespaces.mdx | 9 ++++++--- 4 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 src/frontend/src/assets/get-started/new-repository-from-template-dark.png create mode 100644 src/frontend/src/assets/get-started/new-repository-from-template-light.png diff --git a/src/frontend/src/assets/get-started/new-repository-from-template-dark.png b/src/frontend/src/assets/get-started/new-repository-from-template-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..ef6f2ed168ff8dbced23116a80720e8cff672383 GIT binary patch literal 57235 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 diff --git a/src/frontend/src/content/docs/get-started/github-codespaces.mdx b/src/frontend/src/content/docs/get-started/github-codespaces.mdx index f15317ff5..0046475eb 100644 --- a/src/frontend/src/content/docs/get-started/github-codespaces.mdx +++ b/src/frontend/src/content/docs/get-started/github-codespaces.mdx @@ -5,7 +5,9 @@ description: Learn how to use Aspire with GitHub Codespaces for cloud-based deve import { Image } from 'astro:assets'; import { FileTree, Steps } from '@astrojs/starlight/components'; -import newRepoFromTemplate from '@assets/get-started/new-repository-from-template.png'; +import ThemeImage from '@components/ThemeImage.astro'; +import newRepoFromTemplateDark from '@assets/get-started/new-repository-from-template-dark.png'; +import newRepoFromTemplateLight from '@assets/get-started/new-repository-from-template-light.png'; import createCodespace from '@assets/get-started/create-codespace-from-repository.png'; import buildingCodespace from '@assets/get-started/building-codespace-image.png'; import codespaceTerminal from '@assets/get-started/codespace-terminal.png'; @@ -33,8 +35,9 @@ To configure GitHub Codespaces for Aspire, use the `.devcontainer/devcontainer.j 1. [Create a new repository](https://github.com/new?template_name=aspire-devcontainer&template_owner=dotnet) using our template. - Screenshot showing how to create a new repository from the Aspire devcontainer template on GitHub. From efe51407ec53648cf81604a238cb5070a8b7151a Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 21:32:08 -0600 Subject: [PATCH 78/90] chore: Update images and add support for theme aware. --- .gitignore | 2 + .../efcore/dashboard-post-migration-dark.png | Bin 0 -> 41720 bytes .../efcore/dashboard-post-migration-light.png | Bin 0 -> 42102 bytes .../databases/efcore/migrations.mdx | 13 +- .../src/data/aspire-integrations.json | 270 +++++++++--------- src/frontend/src/data/github-stats.json | 2 +- 6 files changed, 145 insertions(+), 142 deletions(-) create mode 100644 src/frontend/src/assets/integrations/efcore/dashboard-post-migration-dark.png create mode 100644 src/frontend/src/assets/integrations/efcore/dashboard-post-migration-light.png diff --git a/.gitignore b/.gitignore index 9bb5b0022..35c050d2e 100644 --- a/.gitignore +++ b/.gitignore @@ -430,6 +430,8 @@ FodyWeavers.xsd # Local History for Visual Studio Code .history/ +.playwright-cli/ + # Built Visual Studio Code Extensions *.vsix diff --git a/src/frontend/src/assets/integrations/efcore/dashboard-post-migration-dark.png b/src/frontend/src/assets/integrations/efcore/dashboard-post-migration-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..63f91151aa5b055c74c5ffbddcc87ed76f028c5f GIT binary patch literal 41720 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 literal 0 HcmV?d00001 diff --git a/src/frontend/src/assets/integrations/efcore/dashboard-post-migration-light.png b/src/frontend/src/assets/integrations/efcore/dashboard-post-migration-light.png new file mode 100644 index 0000000000000000000000000000000000000000..be5f02c517f8bb0f14907ab73e50bd8ba359cfca GIT binary patch literal 42102 zcmbrlbySqm7cPtniXx>_A_5{JQi1}~-BQwxbR#+R&>`JDv~)=K(A`}_=L`(p408wk z{q9}gx_7N_eczpb=IwXyefD|Jd7k~8AUPQ^>}Ri^p`oE+ONa~qKtsbYKtp@5f%y=1 z1o2%j5Dg6vO+r{e(J5sYg5~yVqv--kv#^TMSVd8Tpxm|PV9r|@dQg;0SBZ`nm4{c{ z0?uU&;@6<|m5d^+tCFbnO}E56 zkplzp-2o$j-TZs0BWLjEp&{Pmf!%@Kjmx2P=RZOsB7P`aP`?8x#r;3pb4v z?l)R|bsyYse5O?Wcjo*5)g`7hNsBwfg~LE9MxBCx@1j^`bvA09av*ZFs-r0A%sV7o zdkdW?agVuw-|{oS&Bfs`@3qBD+0RT?vpLWyRH*yO z-SvU5$~&(&ldb!}){Tdv!yujpz&<0g@9{ylM6_@}?Z=N1z>N>R*wOP;xdAw2bE_IT z(Hd0-y;1JhXT7F%&bEb7(a|FP&Pc@hM%ON+L1kXWR=+Z+E3hCh4^MjSCH-b(e9znvP<7M6W%#>ebKh7Ew7u^ij^lfj5XEO#oZ3`52m21-hS z`4=Q@5%Y0rX=zbWW8NCnHDbvlXR!;_nVIiKzezi#f(;;k(0<7X{%hIfnZ~oWY~=6z z5P8N?&97G&4L+0S$D(#Sn>8Mseawh*1=~7f6TfG(2DDO2ebb*?8CNIA1PYEz7kdVB zT78Q0hP{s=GX7-AX)QDk`)3bNwaMta47gAobLME0nPbh(!Um5OK5DNxpX zEPs@iN4RfQ!0oVF&Tm(6WwPOmPvueGjKlGs0QU9`v)-r-zE|_dBp$O4-=b6^bd>L& zqLHD!BashNEfV>TdZ;qhwj&>sd~kx-ZH4GRFyWzE|9%-$t)$N9XS7K~8{ukn7ns|F zmG)D`z)eb@SGIe$G(AsA#v{$A0r4TPdjgJV_e$wM^aoy<7YukKuN%O)#8XnDPk1ku zvt(j@vV^;MZJOLSIF{SX(yleFXzyC^Yg`-)#ROrk#YuC< z5na~CjQJyyp5V(PYlU;M2yAtRA7w75X8H*&)_4NWr?((icqD_PTCG_4+re2W!T!$A zqR-Yrks5Sqa}9vfgEI^hkoF7p2*G)ML2SJ320=I>$&X%@9ltd9v)QXKy^;5=-r?t| zP$$Z>a+ku6)vbG_({Op2-hbxmiHo*>QTs?|;9H4tkyh>yG>O&{< z+=i~$5x^1>L?MH#2X#_wMy7Lr^=)_bFz*OmOSH}_f@ZE?zjiZcK|k6mgu!q(!T@ZsbFb;!cH=gWn6EFI8apBf^!659=IBh$0H(fQa(Xl@Y()B;T@T zh%&D?7wmuV19#pIvTq@;LtzCXF;ODvuV3l&G@d8p?9JCG_%q1CLk_@NV*`dXPC1@ zg1=RrLxghu(LLZj<}luJ83wmn>#@eROr|c`y$|;(@TJ(WP@41!{=}mPU8W?gBT~(m zo5|9ER!uO>>#sl|cJs%zhvm%lxrTNsOK7t%rU)Y~FN|vKGTzdTJS6NA_geT|M_n#` zyI?nL>SxGI!gLVq;u{~goiSNTPG7v_l`;Y+`NXD(LT>Cauqh!xx{b&O#o~dy5abJbJm?TpWq1@rhB32t`t4A>ZF=x4QWI7X?`;owA1Z=0zC2DF< ziw347_HpJapo0xXXyfg>(wa7H>QR?w|$8L1CJ3IG=K||Ooc0t_oxwvJ*(>*oI%tkFR&y0aWj-g(ogjd;xrT*$qUfy;d)Y0~~%i9{B=1^>+ zoZ2;Wu9xemFey1A}|#D7{fVoY}N`F46vq=LB258!K(+fJF9 zE)&BoPObV=yPt9?%j-7jH+);}vXMsg9Rb~umJ$Uhr}3P_OLK?luC@SAWRsEWmh6F8 z-Af)Gll2(qyR7z+a!uzGDX^}sCIp?K2AG58b8a{OS_?YQA8Gmx<_<8jq_+0I2u`0DTY+u^!BuGNX5Nm-uLXz*KFr|Uzm4$mhb zwq zQa6H-)}&<_XXQEJ8#?4}13Tc2o9nPX0UY;?tXd6jwj?vPBvbdqI|N%%W04c7eh#Y# zKxcANU5tH)!+&SNnXXl>@dkI|Oox$m<4hj66ZLgLu=>zTiOsApq%T;$mBR<0`X$FX z3qI2C{$6|fw*gpnlrL>Fym+l;omgy+!=qO25t5t3<#=(2u1{>bnv-fI~_rs4rs_ki%d`K-uCFWux%ut;b> zm%0ofZgUJYb)lt>fkCpRz_ynVxf*AfUoDN4$DXsieluU=^hvf-Venh+)B{KYv%X%5 zi$)O_`>&IPznc$mz_aR=YR^Hynk^9s?}v=>tIT3oa&Wubqu)`iPtrcoHqKX6GuyPQ zK==@TCrT3gJiPZaNz6xx7w(TrdSODuU-8v|gM~|1x*iXROvgwG`}#JNTrAVk5m5JS zaW9a|NVbmvv@$S=ZNbN;nY&iKGL!k5CIy1Wn6|gHwy9CTq;kHySgH}uxa8(qQcwUL z%jvh3IW?q2o|Y~AYW^|A4OAOaY-(VJ9&PkzIy;n0ySwzelG^>jZf;!js|y0$8cd3v zf~%Id(-NXEIlBi_<|KCAkwQX|`!cR3A%{s9E!k<$iHOeNDlZP08n64Nuu}iO~pj#L5+Y|GyEXojRYk^Nm?dtYrl09mE1~?EWoapr7%wOl< zWiTG$Y169ZZuN-0O25$8;;Kk2Go!ED00}&4(S~AAHimN_w~y>u>FMcH;sOfcbsyRJ zAJd;)D|`oWtHG)3eqR0Q3%EK6C|C88oKTqY#^??M$%`>6K4yCL&TNJZdD(lIN>s?G zOqcP{p&8HTY5~#7Zo7%W>O>*zFcF`ob9xTZ2_hWHpPs23wst8!2x4C1IcRH-PP@u0 z&<;Lt(ofgnY?E%H7mRT?+Wx`k7NJArweJ`^xIvZnX|y(4rw80_ea((^afPtR1qz8h zC%d{|3+ zjuU^&OXsU#6MwbrW9CSHZY57XvgQL0R;dJSPG=}A^~#p)H-3g6o))t4SZoW(HOM?T zU%*by!VWKaruau8o-tFK^Q)7l-!i8TS-}{*2BPe|J(592{x*5;oDjVASmye)z2*|k zIDUYB+xKjmECT6j))tt11Dd_G9pzhdBV!c4_T1uc0uZBe#Zz}($)rh|v6St6dz4Cb zO_@|h2RP#?v+qEYyi^`U_vqz={h>Uq-t%OVU*9|aP@N|qo`qgjxzFlNJ1QOvKl81D zdFd>RilU#iVpVF0Z_Dmb!?^l{oV+n;`i2W>pUJBy@DIMm)8Yi?8t;=bDT1tl4m1uC z52?dO_PTC2R1i7kvkuX)C8Kw{MwnI4B0R3zoq>`O-le1KZ0AHI(F=q3f_z-oSL&`+$Ta4uBm_ z$90N_`I?glt&c>;QFtQy;>4Q#_L#=qr&F{9xwvKy1~?w+gKvA=7)zN**T@v!)gJ?V zFDj!A2NH3N4pYQJ;BcW#K>~$ zzg)ok=McPR#98CFCD_phv_F25_er1c$e)1cx5Khw`}IzT-hlOoIRl;^LNacbt)0PJ zv9Hh#cOM?YVbgBMrIMp>KK)iM;xmAM0>YbWke`H?thA~Emg>~1GtNEapme|ToDh+( z2`t^4wo@{;+A{b`7HK(YZd$&*Sc*I?bvNj#;Hz;M#6rGm?_SEU9OZ(r{tT%tyG?Wu z3xSXi?P(%z@R`5Uy_k!n!Y0epJLoWN>R5~g&y$#?`wwNsH+=>iToz-&wesSx;i>wM zgMlTkrrmYw)w_B70+WlG4yfn;;c**AjUdvL?{blA5*fja)y)q@+fJsy9 zyO`&_EGBQZkg%Go+?h2_i^Z)9Uhj&_ZsgxXAxP}C50+2+tNNwR1qX=^`s3pN`p|%! z+P;Yqj&O=y3|gDnf=y`=v;~AgueLSbozINrNEyBtvGNSLAhzT8<#h4BRcvvUm=Gam z!3raTbXqbVzHz!_9MQ*K; z_Aa+YqwIM#+>Il~m3g1TuP-59xyp-(tnjyKtXEvCZLQL>;DbdzE?GC1upMnrcP=pU zSKC4wH=DB@%_*agNZN0&a9&Wl0|abz(?+n5uw3lR?w!vaOo2B!tWHs>gaTch1-GaE za+b7Cp=Lg(f!9NeOeL;2VyBICf&(dyVt@}k$1{+ewXNG}2v12=;iB5fXp0UH>!dyI zqm62Oy{n1XaA`tWYxO@Nb~BdHHnHF+klL?v%3<%-8)I^-rK6QVnlxl&wMm+Q@?VGX zf?WSpa*wO!*@ms}7fy&PEWMMamk%4?X|yTAu;`{smbi{>hB3pYhFqgxzP&!we~RD= zVgi(CYugJyPe}&x7v1-(tc*{y9kKC!hK>9(7pFJVjGCldJ=K3r^saJTXKPtMj9qWw zyn6M@#OryT#NaING`r{$DDL+wOxEgmxG9^}CQ0nim^Pco zVVN8!N%c3ThrnqaG( zURFCehgD&SZ0+OR4DZ;vvrF!>GHj`k-=0jvh?rEDOb5!J5;Y(HAL~4=E=fo3-`dv^);ZfK^NwBiY+fsh8meqR*<{fPAgN} zVOo_Qc(!Nfa31#6Yn2}AbpTOV0>A_g^Bea*&nZ<+j=30U$vvkp+!8^u73x8Jg6KAI zG}>?;p^Q%QvG6cg$@X(;T}b#-5_-%uL74xybCKI1t0q02KN!b^G6W83fcdag_k6%W z!B$K#V#@oi^Lpe<8X1#u+i8;h*b&{IJ@nhRz|4L~nzByqU#(MzqYM`nVFpFKs`GuW zTZgMF(t7(^H;w`=F6yB4qp|q37^JitSDAaaiR^ZI`|SK4%MZLwQuMnZqIr)#W{My> zM$|XJhOe*-mMl=S5bYN%MwCdX{38Y=xbx*RdsNcTXKBdYu;6qpFl4w|w{LN#^uEZ@(YGJz&<-6yjeP%JLfUP@R-%*RUE(J+@ zGEcCxIx!6z)APlEMZx~qKZ(_ytWq)WuH{dDw}vrii6vq#Tz0pQ=II}Ja1zjk*^U-) zzn{)ZS#iICmVkE;r_j(opkv)1@qF5P?+}`<;J5k&%oFEiqg`moD-(H7bu6T{DGfsrf8#$7178g3dRg3P=zRj7bmZ5+YE}s3V?u<5 zF#RVM6q&wXR1YS5&(viEoJ}jAqhnT;dOauqo`T3pS-jcBX8D>v81vwv+7Yrt)5%(> z@?Rt)vn3vXi?MlNDd>;e?6UQmbI~835~}Kb>X&l&!M{mMz?ya_W?B3Z$$J+X{zCi9qm5u9CS@fhB^4FemkoPG zMa99k0b>u}Ve9DA3rmMp(T3@fydHlLrBt1A>)RqD*&nm&veVWi8)yy-vV6w~-?H^>@MYoXW^2W#gAJ_1SXl|2ju?JQcKoVRM#JjwWlr z^ZE-L$KL498Sm(QG(D$EB)aI!Iuu`%YcHLS#q!9s&PL~uR=m;ITlHuP_9D5DezA76 z0pau8+Zvs;-SiyXo)&@Kb8zJN(Y_a;1mA4;E_NdCVLYF9TnQbZZkM1MKphXIcRA6Y z;p#n)!`71jyoxTR^&yG|UGe0~O^LO6a5;PtLr8HDjDKTonu|I3jhOe#HM=81eq*$4 z!Z+jvt6rJ;4*3~htrMzXgod`vqzZU5ljeXlt1ORf@!Z_0+l-K>lE4sNT@5LVzD9}*?@#f6p(l6DgMk$O^;tu)0A z0wyd;=^GS*bOQ1CS(a@|_cW^SV2M`4TepMOiHV7L9gkT(dCrIZEv=7mxy#%xkL0sN zpQ4?{BZFmF_#?`1yhDh3@>(Y@i9~#Sod+Jy-hve>MRkCeN(VG_;q}^XA8K@^b|f5h zySGc2Z7Sj!Q`xeEmlliZ0f;3f^C@uCa52Fvt@`fg$x(69X6K|B8Ak@Dqrr9N?2S4u zf~1U;^@R@GkZ}*r{Z@G`X?BB;0GTplGUY$3#}H?I>DUV^c*M5-)*O#rIOkfILB5@3 zBA4Ww>AG?cmg&n;wNc8QPNCT>L5l*1313swM83CUowZ?Ka{PcjwpKGre=LoN=JRNe z%YpdDhhTHxB6z0~hM)C5)3Ne2>*iAK9|q|P01+zMCKU$R{QgfvY`p61wqz1nM7prF zoi}22FELtTS9?iDjd@FXcrupu;uSnx1tt^%`|PSy{k+ul;om(&zPhG<__oT(%h@VI79oL*;! zE9^P8HzF`9fKh9JdB47BxR#$3fM7GU&*QZ7eIaJ}my!u|vA@-S3XZSH=w+<>6F3{n z7BtU_${!%v;oU;JS1Fbxd?{K^V~Tke(^z)9<^cv)i_0VISktUgU=rpe-YHy*0!=L$;(9m-EM|+nge`1PA1xUs*Or#_zbkWF5s)d z472@wffPbn!MjKsXz@7AynK`hQ#38o-V_EsTgg*Uq;A=e5GP07al?_TdCwg}@V zY6;e7_wrHB@1~Mjl8~@N;|eFF9b%P}enU1GjHCu`c5q$9(omI|*&@A~BfSc^4!8aO zDkZeHiqHHv&5w~*qcm0?Q#tmHSaN!L`d?2`nNax?RgR2n_4brC?ZwCxuxfPm=<>Dl zCt3RfdaaW+al1vnG^Y?sfmS?#YoyrwS>X0YhUEtZGRXg(DqhbbD+!ohKDYT>nR|RL zz$@g*cN<>wM(b7iEm4Zqf&D~ivg5L?Vq}oaQ{g=aB^4!L51!L8G8r)ko5;;<&OFo4~2Fcq; zO#{a9vgfCk-!!<{J4tD4^@sdfO@*vZ2z6|yVymXUAeg3K@}0jTt+GE49_PM(Z*_F8 zpW9*R{vM`wo$SB|Ind`=Qo5kor$Z_PmD7EFxoUKCvpZ{jSGAZc((exQ+cu#{BS3@h zcO@5+rbz1wmr+FMH$2l>G)%!qSRaxE#}5%()u)4zvUPJ20i)yPO_2|kh^`yc=6=T> zKKz7Lv!}y777;9`=JBICB6Mg9ElkK-@H5TRrn$*7XbtNOG9UooS za3P+R*fIfwauRdSPtNw&O{93?8=KtBt1q+Y(Qb*R~GT zXgmANXV1=h$!SPH(WN&wO6EofBHw`vM)8T=Jv5@&+t5uI>4}+Z40c=J)X<)=dAIMer5Z z8^eJHj@9~KF5tzNGo;iT_;e-1QcZufO~mIeb?)@~=A&A7wQU+1n9^|;ha6Z7TSg8^vAq}?Ip@1U3W?$zKs4A9Ti z{p!%ysOk-p-B)8#uf!nBYzX^4Uv}x=yH;)hyI6nRy-V4k<5p(g{t3pyQemL;Lt=4N z#2k>SINuwKRA{{LTIKt0bGsqo>bt&{c7B7rDlEnSIc})9xjB{%UT3_mvYUSDAY+)` zAaZAY=nkae97T9<4W|KjXZ|8D!jZ(RW-%!de|;Joxi1w_!+yI}s;a(cySmaFK5CrX z%foKuZedpL%}U=)K&@?KRdxII{M>m1;t2IIf;ib#VFqvlgbq3|KTYu@)Wc`CO)a;= za+SLaP6QiR(7a|&`zHjigC#(+p^JzO47(b+t8*^o(YS^W{o)Fzj{SY z3C1OO`~4$y+J2@UC$Es#zJ~Tfqv=+dkFNW~TmL#pP$>pGemY*%%HvVLC^<6O%EYG{ z82(UPEEf-{J7{$vko3y-3pT*O+89TbHJ|tQ>H2O(mS+PP7CSZkH)x#gxLYH&NMyHb z2r4_BM6tiQF6V8(9tdTfYeS_2j!fU;nb&IyxtLnVM7mcc(yaTYA3rV47Cy(X6A=6nJrz06K}lOjRL?$7e@Um*knl+~N$^D>!m( zEgWeBYUiMce#Te2}{ds$nf3dYh20K#Y?Wg1JbDb`(Z~w+h_`|?#V z_t8zEm5@DN@NS9XhH$+oG~AYxZMa@P#^^#5QWJm{TrHV*)jS}l2h~p)&TSS{l;jj@ z&Z&1(n~r+-IaF*-JeN?6i>E(`QPjR9L6L;^FsS=RYxx~U9hqXaY1Hk>Zs-gn2skIN=%GuonPB(z!dp}6act(y^KyW9#pec9NfcVsDrPj0Jqwngb%nl&y9*mh(%%Lo+^($bMu>w@$F`Fg(-3Jo~WJcu1cO?di;OPgWKQ5bb%d)O5|Vu>FVq(faHD(Z#oSq3I&leb#3hr zlNMH8(rIDcw*PIN-`;?H^BB8hoH7&QQU3rYp+Z{$GB_$Ot|L8$w9uxSc+-_^=-8<8t z-mf6}~b!HY_HKZV&m!r{g@J{0?6wEt{Z&Cx<@EHl-QkGS@&@>JYoQ#f`A3svE`kn%_!YmYjt+za%mbq ze~_}E)o2Fz3nTyxsMREh-$7!*(IYH$&t(I93eB}w#FKyl@6mqc!0xy9v+=m<9Bu5i zp2iX0uE8&&#DW{*co-^qv8a^i*gi2J8;k~dvWF6N)^*Y{4%z^QpWj)Jkc)2PHno#* zfAE+qM@{n1vpbJ@+)syZX<1bo`gJP@56$xX6G`}L&54?@mvRa%4SxKo$UccBA+#JS zmPo`6D|a}@Mvy}$*`Tf8x5CD-^MwZ3(YINkPgQohyIp@h8(H}6a;QbO zxQ2>OQI`31>lufv)g0nyHGm>XBYG@aR1KSpX2Kj5la|=x`uZdkIzK(059D+ds%80F zPI`y@J-aYn+0iKkg>Bh=Kl}jyhr>#rr24O}63S(CPcxts5)e#wH8^J}MHyFd*NBh` z-7{Vwt#mu0Od{R_V z=|5HjO&%@a$cuhWG>bK1q5Nb#a8E?6jG}P5HA>v>iY)u#GHNu!3)`rx&*$UI1|NiLm?-4f$ z-nQrcP7A^Rq&VNFprmvFe$4%M_h-^2{1{X}n~r6p^r{SM<=Mu=AO{_2DElG>_PwyYDEDXYzkBsgx+8o;d$M;?}dvJn8|? z{Zm?EgLNOY?F?+mr`9he+?wPote|gN+8${YbXQ@?(YuLE_HWLP12ty&tS@nK*mTiWfU3^`Crofr*2h zj`mShfvs_$-FJ|0_FcUj&4hLj{kef0zxkn=G%E>9#LKx#k0zB{cUY&VK%DIsdZBEH zyG-kCMW%EFR|hez+>b9Z!a4L{3Lhr*QgonLs*S%Efr=dC95=)3oK&Nu(gm*!No(1v z*Ew~<`n1N@P{;eQcIn;8M`;VDbLqH!Js7QkRJuVkX?zs- zw%c;?gMH;*?fX-h9UWNSde$2t`CMd&XR*lz#fZ#R-V{ntzmThCp5mn(dMCVqn}w1( zDm23MnL8QPS;5Sg>nEtF%)Pl(fe*~pTg)6EtraIj1XYFSDb8n5^LTR!boK7IFEp73 zl_Ky$8e`%9ONA|+=dYvZK+una_H|_bsfNSzdUt#k8Xhn90DYcn^4B)~6`4_!?kQ@9 zXF{w$GfuyaB%6T(Ad^7<%c{bn8}-0#Sg8tm3Pk5~_uH&98R9RwBgI37oUp6Yb*{$+ zrt5$K+NmFSGBF0yh$nDxUZ#KwyUlRGjehr{((DfT7u@Ar5_R zf&phlcD3!6#c18L5&Ie#9i~8TE zGR8@OP=DT6*gf;{4N{`$zOUn=ULNUy=NbDCem^J7zB%(wi9mWUNo6k7HGcDGrV>{b zfqQ*37AR;w^g4@G-^>H(B%XzzS+rc^I_Y@{|8^0d+sC*D%h@sHqzO@kPI1(tsn2T~weK97DsRhDCHXmIE?))N1E^ ziUDjIHn*T`@EhCs_ZpwHNB}$$RpYCwRijF)_9ui}B1(yNT`@&k%)#vYj>UHNvvJJS z=3qP;Ea2v^w{PQ`oX_Edg&zW=w?rN}i>_f+%Es7Vy_9z#emYk5E|=aTQ>)sthU~j- ze$Z)&y~d$!E=XPHCP|fQ%PKN-ecABG?-!LRH=*Twd@Dxx zqUh=gR#>ryvkAP5ItyXs@&!9;iYz*uZi=V&S8AO5!E*gGA+PMJKB_}_TT9SW7asg* z6FF;|U?QZ&P)b@(2`BPc`da%tl+m~@g(GKl9HhnCIaPI@SE(}?$lFkTP})pgQa?m^ zzWzy!Nxqq~=Ay`OsABeu=p4OIbh(Z?w{Q$$5mT{cY!=J-TKz{dNf|`*M04n_z=r)TPZ$}@dIUJ|jMLml{{>wG^bxF<>rsy0W2W$v-#W zAl;O+KA2}AuX0VpsV=ohl*5RBd56@8sv1IQO1{Kx=?c;;3WSLwa*7{U75y1 zemfioztCR#Qd~1Pmj)iXE!PSx7SUS+@id`&!`~~2X$3FC>sme86)pA4RIII_-1A-e zRcscsGLtQkK@-TwZt{}AoT!A0O+CMC*3@U4^K<5Sl)hbN-6om328Me^OmRMmtsFMqsVRVD@?t;Z{wXrUE$gA z_rU}wF;V*v{Yk0Bvyno~^g9hNx#h1X#phnPig-sZ%{9FR(Zx$KdQJSx8)kI+WCj&a z3y}-ukIVo*dP^w}{%*8cMdj_=J(kjE9~v7 zrxlg{?$)l}s_u$2e#CqL{~v$Ci%W0j%|#c}pNNGdu;1?R^ox>n*_y2S8qQ?`q=}IM zR0J+O@M1bKi^;bkV8cX{AYHEm|3{UD&Bj(?M`=0%Tp#R7;?Ku+5z%%=n_>1j*wr`$ ztH-88;F}xerWU2?UiT$dID4{W+P69w09O_`^>_JfEJT2r<=eq6<_DvwY6Bb* zt-g;2jV*g4k3+-@0gb4}+4~cvZj8>*bF>~}aw*r99rKg5iGAmJE!5_Gww$fusB6w# zM1X(({njItS+_w>D^0+$Prw`wB!mrFU!{A*%%YAB7&J@Etm~_SJwx2seOzJ+`r_H|q9#5C(Ov z4wj!?ALX0P9J}Tqh8yIu^q?vyF!4qL{k%(DhEP^#Z zyQn9CV}7WgXR1Zqi*4X%h?03;yfq!Yxk+NnRfyCJwJ$3r>d~HQIMNak(rG@P>Y&2h~sq2(t1qfrn9s5E%3-YQLSyF{eD^~?8Aa(Pyx(x z`fStjWlo4%O?U3dH``UL=!AEd`qNEZ{=G&6e`ANh)xbn|_BR8SXowuBYzT63WMZ=$ zn7g^*6D1nrG@v0H{5(}PzQc>NDxkE=n6ZLrXi!><%X!@Tw!EOd9m|8GPL2&Xiy>=s z-Qndb%t~)Q<(qL13k{=tdvvs67Ef>8+Er&bgDQ8iobrg_udxEM;I$Ze+>Qvv+%;<) z;~{(3#Rv{5vTBSWPuT8NdPTO73$#>aP(qWsP`VF+TsJbX)}l6I=n+?hhQPl-jb-!c zO6S;&GwY9dZ4yg))k-TL?iJJ$(vFPn#Ckk|kP=gks6~BQEyjU~8qUQLTcZN1JIPi3 z4Oev%{;0soGToOqEJV0)?38~`0k1YBh_!mcYSM+{qn6C>yEm1ov}RwYBRN^!^ z)TOOSA8J^n(x_|3wJS77+ztERC}uw=$Y6xpv;XS2&)#Cyd*KYjf2Q)InB^q&^QLnf zhv&#K?b|&-@|bS)xS(afsl-~>5AdS>AJ-NR=5C*p0SIbJk+yn@H#xp(%y6>1`_mIEUz#vt z2fzAiByhKn_S#cd;FyG9siomLo6~;}{Z}UOvg`j{uu|Cq!3!hj14TqoAnzlLhUctK zp?Yw)j8MF_+5P%I@RECwj6UM0_sxwPhrFB|zwJFJK*P^d^T9wZHtgD+t*A03p^X@~ z#i6_t9igGUle}vw%xJN<&hJ&Xyir;llGm8TM8ur-+jhe|G;J&Y;p6TvPRDO^WcQ_( zit7@kzOXt!?>p!hgaSJm$7IwatjR%8)#e&+_@d z5Sgg`B&}#MIa=>+55S$i!?x|Ep1heEY-0kbUoqky8ldqXn?&gfkTno*17v%Khxt5i zE;2=e|3%2e6s1?ew80fw3w^O6EFj<&@~UU~VdVYC0qvczoxRZKBUn^KN=hSOU;Eu% zx}c#6hsEvsQ%rEtLW3UPAE0>gRfip2{|P!I*}6F~Ee&iu{PsWg3mrQMH+Tzp@3#o!({S?0!cI@f_pGTDyYW%N1#srzur}` zyg3(d$A9n+-CC65#et0Q_*17j6!C!an;r?DuaU(fnHWX2aIN(}Opi~ELg64D*RkFE z6|Ct5CjSo{ejk+oV-LAM(~_Oaue&kyRN3^Zp9cGjR=%>ira&DUwCKo0LUgrqPWaIOF6OKIB&mQ(tj=g?Oh_8rP_0b9BR@5*)H~bnFa0wv!>r zsrCq$dMzoIx8H1s`qjV6NafHioWgqhzC2nhcTD4H;F5CJCF5u)8%Qp+v(@M_U?4pU z>n#uAH+Mjsj;^lH@x`UEW}DWH6`j3tZi_Jt{i{y%tzX1&r#~Nb-1_><<#a>LOFh>D zhwpJeK6b+gu@$27suUPSwW}Plgi9Wi1F8}xlj@;{-Qrc_3ZXgnk}9;_q8#$O2L=aM zKb))FAWHMkwifa|F1|hM|J47?IDA5R<9dLjVTohjPG%OHT&{RjNy{qAy71vv#%uCT z8p-lM&b<8_T>Y0`)pipglPerPXvp!Iz%duU?f;?%wDuN8{2l2>d>L28U!dbZ;M3L_*x&|0|)z$#{XO`Pz&(a`Z zHp?TjM?BKWA(kKy5B0=0T-)3WR==Uz@)!H*D$4{JIIZ5zJ{`%7*7oTrA!)d!L+ST7 z8DDP=F?Clmv+=12;ckGRW9r3$ZzWMhU0-Oc!}Zh$p6bhOlYvsE$YV@p3we)R5CnA9 zKI^A<6i&{p^+NL>lPnF`P z@BEH!p;e1#-kOcp0!GD6u&TBqX3rTJgFv^dTt`iDQyM|^Xn6tUd|c;ZG@TGiV9opY zA}WN0`$yb|Oe$TFqu`>Nwew`n-JabbdmIYMzDA`dfbXmz#kVZf<(lV>l#PMH-K0hk&>jibucAQ~aw=Jl4`N$8yPh zu3t91W(ZO%27C2uJ%Yh{7`03t5g$2t8|$O3Qh~1xVzU=r8Gm^_IAsaX(xuOiy^er#XuJMPU<*ZcG*D!k^|n^jV<=%YO^L@D2<32&7s zez2a@x`y<94~J!*y(s(}BYP66RjObltTU~|A!de>v4rS+BJu0SIjpN|)OC9bb&-Y`Bb;`mJ^0*@H z&Rb-2-5fS>HJt{9V@qi}Kw4^dV{wA{*9+#+0$8*u=6CsKGP|%su0AY~l_7v9>EdP6 z4uM{WFX2DpX}QWBKuHq6_WOzr#prl>zTQ4jf2DWg86Tzi`3-X0o8- z8X2=8juI>xgs|q!DBcnV6Qb|iHr<2*5!loDxGox&pj^lk-WRJrom5rp$&n;1fdDV5 zj$-wApj4kn)``#m;Owmfs(QO_Q9v3bL}?I2x}>EWq`OO>@>woCcO+OSov*N%Ld3#hK^p_$Oh` z!dcm~G$p0Syfmd8r?7^3CAFi+iFn@29~F8G3_R4!2*%p_166(?m=$^mduy%;ff^W`JA!(T=M;`f7@ zjL}*^!zKk>U}W5x%4598ozTo^vv|ImKi)T2$ZUD2Pb$XXd~~^Rg27ZjTRD7^2U}XS z+&In{k>{XP@?bhv*}ql3dYy>QZn_A=u-wn3Jo{nP{G+8a<3onPrscG~tt0@yaI*Dy z%6@GiS&U&Nm(>N$KUG(ueT!COTIJvL+81f&k!}!Ftxv)*?Kr;=EJmJ1tX|yQxdB~8 zRA)4_8v1bo9Gt$zh9>8|M2X8|n&_h#(#8}?(WULO(b`OU=e(d6N|i)z!cvf9qRnvR zo!a2@JR{g^AI@N-Jpx(+F|g0>Lrxi&Dg!|f z)2zI8>ajhy*yC)~Hxm8-;a3wT`9h-I$u)7=TB z&oO2}$wO=4lpC$~R4#dX$Kxz?v$eWcVrGB)aH!IIQ9R7dKq_`PHtKq6nD4T(7ZsLR z=JTZKr&@e3=UDJGsnI67=iThwJ)+$hDuG+*>F&JyK681GW~F}g;>xF_d|+2rO(kQw z3F6YBD(;c}dU1nhMdvpcJB^KGV(kHTrK|Yfg45&AB{YR-I5r0uzpWiR*O=P{dA`C2_B|78;G`&rEnKGeaXZKR6 z$y7ftf8@l182bS@vN3Lmv3oh~^VUwto=b6d37C9z_njoRMUV@p51&>?zUln{vFFNP z!0HRc^4H8{#A;1+1sXtmwp_^I9S&y^V~kdNoGB&`0{udEm+^2LXEh|v-}zA|5PuFS zwOJg#CF_*5m|m!XFDy@KH;2?_tnOdN9X55Ed@Ni@U)eZQ{5|Kb9Ode_MagJgr1?E% zCp1>@1Wo5N1-%aW1eeZC;gZ@-r<9k*L-rIo#pBnPQa)vMc=SrlL_QhE+FT24p4FBz z1sf_MXNmS?xgjGODMm}%=XA^5)Mu1IQ+nz=H|eBdjs2t7qk5`NuCCpTlsKx?iDKfT zg9j8C+4xS&mLKTZ#?IsJNoqP{t7n;-Px=`XBHvs%mh*ZX&@fpFisek^^0kZ?W%AB^ z8!xt*J&1Z(=WtY|R^!W|CnG9#U^!xz^stU`?7s+mt5xNiQiIikDyvyr%MEM$;Hi*1~=t6i8n*B zk?W+Y-YShH){YchwDmtK`S8X?rx3A$diClOiCBeFq3i{CRS!yLt-PMd`$IrA`66MY zN8WlU6sA8183vLoWzOC}Z7EvvU)&&z{(qwf{2zE$#X9H60JZ#A0(MS3!XKkG@&4B< z!17oF+$U-(zhr<3L~GVs0paPFY;0>~Ya$kKACIGh$zVhfLE!@L*V01^ zuzo9>PZ?qZd<&GWGH6pcN=4c(`zTgIOcJ3J6WDjqU=h}Ij6&oWgnzM+|ARaI_b$&2 z0N@7@r?(`67ixC^? z=OLPQq~WLjQ-yN>{4)w~-n@B7`0CZG78mfdUCo}OSU4`}227uTZ-RRjfVX&!kwx)1 z{QmhBfUGdl0Aa}fYG>ykxB)5x1AspOmc#)k9KNAENz!^x$Xw~p-+#-@V*TyfNwhfe zLZfZwBXFXObxFd%hmB^XBXZyoec(F;wYUELNGuqZxN0)^;y zpZfpeNfjjP;9z+yBCJ1~oBUY~O#B!`{%#a-1fF9_MFsXcR?d%YZME8&iRm|Dq1%Yq zyWtO*yWxKh8D%`AU&469zSELY9$ZlIL5NkH12(;yA13_|(3!Xuy4X--dxuMjqR8d+n!>yyjvKemPt1-zRz}A6UNBM$iSc(q}2jY zR_8i;Pfny@`Yg`fAEYYl^ckN6EO`Jl@BRDt14VwI$HZzVL%gGGR6H|uW4mX1hD@}j ze1Dd#<&oB(!4ohPQBhV7{SXc4chDw6K9t3WQ%k3?QUeAgfrG_Lh484j@~apEmPD=3 zTo%OjpV7`fUgbT}=u0|nYpK*e*a*@c<-_-p=_0F33_jqFl4CDMl&qjMKCjz?RGU|3 zbpUrpGYu8{{P`VwK7)i9@+`ygm&@=bb?P5Z>vS}dU&66yhaCCJ0rLXs2BK zWhuSu)&pW>GB}*Eunz_ELnTH*rgF6LC{Su2L4DbAncRgk>Rc|*+yw#4>~p@N*D~wB z;qo1z*O0}lNTBe@=1-#JR1crzGpAY|cNBPSWQmxQilFi7TuhJ0AnB0IE%&f3u3@v` z-MU}qz*w+$T`C`J!@5+g+%+w88WgDOFxzOQJ?IA;c=yEP?5Z>?mM>HTIvp<&C3)32 zr2^@f17ED|)luaDFe6fNRa#HNVEEiRYMDp8+67aqrS$#6Zw=?%B87Qz_PtcIc?OMg zdkk1@L6Ap#&$d5WVhIfYQb#~ilD5-My9$i;3#Lw}81_!%@YkRE$I`W)&>Pb_4{FCn zHwNU~EK{Vi=%b}Y~ zf8e*@RgVwheC)gae7ru)%AJ=wQB8ikOB0 zGmcXRgE2S`N>Vp^;csEA3sewHT@6zj0HyN@1B&+i2}5IK7X3fG0JKxhxDA49UT@Lp z(YX)lIa^~}y{A}59e7J>Mql&nWu}tQ!}Ke4#u_^lHXTYwqG4_%V%mQxI|rfann4U} z`dm9HB3q+HoSZe~R2-GNkzXDGX*N_~zJ!0-Kv6 z@FKM%D);A#GLFO|>w+YqQc|5TuN8L;a{qKF#7eGy=cifcS{jpvbNT28_HpYq>A1w; z?FAXBH%Q}yYeTO!Sa>@>4mT2=KmHtvVw6R~R+#h=;WBhM?9eNHVU<7pAXftMKm6<` zW_fv~=GHwzcTuOfh$LC`Zh5^IL$fM+cJinP;-5251mZ9$?z!8JdFdf;-f}y;9IcV^ z8wnbgnlSH1&6fGqFW)AKo`i2u;*D>G5{mE60%tw3UEGx!2%w$>7**@Rb|9$#q|*^Sw=Kb+REtF*}Sh34TZ= zmdWV(ap%p^ms-=f6;pB8YFxOW8ug|na~>98i%&CqL+)UNnGuc{ID0UAvq6!uBY zHZL=Yv9sVny2zVT<4S8K&`}MM$NU|(Dj)0+^2~xCN{HEGJ=YkLq^hSzEJG>W^CdS@H-^l?kF?8v+pY(gh&=(Wh4HAWZ`p<>>}_(K2k zJA>*Y|1UMD2#4*nBJW1pt6^6MvAPWLH8qp@CMhHAx-!*{D?LDv$~889bbEM4{cv|A zEjiL|85fQwePkQ&v&GLT&Zl)9)fK@ejF$b#yM9Ofjn+=LINF1Cj21x`DM?BHJ<8_s z$eRoO4vhCcNN(P6bu*r?=sK*&FJTgVvqoIY-RM@}Yyt_Z94C{etwpeWWd;NG{DTHXFh zmD%>Ynem8e6NI`P2&t78Co1GqsrEhcNZ90q-O?Oe3m3A8W|f~Rp{DMp=d31>i)^(_ zQ#x|8Wbhq5$kZhqxi`0z50c856%MQ5cV&Nfl6R|?+hh;dCQjqz;FQ`6xf7UgN8#ru zJ@T4e4=}T$)z5)K8RdoVs>JFGX0vXb+%7$JONwR89_cQ$F~-S#zB;yADOsE>7AF5Sur0Pc6l9EQ^wSxL_QID!DbnMgkGl{>tOY3 zvOwF09^97{vgJ(S7WSradm66jvE@#bt)?6tvn3N;T>yqvxk+;}aPkGw#fW2_D;b7MJvE?MDKgreC%sFEVq-l0kW&UA+CdhR=E9>_3Fn zff~%`s&$}uq8h>KGRbxo65Yu1(w; znGQhgh>XJuBP4*c$T#w^8JQ(xrga$FZ}jY{gDGc_W0514?6H-xB``0z$JDy>)g8LT z^|;ZDW%=!;rIm|rXZf4AC!Uyh@febJM60a{ov*WgwAM<-GFz*zF)MgczR_vhJ{nAv zEM%Tz31-Ykiq^?}Ssc!^eZYBGer-1k?c@;`7_BdZ|8yx<6|?O;5CAxzT4}CgotYra z$7GdL8>7_DBo>`JCqxX6A}wYxrGbz;#Zs_i*R}&+y zVc5!AfEgwkH@9UOu;;lqI*?bn1QVR(R^5M60|~226OPVo`AJz7Ysxg zu|5YMDzZ85T*_7$MyNxF)cjd=v*?+{pov4h1X908`>VZmoteMOxLI+*EJ%WqtXsSL#6f{>dSN)+lzUX~(RUyo2yLG(|YCNLwA+p!@i` zQHZI9udNz_^&}!Nw~Auwk?Y8_Y0laG;;s`r-p0*Yj<{ah=DA&EPcFX#ZKu_Y*C)ge zEuq#f@p@z#=w&^Yva48@h`8zWrt18-YuUb83tzSKUdYP0v*e`qf^|?V}n=pjv3xCJy&!Cwo-g*$pni0~_(?N_Q7`v6`V?P9!?2zs)GB`mB}7kC2BQPhqOBX#jd?&|J*7(z zZ^)VE%FND#zfzhmat7MHaltXZ+eWnxM9k2XvzH8a+nFHAH1P^yQ_t(&&mQ)7Wq^5s zPEwtj!DJ{V%IX_#9JiX6n{^h2lt}A34A68~DMyC0Q@+ z=7lzJ=a@*b*{&HNn;Mp237h3X$-Dj}ErL*9x#pCkcH(1W2?l!#_@=UQNJNZIEfd*> zxTdva>uHBQJ;>M0!NCXN+SBG_!KS(|(CTFR(FvnYLMgW$v&~2cc0Q&>WnSFv>#VQZ z#}^!vuWKT3c1IFNt<)who%L$I1au0>lvXH|PwGw?8mU@JRx@d4E6IAZef*6wIb$t| zMLxyN?JPcEmIcZ{)&3}O#&{kfdw%@>va4AN;yG(LD!I|99x*WBo2$f~O~LwvBPlcF zK{)~EiFMVD&nW-W122S9p7}M5r!!oM9&bI}!)FUZRr1`;F3<5DqZP6ZzY>UdjF}$n z&>j(uE(R4oBsu)zy5-G4tbFpNC!%Wu%NJseByWEjVcbXlYKNRA_fW2Cjb(b@6BZNf zI(=EcF94NYb5lrm`nDUp`+%PZVmClgn=iq(f;CZy;w!^ z1h||p^&qy#I=SaQ#lrAlJ_Sqgi+J#cx;Jm>lUfIXXX5pyZA!s4(zk)cFQt6?u`zrk z8*sb{S4Esc-9?~Wi&6;*y7R{jc}=#AX$@njyaECYVTt$b_hwqrPU=~@+U97s{hAMn z6)E$F?fu!1b^Tp%d3czKY~+lOe9I)NVdp4>!D%|VB;%-7&A*^d71!ePf@iU%gU))tBqO!6~1qJ6OxfX)9Y;>-)g0aEol+SkyZ5m&Fs5 zW@Pj~-xY&io@mQkui+G}mRKs6ia_tb(vR=gdCgb*11GO^%Kvsr)h0R zEiAn@_?W-X6C=OX4-wL0v6&msJ;mb~XD5cDpp@L^A}sGLK`2zGl@%k=KS7l%H zVseDYd+?HNvNG-z#RAp3h-s!0Rdiiuw`!;OD*B@AI_rMAetfELTfQ~wtNVE~i%Nbt zR<>9o-NX4J;SX-ufW7(y)Il~?yHYfsN z(J#T8XE*#e9<2ZiEs9FUabw8vKsBt5*Ta4AYu*jSK2z{>{=s~mxkX#n9Q}(sz7(~O zJ>SJXi%OwCS=j5 zrBvi*NUeiMvE11*l9`1M@E~H+$~wZc#LbtiDGz3(?m>tjeb?TRh)lpy-YS> zSmVR};>&uFr8xesFaK6OJ~M-JQQM8QxOR71%Ht>3`ng|) zO%u8|dY&DqZD1b#nN^}8G}Mn-zV134 zv=sc~cQy1*+VW~?pVKn7GUriCP2pD9uJ=J*DzVNoeW!HcwEYEPa3MNP&+O}!X zA(k{o{}|^jfl%IIF~e0Zq^Hm}RUSk?BK5VP@O=y}NL%t)IwH0xvpHO7kWj(IS}s2E zSSL99W(_#f~cz-G~w+w^sAoe)w{lUH6De-nk>RkDU}7E&gqU zXMJ@7;uLq}W_kidYt02O_Ocz^>YZ&I#bQr}#VJ*RB_S zYR1xn+R!}BHBJQGC;|twR&Np6It6a%EP5?Cn<`kh7<@ZS0gD-vuWa=8v>~&k2jXg8 zUXrZQ2OVV0PoBDKl4qa;B6gfFh}b~5=>K(4#Ra5A{%&b+s?fG&kHSw3Mciz+!Z^q! zneykZvBxDHOTr#NBN%6WP^csa{`~beIm3b)S_$6W<(O{A(h!f8Rob^fwpHr)L(tWn zG;NhO7!M+^jZ{Y*CF`C30%P$SKiN`q^F=nCT10}$IGgUO8e@hnrdbtQ`gAMt>XSqu6xM5t2+vuVf^jrX+N$U0->fl0HQ7`D%#(_jY!^WL^OB?SnJ$t zn4V55m#lAd@48kyTIBIEM0{m`9eobb<-h54e?<+Y3C;W$AorCx2)_{(ouQ5`iR=Xq z1@vV~nmbS-PKRIRSJD3NQwMiW@qAie_G}5q(*Hz>*Ji&yA2LC~YHm}nw>8>aL7_wQ zipCbx=#RQffZ)}ofLyKeJf@o3Af`mJ`rBzLME~hJl~&?C*9vpsNNzIt2KLU_d_T z3N*Zkjg8$B{)Z{b{fpJ;3*aV90<^6VL#X2fP63ofG~3WXFly9@{A(wyM}0q3tiz>7MsjjdcsLmBU7(Huutw_` zkp5ubP$Eem5dJVzfx<$iZaWtzC#OiYL@dQi;QpryWd7O74$bcR@eT}LYP9{8BMMko zmEHj51doU9G{A@b@3j!I0JFB)a+0-l%z7=-PkqUNp!Lo3CSO(H{!3a~Gy~-}Xv4c? zzDYmZck_Gm=;sL_vwQ!=?dy>}Xj@L-h^!T@fXHp4tNUn1)0Ig{z4bY}zDjPxM zPeDUlFr{v5xoU{aF7}-U;M@i9Y_Gylp1G&ZI~ixR3E#hGMX8bqBMH64`^Q^OC=l>1 zV}^ZxTE1?uTp9v>aM<*kn;c628d{7o{q8D*9zc1jEH8fo3=RTq?n~Y0hadKAI0Oat zW9NKt3T7SH&oA$SLcQgSd8m3<47rqrjKH7mQ1s+!hS-Q~_G^IEs@K^l2e76Xe-t1{ z6&Neyd=IUI{%5aHX@fC34A4Z^{!HlwDQX=7)#SyW4ZgHONh~N|dX#T_Fv-M1Ro&+T zhH*ODT(<+l3i-cd9dWIY?9_ohrTPiLyAwCq(6|89wxZFY^jNEHTdi#hEVAjq*TnOw z1UAh}^aTaVD-Zm_F+H_96nv;Q;D%PGBo9eiT6u3xTFvSp{vYqUQC%w9BhN7XjC}Qv zXPdY5;w{m)0`DnJJAn8aNRZ+b0!W7Axhdys(GJiz(vNvs5dqAmi780pxnuzQLwcc6 z!+0o;o@Ihq71YVOfA)e|M~e`fvzm7%MbV033jpYgRYM8`JL0Nongu$zZLLBh6ga3> zRAR~)N-CHp-tB*TmG0RFOehM-;ObKQ#b<;Y4v}QH6#Q^Ap}_Bges_A!{A)_Un~~`bEEoa(D4wJIYAG{Jq^h>>f(74-e_bNQaL%9# z*ZPV{HC3$INi}|{>>(RIrSn-0y_9#fq)o1WyLrXU9g~yaV}j>QQS{yFk*X{_`8U>D z{j|kx##QGJgIlvbFN=}<$RypD1>s>1?SBw3;_B1t9MiqEGQVuj4AC9_WDCN>_8m$Yp6paj(s{>}P zFNNdw85O+2WNt zX9h5reFfPl)y=O_GW%?JT~sfV$vzhu72XJ2Z=CQusSBVbAdrS+kl3 z?i0T7#*(-Fg5Ao>YaUUdIl37UKk}wkWQI8>5w+XOjKe1;H_i(yGt~x)H(^HPXYkLX zU{a-TZ9LX+2GJX`)#3{f2>!7DSVd2wJVmwI^hEXK)O49pO80ecrQ;g^z-Q3shzn%b z;knWLq=EOP8bB%~U)9j?3#R99zQFuVI3&c`CFA@)*>BJKM* zQzRIVLWp(&l$@RG8->M=k*CI(G;gTB>e6D2k$JM#1pGs9p5lUCF~*-5*~0fjz5 zrAeerAw$nMAPmfvrB7o~Dk~OlBs2E-O?mrG<1e~-tgUP12`pq;5`W;86l(aYfPvoGJ4{D-t=FKvodJCZ|0x1NsNjFG>(Us#Pg2nke$|57>oUy;R@c}4fR-E zGyWo8dB}HOrJDGdT%(dXGt=pO)F0!xaIPemerjlK?*Ni@DSDd);lMM#_AB-G>r#Bq z8slTT#A$=~KdwFH5}n99y~4o)2&v%M-E*VnsPsh6E^mPbySq4Bk8(Qij*P909cj8T z>>`=B;u4S02e_6A5E4G6;GMX}lHO`jf_FIy74Nr}kVS9tTd%TF@0%m0B+r8M)Y7qt`5uIpX;_(luT4FK3b6e#x zo)-DFNVO5*?%(1EmV?gX#I+s!L9Yf?v{~=Y+ujM-8){Xt_@hD(3k_LvE;7T@Ld~(AK6l9ER?X9FQ`ua{UFg zs#+qm84Q4_Ai(I}T*o8Wcs;8$izE>0r(@eF&e*)5?zfc-3UJM)B!5ayq_%rcVK6iGzZrO-EJD*p zV6w$vpI1yTD-xegKAS9f@G!1xTkSb4Q}a9eeePysh{fv=)+1TrhY}mM2lXdnZEBpKc))lYgL!_@iIDYhAzR?JQ+wYCvK0)Iu zLbo%se=difhFg`iEns0Cf*?anQ+KKtvuk*36Y(avs7?tk#kph3UIT+i#b_H7UoQ+Y zarM%a3I&;f^%h@F?ht)FwzJVP;OH!L@?^x{PgUXExwj6leOmm@!J}OfxXX8r(1pSC zWS|VloS4U20Wwyr$dYjwJ(1xIB*uEL;#K}r74P_wbp2vE=g`RYJ(MA~dW@9zyRiy- z4w9*48%M(FZPTAxM5=7g`cmPIH$xuVv~GujLs`WU4dD&iU@3-wC)e38m6`q{vwrnY zX3aYn&)ID==e|nGg;$$pqYW(1lz~_u#+|J)XjkrZ*>UXN(xI?-WI4$fn__M#dX>HF zKWqL~1nXg(^-Ynf!l?j={(L{NI6d~>-=qumquj1|YhYuUaRM9|r&0J1oDDYXOI`@= z&H3QrVKEP4fKmX0+S*9h0)T+sUS%sdiA~yILwtRH5TJ^EPOr_Z zIVj)cvW0nb|FiJw{o7v!cYH0?c4C#cwy_`ol|!=J-h#t~c|2B*vNK*vu(Q_~?x`=) z9MY|t6Ao7u0MNcl-|L@m1e#6z{cgN_HlCwU%uOI*<5>9;E0D{!J^R(`@QQE|Qo&qb zyS5gH=T+bQ#!?CW@k`Y2XOpaN=8XKjATF1Uj34Ih3)0bb|6l=IvEpb85Wtma+Zy*s z+ZEj1Y_Y&AC8qYrQ;T__>XTqt=&_A$my(%MUF&d5jk3qI5b=7B5X&XVz`-BfXL)IrcF?8O z`D75sldQe0y!tDtw6_UjNUjBf+wahp+l+T&et{+gD$N zm?oDzjXGIxqM>2%@IPTi6BC^n0^ezrf08u92S;39SGBX`-f9)!Kh#g}cFjP7d{d)8R4J`A>2-VIm?b z`n3xAKhxL0w?7dKkmADr+btBVdu(={L#d8BGA+vQl|kxCn2mR(er7l4pcq51DlnZ-}_Rb~Nfdg1l6KuL$g>AL;+FpjiLf zBvs%tD^@w%7uK5o?3Ki7ckl#$GdPX~6s5KJr zK2@o(V!8ANB8YT@blZ8OI=#KGcYen|ZhU)U+U~jtNna7!XusL>6(w?^Dm5!nbD;yj zHDn&uIBj%RoilSC;ua@w+#I2BvVa8pHD4ud@3zUgH4%oeub8G_4I0IEe6>-aEM-IU zpMY<_at|4WBVtg2^KS4$U}9?CAM+@MU4(yUO5YW4QeV&vyNHTMa((6Rqu1fsoc0}k zxRWLk3zD5yJc^XF%-L=6egBn#(=?uGgd_1AM1JE{3mEV^1O|MDmA185c2unD<1N1I z$>+*1?5Q#c*AN22bqYY{p`D(^HN#XZsej`whUXGzOIf$PowT~r5lgy>6Ii3Xma8qk zKPcaiFJ%4I0Wy6$CCr(QUqAY?SM4ZXv_YA2)9c9Vy;j4MD~KL{Jl;uG`e0Ja=YD&S z(0;VZ1Vv>!)9N1G&U2lk*2UtfXBF-I@gUl}G^tG_0;TO{FKHz5X8-rc8RpdMe0K8*&AB4QvxS~Z-R~2%cxjF9=*ii-ZFPuGWyd`i z9BTWK)Ff)$iCVxEmykA+r2fmSE>4NVNmrK%io1t)h*AnCbF=SN{7sbZQdI7K<4~r-d$@1q zVPa}|$iYxp)jD4B^wC|gLN?%?mrx3cYH^1XB8jF3ZwmFnNNBD15;zbK6E z`4>pA7dT;{bxJI({J8#S!aA)U1Gq*#&4v*v+So1)64QT^kLZtNlM)7+7U9c$tTGIM z+BXMafe5;+YQV3A+tYWoBf9cmEUKfqf3c_{kN(?46>78!*Ya&AC$@M+V=+HFscu}0 zW%Ilxke@Pgn|+Kz!?9tZ|E(EK_8ZGOM}^uY@!R!RXRvS>*#g7jJGEbZ*MZA{*AWX5 zlGI!+SG zkUh+X?xBrzV{D-Hsn7Ss0d;;lo6a>Rr@FwM#4>8VO_f2{F}&hc{fywpka4$vY7-MO zyw0&Iuej2{)z%_kdeTniRG^(cS-6(Z;vl=2YJq@ocImowqv`VE#$iz=;z|s( z*}Nx{zW`=$v$*s6b?js+lUfo?AZ-r!`@s4ju#l#);{jwnp;ruv%Q($8^`UCz?E)#W zgKBfN3%($Esoihfa2N;Oz6*A53z`wu%N~0QK@36AdrfPcx8?))t~+@=_jaX11UVxO zvwR2hIv$Vx_*F6-eOS95dUg&{@axaE{-p_w`@?KAXCLCN)E&r{f`J@N@lk~yY5ZTw zHbgOx6k0vQBSYEwD9$nema+@Tyh_EnDdWpl@Ff;IHm&OgU^i{`49WtmEH<<`k@rEd zFWI#wKiZOH0Yoh5UeWFM)^0ayuDM7Z%KN!B-2~raFtZS-g79#b+FykQ3piBBiC1$Kmiihg-N|@C$Y1G>xV@$(vFupc?&gKn&vk@I-2$!n||G z@99!WzY6-OQ76U!;iL+L^pwvs_}fJ8)#K{8876dMPpZ|EbrjqSi;7RyYO6a0@oVZJ zwe5L7vAq#+x#?PDSr|2_q1vjYFqEMEjGLwwbT4K#!F*$zc7NL3#&H1I_pkh+6Mc9j zV&~e!<`BF>ooP);tf-3bdgu#vbbrenOb|X}(azH0{pjb&bZZ&Ma@=eJ>0h-{dI2km zE2OQfR~Brzj3Z^Mf@7cg;Hrsk`xH7vS+5VY(vZf?NWA>!I?1u-Uqjn=cVbe#o2Io| zvYuH!cW`r;%<8q;aUS6+I(7)YV)lc3etIpwuSh&<*1b5CX1%l38MoTt z3Gat$F#TYlB~aCs2c7`)U#BJ-_RIbvmd$wLey}yG7?lhz71FI|(YB(NO{P{YJ##Ti zD45`H8(sJ>D2Bm6Gz#l~f*5!}?mnE7&*9)dcD1lel~R=1!*W65|4{!v(b-0h&cW(+ zQM|Es%&5zjs%{Y@*2OEe-^3qipIW!=^rlvO&DygOO+YZJ(*u zOOFcL+PVbQmcezpJCh@#4d*_i1uyF{fI*kh7{kp^VHrMK79XMFp&Gs;)%8KIzFPhP zn`%(=$T@#WBu7#DKua0L)(6{~Hs(Ha=-Z%6>54>LJr1a_T_!%UxUH|+4I$c`^~9#q;%iNbxq`;mYr9QTmQ|&Rj5r z-o2y!?$BMSRkPVOBSXVbq=%z(;fv)C3|O&Usq(5WVutVj284;>QFvK1{Iud2*7$PO z8X}x?elnNCP{}Y)^BRZ$7sc_ONu@%f_R6}gEz_7VQTC2F(eTWt9)urJ?1D%E@e33SjU4gBbzc zTEvibz1CC=!2yuUfDGJTYE?NYyZY9=%j0fH+*#T;?-gwS(JP5B?)V=JcZ|`fxU=f) zj7zirL5f}%=>SOY#+6q=J36quQ3YEi{$_z{RIYN@1mgUuj;Y{n7Y|=^ZcgU?x^8g~j8|!&s%Op1CZLlUYzdZ@RemNk3qRE* zf?r=u-u|)<3fV|^&lAh6EEaAN7qIXj#0S?n_v}JdD6=W9aYpVhw*MjzGxYZKB}86F z5+Zj6Z6KX)A5&gjmnh1{O67-^NYUfrEcDPlo6htG#hk3&r$4HzbO&s?=h^}E5Gw_|1e-7L!A(D zoN}NVJo({g__r-l55p_0fC)Vn$a{rJhB}Ms3^YMmPN}MP?Cbo&q`AnvA561r3ttgm z2>ycwycMLeib;?G)yT6t_(fA;Q7F!;ru9X+JLPzFKXM zv3q`CZhAL8`@I^UW1I1$u9GNF1}E3I&r9by zifp(jx&YmS=-j81{Z_KM(e|jV$F(!KJwh^TqK`tIQ$d?oBz>Ol7&}zEZ^R#ag!(&x zd}@Yi4}8^p+kgqY!A5ymz{^V?C2#5 zs|byVqe2!Z#}dtXUVfh{TojJ9g};tw=;FjZ;tl?nIz%wHkeG*sGHzA6-djO}_S2iO zB*Io(#23w%!0Xs3=<88Xq#<+@%*+iFQC5t6qmrLCp3IGUv3Yl8HZg~LzwvHB>TGj> zYT>QlZ@7OwptDJ}4*QD&GtM(Te((t_V%&E1j}KkhlNIa*m8FfMpI+LPYaPY z{jP2s=WV~5IfYU3Bs)@R3bZ0UNIW(U%Bk=#|2-<#4h^$#h+dcF<}2)2tLHj-QRs?1 zU>0hs-Q!^+i36IUPNzl!SYOk9_^r6mrBW&DCD=S836YSTFS1Teb zzu3J)d#LtQ^~5(Il|W0ttbPbFn>ZEjjEAx{n+9R&)|Q?%6?A_6-YAyyzY)cjmBuC<*tySF8UgZEjqjV*(M1^YUAGQ?-empv! zmSO<&i$ko9FvopXs=oN*<>YNCa(U;P%dh2msIE%0@qA~&Vi16#zSKUP5{z=H^PQ0~ zX>YGS8|`A}B!aBSbCHs@g(HNy#@FQ>!)+wJLp_^!+&UCzpneWtLfP>`Ce?^Iqbi}2 z#<)!UB0OHt?!`zqol;b=0C&FtfAWjAx}#zcl;6GQRAN!S&_ht5*G}%u0t+|Fkqx4x ze3q6)!UQ-t%XJt3)HflwBK&m`8ljyIzr9U3rKQehDx(N(`pHXSg4ret+iCi%B?3cc z{s_^nxCjYVEO*dS8W zXn@8TsRfoD!3tG{}ZWgqd&q=7~YMpMayA$J-6zg+$MhZ zsg)HTov7LiMm?>wp5AVYjop`SB6}qIcKUblH*!8jy@(dzfDg{P+YYTODf!ZreFQ8h zzrji^n5CTp@dSBGaEl4QfZqdpcg6tUm6t|-nk*=2WcbBU08 zo)KelZmhsd(y6NBQwuq;;xCI<67{lo!^bObL$0tHmf)d?_vO^HpPdR=R<%2T06Si`5hdG0gxA=%>OVeP#a&EwX*I`uc&DaX*5()#F2Q-UZ4Cr* z^p?$zpn3b83O$vf>%@k;?d0)Sc#2;>X4rE&1RSNcw6khi?ct6;*5tD0Rl6g>2yq$InaDPgNxXSVz3$ChfbSZ z-Q0^sjgB)wXojw^HiMuW&je==w-zV1M8cTI807@_X*u?@k+~}Qh6KKw0l{2Co zD20p?Z_+XQ_ZXW2O%Ea5< z>3b{bte1D(?tF~!VLcBXV(7g(RLaY4n5Yh6AjCn+LK?{GDwU`Ns(wwio`v_6Z#64w z2XF-!cUdtPhERSVc0?|3UcrQVW&qX9FKW7_L(t}}_^Dx$+os2<`WR*X;_Vl$N04Tg zBZld=`?qxY?PF)$qG154iVdaw*WTT(x5!SS*6WnWcawQ*SK^pe&yHc<&@3L^A##RXQ>yh-5cU_@m>*X z_b&tt^q2h0mV$!%w+=dxkMkLlouCjA4Kn{Uz@_{@MZ1E3eFW=}fWAckRnGg*7E*&w zc;f%i2_yc!p{$okcWfvBDG>g@>2Fz1uWomHZvKZl1cjen4~Jp{u=Su>BT6eeG_#I4 zpN<-z!ErOg{{+@AdYrZ!0<@o*SallzpG`Ca_3qSk%{xtGT6sN0jPnu0c6W!##I#d5 z&n91>BeF96g|jDu0rdU3bZ~;CZV+;QjwZ)X|D&{~W<~Fb=1KHuRWCl43_s6J*PHfV zUhe?c3}}p{I{z52R`;p9H=dS}_x$_rq-bF8LhX^Bd-29{a}8vlR2V-&ZvvIE)5(nT zdFY|6ecRv}Qo^etmzJ}LfNo)c%pmObC!Ll7WaIi<8vM2(gSou;Mj+yT-Wedk0r0-z z*3d^dAu3Kd8G%w&Ezx$?rD0p5e~kwst+hzchwaz6<}<;T6C$wxhWRJ{n%PfC0_tT= z62gDaiT`f6%qRdh7{9~j0A;49LvD%fY6s8(;hFIz@ZQbRI^?Rc9_(_r^>(DF<#c=2 znOk6*=mjA=fm#XRUZxYM<|dftH$77+OrM281Np=t#OJvzn z>Q1Bu+6LkSZsN1+p>Lh~ipgKhQQ^or{*U&~E2@cb(ZT_w2?C0AL5fHTAOZmt2t^R- zRV1NAO6a``geF~zAXShqMSAZY=|!rP(5oPkBE8;0&$;J3oOPe>%U$cfC9@{~n*5Xe z$?W;|-XVBEjjnZs!(EhY;X|aU#eQb3*!bq7af$|q_Mi|21m6x@n61&+EzX@3=q4== zcZSyFW<;fJDxIrTpLN8^EJlPz*PO|vsZ2AoN%mYNMHSmRq;AR=`gUyg=M(g^CjY>j zCp}vEybKrJSJSIOSU#Q6t#A2LWqaOS_rf{A1$=>85*{GKbEHd;VkwmiAigT@@ezsU zHM7@OoU!f}r?HqmcP^JXxHxjTxYQGf1n$&QE;4!tAxRx#ALy)90M{$YTx30fad-R` zqVekT?CjuY&cHAq(Mmf2ycNO9JC8M$c29nZ8eK{j$~OEFugxUOUh-%2ng^kWWs{UE z>wa%_Vxu)MPaZ3~hUj^UphpXS>DE(&#hLc@nK#j>6fxCi2&O5j85E)cbgg3kG{OsfIyp|7pPZbrCNeT+j3Lpk#SZ9NR$UpHQT&mp-N*F7j zv${)_@pYA|#jH+>LHgWLQ-MWeAj1ANYyQvnv?F|e#v+-+hZyukwJm~My~Jc7QPFSy z^03+=8zoOU+0-}~($U1iu+^Ps8YO7mEiUws0W8;cxlt1sJ&+*2)fcWZ`*4WtyQE;H zebJVIb5I{%61Vv$A+jM;-4UN9=HI*V@!kPKiLVEL@VE~4zWXTtNU*yOZ~{qx5pg=T zKVi!Xl$E3L+Qp^ue9@mE^rC_X$j#odoac-Y3f><5HZlC%Bc2ADbt|=WZ-8Q9dFFtX#OcU+CHPQFq>?U4;Pi9n`Fp#JdGpU7mM&f$Q`lj~rSjyaD<=Mtg8|-O3 zb~&N!S>&-XQDwCr1Umorp66)Q$HULA?GBDg$mKC(nok3O7vZ8%}V6aRn~dcDnG%w zJ{+*YV6|dL=Qdr*C}{#XgXZQ+;hdTI$P+%M!0`TpR_&~Wv)?|S|etDZXqA)VuvAL?$bw`oY$}` z@1jh5vg9=^=xJL%wU>Fy#J!-MV0$fRD@4;lTPoUjY{KrPR1j5OEzHF?W5?U`8+*jM zqc8S7pNCD!EQP!6#5sz{Wj`Ff7Pd<%Xr&Dw@eI6oa}~J>6P@D}rN39f{mSo6=X<4E zYlwK9Cw?EMLB;<#E#-?%fQzE1uTMJ+e~gO#C}c$G*%iYp{kLLU%gk63O1;`RzePfJ zhWUxYo>2r-G7CMw%wPU<5iWNYMf#HBQTS%|=Y?Ks$+1eIo=M+xwAa=*3q3(7;wLTV zqiKRgC8@aP9t-^+{12Hzp%IXc&M<_|T4oBcRJo<#`5|XK1vS>}lq>}IXl-%Yndv}* zTZY?JU!HsmB7FnqbhgCpoW@`)Nj=9pJ;cz}^#e$GE?tokOj(9L zn6C+$`@S~m_7SI-r2GCh5VXMXT_=aK>--Jo$iADLqV>Q&hW!>bri7xy{V?gy23W4B zF~{koN=mFy!fdv=vNMHpp|3J26#YBqdvaCL$EBv%9~U+$Oaexp@(DE(Pkh9I1i^`r zSABS~fHukzZy}N0SD!ziCj;~uG-QIH1Z+!a>e?z&f_ zKK{aYT^P^p>Quu|l`!SVORAyvOb+E0lD-`Fc$<+I!kmpEhqMUH-#+dabdD|+)-t6P zmnK$#-K!-D)ptyL&(}^w*jR0eYBE2V5Iu#|?ffW)&-1qTX^N9>)0w(|+~gUr{`z67 z)6VHkq(Yt~X0pStS7dhK4ZU`_;ZS4`00)@8$pH=l`N z^7B{fMR2Qq=nLYP>T=u>a=e-r;p1LxxMxwEXnqmt8EQ+d0jB+-1}S_ZT6?FJZKL>v z*VSw6%_6gx;fgq`ic#Tm?J^tJjRx=|a*9jhOp0FDQtL>FvAIq`F=3Xm6I)?XEm{oo z%wr(y7EW^yI2@M!4J#SiVgM?8{7K9t0Q^LSeIVVfH_Kue&Ve&97(HRcCJfNl&SJG^ z+D2b}CH`oju0ww`&~&TIaO-|F+Yccb`*-bezc`1*DY2WqF`vB|yw*q9sOHeyBrG-KllH`umykU(fomz#y^w2=9kxD^WlWrF6_ zPbW72y-V5XgI zqWdaz&l+=BcHd^F<6^JOlOciMR3WDys>2UNS&H&6=KQX>qD^~!CLxe%WiRnozvNs3 zIr{Y1LG}}gIBvbjkpyC~T(MA0!Emp&l);9`u7T&mu|HipF+2J|i}cSXglTjP!nqhMKmM z_~#Z!dFY6rx}0QvOi)|a7#3GGNu}PN-0CIowIg+_v<-0>TUy7zfZiHODaQE0r)(kk zoP^i0d&HE=h^--jHmn*hX z16;Y683mi)9AoP_1Nqg{4mrAEiz5siZeduVU*cm$#eHJt-O|D1bv)npT`V_v#%*mJNwOT#%c>wa*q) z7^7~4*bo^ySHf^c(owGXP4oVevyg9zVCc0aY_A(LEVOUA4T_Qw{NT--DPOhOPR$YN z{5|p872tTNyw>jkDrRL*R;NR@>5Rqwl*J#CBawR~;lfbiJ|c;4{B+bh0tCa64{h75 zjWpw*>rot_snT%-)?j(!UANVBqrCB?3t`6cxCc7d>Q#Q6xOuOcjJCP!)1km8pECBq zjHyo@*Az#MDYcChFeyd_pGXfESXZ67*Rk>+IcwEpbEs&>2mjW*y)P}J)Z1d7qNUa% ziUy39PTLU>sz@s5pC^t8`YlY!Q`paX=#4Bt*Dur)@X?!GT2ZSC!bceP)#o2l-ou*t zQ4%IwCixJV01tCi>l~Tqihp}R>xsYwBm4ykn>mZ$oGHeC zRDU7jPJJ%Xssg8_qf~BN?=e08{-d(~b449_p8_n;YW9FT%hr&!B-dAZM^*aJAH%N> z)2nF@0`O_|+5jfpF2|~bP0!Y!BAKM$dc_^8j@W2FCxTzyD=~}VD zlE@GMN(>_=@AhV%$sTM@5O0p71N%4j;cSBQGBTtpDE|@WW)_*Zl-0T&_QM&YM8D}` z>hC^WM>mFC;jbvTRxd8a0P*4gE+2@a4`l0{Z8tZYocf?F1`;8_zdNhMery4)_6Xsk zH*hVKPj@IW4zdf+MqR%)=FO<@$-u}Uah;JthKp#wnVt9La~=}V2oTcW?G4vyY@Ikv zI(5|yK2=GDdX6dy5em?L#AU!3b|Ii85T}N;i|!!lNe+&fy|;MH$#8BOg2+V>&0V0U zz-%69yl&^uW08#jd}QxmVEI%@_C!}_eOpEsg+QFP?tpmBGOVz5?FlH~RQx>J-b*!O z$Tmpz%YtSc)Bpi_K!raq|FQ-W{-rG?z>;vun*SDyFn{yv4DQkwo{M>C3E&pO zttrg-{^}KJO2I(lpi-yy$?9#Em3g48^g*JJR$IW5y zaCxD!y|X`>VXi55sQpqo!Yp#l?W7R&PYTn&5lL4fHI>kO+$FAmId|0dq(;K20vH;- z@WR)uD1QECBn&i0G4T;i8zBtHC(~Ru$$#4>{v!^mDh?NSxt4j%I<6_wYmb>3tr+e! zGxQ~}aR{%n>UFD<(Ch=B?AF|4Yw}c%>s|f+T?o5=@xQ5ium8$u|3lG%|Nrj-%-DZC z8-M2V|LoLF6TXQNVbgA0`XoEHR$R72#+8GSrgyQ+d&5G44qb7+S{i^OffBr1=0y6}m-W+oAxK#HzF<}3 z4m4iNw#`JgWd*C&rR%wY0)pQ*lHdy$I7b`t)uLOPT|-Dazw5nKBigYy?9seFB2dx+ z1i~qola|!1R-@~6C~E*mrr-4VZm?KA;5_s9C_`Da7qW=i7hHfuoF{$~#NE2lR>L=q zAG{k;F>bF#p)HZSCvGk(gl7#-NwicYVfEj#Dail_TW5~xwES!@4vp{&#gYl_bbY^n zm<69WJLxPg9ur$TJ9riGH?09|)l1snA%k~pOUbM@Jc62Fu**J2@$bKdF>r=f?DA4Kn`&_R z*lj-6InRX>?(ai5EhCSf=h|aEQ9GQja$rp)i;fiKk-KXn!g(F)$2Kja7emiZM`n5J zCD8DwYaL>%X-Esd>C+%@`_ATg@v~g?$b74f-&;*=KO6q6U_JyAC20>?CDXRjMBZRc`Ns{o|8AhpAJM#4 zFly}3ht>g)30<-nXt?ca6_la^;AR|nv?`-wRt+cEdAju@CvBsoQf^hktm9c>vuTR% zLAE;rdzMxyY*pXQW!eMKc|cP{cGUU&OaV6pSIGE#tW!vDV8QD z=GIy5yfHU}D=WHIl5B?|bELJGDD`Uy6K9=`eh_{_~MDC92n~t-M;u zY9$`VLCL!RAu7qu)=4a;JbL3GV68_Vb0E@j7?i_b{Id6c!u13;+Z4@j2VEKRQfuaq z@7T_)<|_z!G-k+MC&YTaO~&>9?%6cD*|h&>aXHrd?JK?lMdVk%Q*IqNFXX$v!E@{$ z!E`+mp~$t3#K-@STj2%4|LPM_VC1W-(5Dl_zyrMNuP+X0?Ucu=>|xF*umvP1qbyw{ I_4@690a*gW0{{R3 literal 0 HcmV?d00001 diff --git a/src/frontend/src/content/docs/integrations/databases/efcore/migrations.mdx b/src/frontend/src/content/docs/integrations/databases/efcore/migrations.mdx index a777f632c..ae3fce374 100644 --- a/src/frontend/src/content/docs/integrations/databases/efcore/migrations.mdx +++ b/src/frontend/src/content/docs/integrations/databases/efcore/migrations.mdx @@ -3,10 +3,11 @@ title: Apply EF Core migrations in Aspire description: Learn about how to to apply Entity Framework Core migrations in Aspire. --- -import { Image } from 'astro:assets'; import { Code, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; import { Kbd } from 'starlight-kbd/components' -import dashboardPostMigrationImage from '@assets/integrations/efcore/dashboard-post-migration.png'; +import ThemeImage from '@components/ThemeImage.astro'; +import dashboardPostMigrationDark from '@assets/integrations/efcore/dashboard-post-migration-dark.png'; +import dashboardPostMigrationLight from '@assets/integrations/efcore/dashboard-post-migration-light.png'; Since Aspire projects use a containerized architecture, databases are ephemeral and can be recreated at any time. Entity Framework Core (EF Core) uses a feature called [migrations](https://learn.microsoft.com/ef/core/managing-schemas/migrations) to create and update database schemas. Since databases are recreated when the app starts, you need to apply migrations to initialize the database schema each time your app starts. This is accomplished by registering a migration service project in your app that runs migrations during startup. @@ -509,10 +510,10 @@ Now that the migration service is configured, run the app to test the migrations 1. Run the app and observe the `SupportTicketApi` dashboard. 1. After a short wait, the `migrations` service state will display **Finished**. - A screenshot of the Aspire dashboard with the migration service in a Finished state. + 1. Select the `Console logs` icon on the migration service to investigate the logs showing the SQL commands that were executed. diff --git a/src/frontend/src/data/aspire-integrations.json b/src/frontend/src/data/aspire-integrations.json index 41083afc9..3d5cc70d2 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": 22507, + "downloads": 22615, "version": "13.1.1-preview.1.26105.8" }, { @@ -33,7 +33,7 @@ "ai", "openai" ], - "downloads": 464281, + "downloads": 464811, "version": "13.1.1-preview.1.26105.8" }, { @@ -52,7 +52,7 @@ "table", "storage" ], - "downloads": 3198133, + "downloads": 3216949, "version": "13.1.1" }, { @@ -72,7 +72,7 @@ "messaging", "eventing" ], - "downloads": 312122, + "downloads": 312400, "version": "13.1.1" }, { @@ -92,7 +92,7 @@ "messaging", "eventing" ], - "downloads": 780066, + "downloads": 780975, "version": "13.1.1" }, { @@ -112,7 +112,7 @@ "pubsub", "messaging" ], - "downloads": 33324, + "downloads": 33350, "version": "13.1.1" }, { @@ -134,7 +134,7 @@ "database", "data" ], - "downloads": 50344, + "downloads": 50419, "version": "13.1.1" }, { @@ -161,7 +161,7 @@ "npgsql", "sql" ], - "downloads": 107272, + "downloads": 107449, "version": "13.1.1" }, { @@ -180,7 +180,7 @@ "ai", "ai-search" ], - "downloads": 228670, + "downloads": 229392, "version": "13.1.1" }, { @@ -199,7 +199,7 @@ "secrets", "security" ], - "downloads": 734973, + "downloads": 735784, "version": "13.1.1" }, { @@ -218,7 +218,7 @@ "blobs", "blob" ], - "downloads": 3548908, + "downloads": 3562099, "version": "13.1.1" }, { @@ -238,7 +238,7 @@ "queues", "messaging" ], - "downloads": 1259198, + "downloads": 1270983, "version": "13.1.1" }, { @@ -256,7 +256,7 @@ "messaging", "eventing" ], - "downloads": 1954024, + "downloads": 1961780, "version": "13.1.1" }, { @@ -272,13 +272,13 @@ "cloud", "elasticsearch" ], - "downloads": 44070, + "downloads": 44119, "version": "13.1.0" }, { "title": "Aspire.Hosting.AWS", "description": "Add support for provisioning AWS application resources and configuring the AWS SDK for .NET.", - "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.aws/9.4.0/icon", + "icon": "https://api.nuget.org/v3-flatcontainer/aspire.hosting.aws/9.4.1/icon", "href": "https://www.nuget.org/packages/Aspire.Hosting.AWS", "tags": [ "aspire", @@ -286,8 +286,8 @@ "hosting", "aws" ], - "downloads": 252895, - "version": "9.4.0" + "downloads": 253244, + "version": "9.4.1" }, { "title": "Aspire.Hosting.Azure.AIFoundry", @@ -306,7 +306,7 @@ "ai-search", "cloud" ], - "downloads": 30045, + "downloads": 30156, "version": "13.1.1-preview.1.26105.8" }, { @@ -322,7 +322,7 @@ "configuration", "cloud" ], - "downloads": 190896, + "downloads": 191278, "version": "13.1.1" }, { @@ -339,7 +339,7 @@ "cloud", "appcontainers" ], - "downloads": 397860, + "downloads": 398307, "version": "13.1.1" }, { @@ -357,7 +357,7 @@ "cloud", "applicationinsights" ], - "downloads": 435487, + "downloads": 435963, "version": "13.1.1" }, { @@ -373,7 +373,7 @@ "cloud", "appservice" ], - "downloads": 19745, + "downloads": 19783, "version": "13.1.1-preview.1.26105.8" }, { @@ -393,7 +393,7 @@ "services", "cloud" ], - "downloads": 451761, + "downloads": 452341, "version": "13.1.1" }, { @@ -410,7 +410,7 @@ "registry", "cloud" ], - "downloads": 102565, + "downloads": 102945, "version": "13.1.1" }, { @@ -429,7 +429,7 @@ "data", "nosql" ], - "downloads": 556485, + "downloads": 557348, "version": "13.1.1" }, { @@ -447,7 +447,7 @@ "eventing", "cloud" ], - "downloads": 171575, + "downloads": 171891, "version": "13.1.1" }, { @@ -464,7 +464,7 @@ "serverless", "cloud" ], - "downloads": 607292, + "downloads": 608288, "version": "13.1.1" }, { @@ -482,7 +482,7 @@ "secrets", "cloud" ], - "downloads": 1077736, + "downloads": 1079631, "version": "13.1.1" }, { @@ -500,7 +500,7 @@ "data", "cloud" ], - "downloads": 2851, + "downloads": 2853, "version": "13.1.1-preview.1.26105.8" }, { @@ -517,7 +517,7 @@ "observability", "cloud" ], - "downloads": 597526, + "downloads": 598316, "version": "13.1.1" }, { @@ -535,7 +535,7 @@ "data", "cloud" ], - "downloads": 269282, + "downloads": 269717, "version": "13.1.1" }, { @@ -553,7 +553,7 @@ "caching", "cloud" ], - "downloads": 260083, + "downloads": 260468, "version": "13.1.1" }, { @@ -571,7 +571,7 @@ "ai-search", "cloud" ], - "downloads": 143443, + "downloads": 143633, "version": "13.1.1" }, { @@ -589,7 +589,7 @@ "eventing", "cloud" ], - "downloads": 729917, + "downloads": 731137, "version": "13.1.1" }, { @@ -606,7 +606,7 @@ "realtime", "cloud" ], - "downloads": 95108, + "downloads": 95261, "version": "13.1.1" }, { @@ -624,7 +624,7 @@ "data", "cloud" ], - "downloads": 371643, + "downloads": 372073, "version": "13.1.1" }, { @@ -643,7 +643,7 @@ "table", "cloud" ], - "downloads": 2202313, + "downloads": 2205565, "version": "13.1.1" }, { @@ -662,7 +662,7 @@ "messaging", "cloud" ], - "downloads": 22361, + "downloads": 22368, "version": "13.1.1" }, { @@ -675,7 +675,7 @@ "hosting", "devtunnels" ], - "downloads": 69476, + "downloads": 69687, "version": "13.1.1" }, { @@ -689,7 +689,7 @@ "docker", "docker-compose" ], - "downloads": 208343, + "downloads": 208797, "version": "13.1.1-preview.1.26105.8" }, { @@ -703,7 +703,7 @@ "hosting", "elasticsearch" ], - "downloads": 123424, + "downloads": 123736, "version": "13.1.0" }, { @@ -719,7 +719,7 @@ "cache", "caching" ], - "downloads": 47857, + "downloads": 47910, "version": "13.1.1" }, { @@ -735,7 +735,7 @@ "models", "ai" ], - "downloads": 8921, + "downloads": 8943, "version": "13.1.1" }, { @@ -753,7 +753,7 @@ "framework", "runtime" ], - "downloads": 285992, + "downloads": 288001, "version": "13.1.1" }, { @@ -769,7 +769,7 @@ "messaging", "eventing" ], - "downloads": 461211, + "downloads": 461677, "version": "13.1.1" }, { @@ -786,7 +786,7 @@ "identity", "security" ], - "downloads": 307859, + "downloads": 308214, "version": "13.1.1-preview.1.26105.8" }, { @@ -799,7 +799,7 @@ "hosting", "kubernetes" ], - "downloads": 44433, + "downloads": 44564, "version": "13.1.1-preview.1.26105.8" }, { @@ -812,7 +812,7 @@ "maui", "hosting" ], - "downloads": 7510, + "downloads": 7539, "version": "13.1.1-preview.1.26105.8" }, { @@ -831,7 +831,7 @@ "data", "ai-search" ], - "downloads": 8757, + "downloads": 8758, "version": "13.1.1" }, { @@ -847,7 +847,7 @@ "database", "data" ], - "downloads": 370375, + "downloads": 370805, "version": "13.1.1" }, { @@ -863,7 +863,7 @@ "database", "data" ], - "downloads": 174143, + "downloads": 174401, "version": "13.1.1" }, { @@ -879,7 +879,7 @@ "messaging", "eventing" ], - "downloads": 61130, + "downloads": 61212, "version": "13.1.1" }, { @@ -894,7 +894,7 @@ "openai", "ai" ], - "downloads": 19334, + "downloads": 19347, "version": "13.1.1" }, { @@ -911,7 +911,7 @@ "database", "data" ], - "downloads": 33896, + "downloads": 33919, "version": "13.1.1" }, { @@ -927,7 +927,7 @@ "messaging", "eventing" ], - "downloads": 190839, + "downloads": 191022, "version": "13.1.1" }, { @@ -946,7 +946,7 @@ "database", "data" ], - "downloads": 2536204, + "downloads": 2540376, "version": "13.1.1" }, { @@ -962,7 +962,7 @@ "framework", "runtime" ], - "downloads": 135417, + "downloads": 135531, "version": "13.1.1" }, { @@ -980,7 +980,7 @@ "ai-search", "data" ], - "downloads": 98833, + "downloads": 98877, "version": "13.1.1" }, { @@ -996,7 +996,7 @@ "messaging", "eventing" ], - "downloads": 1250627, + "downloads": 1252095, "version": "13.1.1" }, { @@ -1012,7 +1012,7 @@ "cache", "caching" ], - "downloads": 2758745, + "downloads": 2762626, "version": "13.1.1" }, { @@ -1028,7 +1028,7 @@ "observability", "logging" ], - "downloads": 230556, + "downloads": 230813, "version": "13.1.1" }, { @@ -1045,7 +1045,7 @@ "database", "data" ], - "downloads": 3047696, + "downloads": 3052719, "version": "13.1.1" }, { @@ -1057,7 +1057,7 @@ "aspire", "testing" ], - "downloads": 3091161, + "downloads": 3096337, "version": "13.1.1" }, { @@ -1073,7 +1073,7 @@ "cache", "caching" ], - "downloads": 162652, + "downloads": 162849, "version": "13.1.1" }, { @@ -1089,7 +1089,7 @@ "reverse-proxy", "api" ], - "downloads": 101359, + "downloads": 101645, "version": "13.1.1" }, { @@ -1108,7 +1108,7 @@ "identity", "security" ], - "downloads": 235283, + "downloads": 235497, "version": "13.1.1-preview.1.26105.8" }, { @@ -1139,7 +1139,7 @@ "db", "nosql" ], - "downloads": 688710, + "downloads": 689556, "version": "13.1.1" }, { @@ -1158,7 +1158,7 @@ "cache", "caching" ], - "downloads": 20095, + "downloads": 20158, "version": "13.1.1-preview.1.26105.8" }, { @@ -1177,7 +1177,7 @@ "sqlserver", "sql" ], - "downloads": 1095880, + "downloads": 1100567, "version": "13.1.1" }, { @@ -1204,7 +1204,7 @@ "cosmosdb", "nosql" ], - "downloads": 113018, + "downloads": 113088, "version": "13.1.1" }, { @@ -1229,7 +1229,7 @@ "sqlserver", "sql" ], - "downloads": 3207390, + "downloads": 3213195, "version": "13.1.1" }, { @@ -1247,7 +1247,7 @@ "configuration", "appconfiguration" ], - "downloads": 114561, + "downloads": 114943, "version": "13.1.1" }, { @@ -1285,7 +1285,7 @@ "database", "mongodb" ], - "downloads": 206812, + "downloads": 206891, "version": "13.1.1" }, { @@ -1323,7 +1323,7 @@ "mysql", "sql" ], - "downloads": 2314298, + "downloads": 2316865, "version": "13.1.1" }, { @@ -1341,7 +1341,7 @@ "messaging", "eventing" ], - "downloads": 64879, + "downloads": 64958, "version": "13.1.1" }, { @@ -1362,7 +1362,7 @@ "npgsql", "sql" ], - "downloads": 2016361, + "downloads": 2027748, "version": "13.1.1" }, { @@ -1389,7 +1389,7 @@ "npgsql", "sql" ], - "downloads": 3565366, + "downloads": 3572059, "version": "13.1.1" }, { @@ -1406,7 +1406,7 @@ "ai", "openai" ], - "downloads": 368149, + "downloads": 368693, "version": "13.1.1-preview.1.26105.8" }, { @@ -1431,7 +1431,7 @@ "oracle", "sql" ], - "downloads": 183396, + "downloads": 183558, "version": "13.1.1" }, { @@ -1457,7 +1457,7 @@ "mysql", "sql" ], - "downloads": 310615, + "downloads": 311325, "version": "13.1.1" }, { @@ -1476,7 +1476,7 @@ "database", "ai-search" ], - "downloads": 73768, + "downloads": 73839, "version": "13.1.1" }, { @@ -1497,7 +1497,7 @@ "messaging", "eventing" ], - "downloads": 599846, + "downloads": 600283, "version": "13.1.1" }, { @@ -1536,7 +1536,7 @@ "observability", "logging" ], - "downloads": 311988, + "downloads": 312202, "version": "13.1.1" }, { @@ -1554,7 +1554,7 @@ "caching", "redis" ], - "downloads": 4021430, + "downloads": 4033127, "version": "13.1.1" }, { @@ -1574,7 +1574,7 @@ "distributedcache", "redis" ], - "downloads": 1532319, + "downloads": 1534174, "version": "13.1.1" }, { @@ -1595,7 +1595,7 @@ "outputcache", "redis" ], - "downloads": 551258, + "downloads": 551870, "version": "13.1.1" }, { @@ -1611,7 +1611,7 @@ "gofeatureflag", "client" ], - "downloads": 39998, + "downloads": 39999, "version": "13.1.1" }, { @@ -1627,7 +1627,7 @@ "hosting", "activemq" ], - "downloads": 52228, + "downloads": 52255, "version": "13.1.1" }, { @@ -1643,7 +1643,7 @@ "hosting", "adminer" ], - "downloads": 78324, + "downloads": 78506, "version": "13.1.1" }, { @@ -1660,7 +1660,7 @@ "dapr", "azure" ], - "downloads": 47667, + "downloads": 47677, "version": "13.0.0" }, { @@ -1674,7 +1674,7 @@ "communitytoolkit", "dotnetcommunitytoolkit" ], - "downloads": 37982, + "downloads": 38063, "version": "13.0.0" }, { @@ -1691,7 +1691,7 @@ "dataapibuilder", "hosting" ], - "downloads": 55345, + "downloads": 55351, "version": "13.1.1" }, { @@ -1708,7 +1708,7 @@ "azure", "extensions" ], - "downloads": 50, + "downloads": 56, "version": "13.1.2-beta.518" }, { @@ -1725,7 +1725,7 @@ "staticwebapps", "hosting" ], - "downloads": 40285, + "downloads": 40287, "version": "9.4.0" }, { @@ -1742,7 +1742,7 @@ "bun", "javascript" ], - "downloads": 59773, + "downloads": 59830, "version": "13.1.1" }, { @@ -1758,7 +1758,7 @@ "hosting", "dapr" ], - "downloads": 308318, + "downloads": 308672, "version": "13.0.0" }, { @@ -1788,7 +1788,7 @@ "hosting", "dbgate" ], - "downloads": 112232, + "downloads": 112431, "version": "13.1.1" }, { @@ -1804,7 +1804,7 @@ "hosting", "deno" ], - "downloads": 52605, + "downloads": 52606, "version": "13.1.1" }, { @@ -1821,7 +1821,7 @@ "elasticsearch", "elasticvue" ], - "downloads": 1223, + "downloads": 1228, "version": "13.1.1" }, { @@ -1839,7 +1839,7 @@ "feature-flags", "openfeature" ], - "downloads": 9472, + "downloads": 9479, "version": "13.1.1" }, { @@ -1856,7 +1856,7 @@ "flyway", "migration" ], - "downloads": 3554, + "downloads": 3563, "version": "13.1.1" }, { @@ -1888,7 +1888,7 @@ "hosting", "golang" ], - "downloads": 71620, + "downloads": 71679, "version": "13.1.1" }, { @@ -1904,7 +1904,7 @@ "hosting", "java" ], - "downloads": 57881, + "downloads": 57884, "version": "13.1.1" }, { @@ -1924,7 +1924,7 @@ "pnpm", "npm" ], - "downloads": 20441, + "downloads": 20514, "version": "13.1.1" }, { @@ -1940,7 +1940,7 @@ "hosting", "k6" ], - "downloads": 34821, + "downloads": 34829, "version": "13.1.1" }, { @@ -1958,7 +1958,7 @@ "hosting", "extensions" ], - "downloads": 6547, + "downloads": 6551, "version": "13.1.2-beta.518" }, { @@ -1974,7 +1974,7 @@ "hosting", "kurrentdb" ], - "downloads": 6908, + "downloads": 6910, "version": "13.1.1" }, { @@ -2007,7 +2007,7 @@ "smtp", "hosting" ], - "downloads": 113870, + "downloads": 114119, "version": "13.1.1" }, { @@ -2025,7 +2025,7 @@ "debugging", "hosting" ], - "downloads": 28495, + "downloads": 28540, "version": "13.1.1" }, { @@ -2041,7 +2041,7 @@ "hosting", "meilisearch" ], - "downloads": 53239, + "downloads": 53246, "version": "13.1.1" }, { @@ -2059,7 +2059,7 @@ "cloud", "storage" ], - "downloads": 59054, + "downloads": 59317, "version": "13.1.1" }, { @@ -2076,7 +2076,7 @@ "mongodb", "dbgate" ], - "downloads": 46722, + "downloads": 46754, "version": "13.1.1" }, { @@ -2093,7 +2093,7 @@ "mysql", "dbgate" ], - "downloads": 24315, + "downloads": 24336, "version": "13.1.1" }, { @@ -2110,7 +2110,7 @@ "ngrok", "tunnels" ], - "downloads": 66514, + "downloads": 66601, "version": "13.1.1" }, { @@ -2127,7 +2127,7 @@ "ollama", "ai" ], - "downloads": 208707, + "downloads": 208916, "version": "13.1.1" }, { @@ -2143,7 +2143,7 @@ "opentelemetry", "observability" ], - "downloads": 13168, + "downloads": 13193, "version": "13.1.1" }, { @@ -2160,7 +2160,7 @@ "smtp", "hosting" ], - "downloads": 43649, + "downloads": 43654, "version": "13.1.1" }, { @@ -2177,7 +2177,7 @@ "postgres", "dbgate" ], - "downloads": 58546, + "downloads": 58605, "version": "13.1.1" }, { @@ -2196,7 +2196,7 @@ "script", "hosting" ], - "downloads": 29605, + "downloads": 29636, "version": "13.1.1" }, { @@ -2213,7 +2213,7 @@ "uvicorn", "python" ], - "downloads": 60251, + "downloads": 60267, "version": "13.1.1" }, { @@ -2229,7 +2229,7 @@ "hosting", "ravendb" ], - "downloads": 49562, + "downloads": 49607, "version": "13.1.1" }, { @@ -2246,7 +2246,7 @@ "redis", "dbgate" ], - "downloads": 49917, + "downloads": 49928, "version": "13.1.1" }, { @@ -2262,7 +2262,7 @@ "hosting", "rust" ], - "downloads": 50808, + "downloads": 50811, "version": "13.1.1" }, { @@ -2279,7 +2279,7 @@ "sftp", "hosting" ], - "downloads": 1487, + "downloads": 1498, "version": "13.1.1" }, { @@ -2310,7 +2310,7 @@ "sql", "sqlproj" ], - "downloads": 137775, + "downloads": 137873, "version": "13.1.1" }, { @@ -2327,7 +2327,7 @@ "sql", "sqlite" ], - "downloads": 57417, + "downloads": 57461, "version": "13.1.1" }, { @@ -2344,7 +2344,7 @@ "sqlserver", "dbgate" ], - "downloads": 77459, + "downloads": 77566, "version": "13.1.1" }, { @@ -2378,7 +2378,7 @@ "hosting", "surrealdb" ], - "downloads": 16435, + "downloads": 16438, "version": "13.1.1" }, { @@ -2427,7 +2427,7 @@ "masstransit", "rabbitmq" ], - "downloads": 60142, + "downloads": 60149, "version": "13.1.1" }, { @@ -2443,7 +2443,7 @@ "meilisearch", "client" ], - "downloads": 59667, + "downloads": 59669, "version": "13.1.1" }, { @@ -2461,7 +2461,7 @@ "data", "ado.net" ], - "downloads": 43020, + "downloads": 43029, "version": "13.1.1" }, { @@ -2482,7 +2482,7 @@ "ef", "orm" ], - "downloads": 52221, + "downloads": 52248, "version": "9.7.2" }, { @@ -2500,7 +2500,7 @@ "cloud", "storage" ], - "downloads": 32101, + "downloads": 32286, "version": "13.1.1" }, { @@ -2518,7 +2518,7 @@ "ollamasharp", "client" ], - "downloads": 244440, + "downloads": 244736, "version": "13.1.1" }, { @@ -2534,7 +2534,7 @@ "client", "ravendb" ], - "downloads": 55334, + "downloads": 55408, "version": "13.1.1" }, { diff --git a/src/frontend/src/data/github-stats.json b/src/frontend/src/data/github-stats.json index 52fbf790a..c55a75ea0 100644 --- a/src/frontend/src/data/github-stats.json +++ b/src/frontend/src/data/github-stats.json @@ -1,7 +1,7 @@ [ { "name": "dotnet/aspire", - "stars": 5461, + "stars": 5462, "description": "Aspire is the tool for code-first, extensible, observable dev and deploy.", "license": "https://github.com/dotnet/aspire/blob/main/LICENSE.TXT", "licenseName": "MIT License", From 9d2ad7a9333f8747957e51e295c847add19cf50f Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 23:13:37 -0600 Subject: [PATCH 79/90] chore: add a thank you page --- .../config/sidebar/community.topics.ts | 23 + .../src/assets/icons/astro-icon-light.svg | 1 + src/frontend/src/assets/icons/astro-icon.svg | 1 + src/frontend/src/assets/icons/dotnet.svg | 2 +- .../src/assets/icons/expressivecode-icon.svg | 1 + .../src/assets/icons/fluentui-icon-light.svg | 4 + .../src/assets/icons/fluentui-icon.svg | 4 + src/frontend/src/assets/icons/grpc-icon.svg | 1 + src/frontend/src/assets/icons/hex1b-icon.svg | 49 + .../src/assets/icons/masstransit-icon.png | Bin 0 -> 6909 bytes .../src/assets/icons/mermaid-icon.svg | 1 + src/frontend/src/assets/icons/nunit-icon.svg | 34 + .../src/assets/icons/opentelemetry-icon.svg | 1 + .../src/assets/icons/playwright-icon.svg | 1 + src/frontend/src/assets/icons/podman-icon.svg | 1 + src/frontend/src/assets/icons/polly-icon.png | Bin 0 -> 7934 bytes src/frontend/src/assets/icons/sharp-icon.svg | 5 + .../src/assets/icons/spectreconsole-icon.png | Bin 0 -> 17764 bytes .../src/assets/icons/starlight-icon.webp | Bin 0 -> 32236 bytes src/frontend/src/assets/icons/xunit-icon.svg | 1 + .../src/content/docs/community/thanks.mdx | 1068 +++++++++++++++++ src/frontend/src/data/github-stats.json | 4 +- 22 files changed, 1199 insertions(+), 3 deletions(-) create mode 100644 src/frontend/src/assets/icons/astro-icon-light.svg create mode 100644 src/frontend/src/assets/icons/astro-icon.svg create mode 100644 src/frontend/src/assets/icons/expressivecode-icon.svg create mode 100644 src/frontend/src/assets/icons/fluentui-icon-light.svg create mode 100644 src/frontend/src/assets/icons/fluentui-icon.svg create mode 100644 src/frontend/src/assets/icons/grpc-icon.svg create mode 100644 src/frontend/src/assets/icons/hex1b-icon.svg create mode 100644 src/frontend/src/assets/icons/masstransit-icon.png create mode 100644 src/frontend/src/assets/icons/mermaid-icon.svg create mode 100644 src/frontend/src/assets/icons/nunit-icon.svg create mode 100644 src/frontend/src/assets/icons/opentelemetry-icon.svg create mode 100644 src/frontend/src/assets/icons/playwright-icon.svg create mode 100644 src/frontend/src/assets/icons/podman-icon.svg create mode 100644 src/frontend/src/assets/icons/polly-icon.png create mode 100644 src/frontend/src/assets/icons/sharp-icon.svg create mode 100644 src/frontend/src/assets/icons/spectreconsole-icon.png create mode 100644 src/frontend/src/assets/icons/starlight-icon.webp create mode 100644 src/frontend/src/assets/icons/xunit-icon.svg create mode 100644 src/frontend/src/content/docs/community/thanks.mdx diff --git a/src/frontend/config/sidebar/community.topics.ts b/src/frontend/config/sidebar/community.topics.ts index e8e1ba27c..424fc1c71 100644 --- a/src/frontend/config/sidebar/community.topics.ts +++ b/src/frontend/config/sidebar/community.topics.ts @@ -170,5 +170,28 @@ export const communityTopics: StarlightSidebarTopicsUserConfig = { variant: 'tip', }, }, + { + label: 'Thanks', + translations: { + da: 'Tak', + de: 'Danke', + en: 'Thanks', + es: 'Agradecimientos', + fr: 'Remerciements', + hi: 'धन्यवाद', + id: 'Terima Kasih', + it: 'Ringraziamenti', + ja: '謝辞', + ko: '감사의 말', + pt: 'Agradecimentos', + 'pt-BR': 'Agradecimentos', + 'pt-PT': 'Agradecimentos', + ru: 'Благодарности', + tr: 'Teşekkürler', + uk: 'Подяки', + 'zh-CN': '致谢', + }, + slug: 'community/thanks', + }, ], }; diff --git a/src/frontend/src/assets/icons/astro-icon-light.svg b/src/frontend/src/assets/icons/astro-icon-light.svg new file mode 100644 index 000000000..e0ca705fa --- /dev/null +++ b/src/frontend/src/assets/icons/astro-icon-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/astro-icon.svg b/src/frontend/src/assets/icons/astro-icon.svg new file mode 100644 index 000000000..9a05073eb --- /dev/null +++ b/src/frontend/src/assets/icons/astro-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/dotnet.svg b/src/frontend/src/assets/icons/dotnet.svg index 89df98957..eba1f019e 100644 --- a/src/frontend/src/assets/icons/dotnet.svg +++ b/src/frontend/src/assets/icons/dotnet.svg @@ -1 +1 @@ -.NET \ No newline at end of file + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/expressivecode-icon.svg b/src/frontend/src/assets/icons/expressivecode-icon.svg new file mode 100644 index 000000000..82982618d --- /dev/null +++ b/src/frontend/src/assets/icons/expressivecode-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/fluentui-icon-light.svg b/src/frontend/src/assets/icons/fluentui-icon-light.svg new file mode 100644 index 000000000..02a416b93 --- /dev/null +++ b/src/frontend/src/assets/icons/fluentui-icon-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/frontend/src/assets/icons/fluentui-icon.svg b/src/frontend/src/assets/icons/fluentui-icon.svg new file mode 100644 index 000000000..64cc64148 --- /dev/null +++ b/src/frontend/src/assets/icons/fluentui-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/frontend/src/assets/icons/grpc-icon.svg b/src/frontend/src/assets/icons/grpc-icon.svg new file mode 100644 index 000000000..ff3537ee2 --- /dev/null +++ b/src/frontend/src/assets/icons/grpc-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/hex1b-icon.svg b/src/frontend/src/assets/icons/hex1b-icon.svg new file mode 100644 index 000000000..704a93679 --- /dev/null +++ b/src/frontend/src/assets/icons/hex1b-icon.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 1b + diff --git a/src/frontend/src/assets/icons/masstransit-icon.png b/src/frontend/src/assets/icons/masstransit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..287d5c6856a9886bcd0c83b7f59a863ebd653874 GIT binary patch literal 6909 zcmbVRg;x|#v<68*U>E5nmylWz1*CJAT0%f-DPcjnq(MZN?h=rOr9`@?xtGHl_Lt5UF5b<>E%(i)LRN1aGS)J-=-Zt0zPZ@nuj|LM>q|HCzphVR|9=A= z-*ps7qHAUL*7RK0<)K<5;Sc7wz&D^d_V!m@vcj%Y>>-E9PYW*UvE8A z;q9w+#xE>Un2dvWC*Ir-GP0X!pMNJK4g;xxKs@^CbNhnJJ_jP#1DRp0IBh{vC;hvP z?b|Dt6_C(R8u{YAmiw1;%8AO^O-z%%0Vy+6P=sLLf*RunpK_~^%6NHmJNy*$6pwvd zC2Hs_$#DD5ddG7kB#r5@Yu4Er&FmC(hSKB8`{QFxqC;nnn^!daAKkhgMV~ln8^fFJ6_6KXqlKIaeuol0dd5rwdN~=S1{R&56;be#O-4j`DTip=-G_51??&Ux? zKxrR~qS@x*K1^)Rem&1IadcD};JnJ%SwvDUkyCITI?DAIyCB_z_gsR@Qc6EzNHkgF z8!#B;MpRv{V55gqixK%ead>AT$=6%H6=yX%v;B4Tk5W7a_F!6AhFz;u`qqA`KRWi| z=dJSk(c5Ow(`;e#b0&_x0=Kl^MQPlOW&tsad4&T)ku;A{0e6 z*#1UQ`;r}*E_R>sCXbV7xN2Rjob%n8<3!W)Z+eySG+64c6$q7s%jjA;A&5NqIWA_D zft^9G>cyi%CSlxaVlX8owzI2`K6o?PmaTiq`A$ZW_g7=>br?=FC*lfz9&z`9E!n;Y z6IF!lIy_gr;Et=U#th2J* z$4A%s{>W$t(QVPxHduuaH5X{e4PIM)zK!@B>x6wlH&zna&rS?~r16TG$vXc|y2SPZ zx2)sx2&%}Nl(t*WNm0XT3defhP#XVY;jKa4pM@wQ5X`;>M~ol7y4F29w5ap*;t$Cg zIRy3}{816Vd~??l`synumKe-Xgx%rLrYd23J5Y=9cQx(SQxdK*Tn-HBKb~A_3pHO} z4EhnTc47#WH|&V)*k9(sx%=gDdR|A<4;~t@`W@ZeL|^T&saXHjC{y0>MCUhM!Di4g zL$aC&K}(O#NPIx*&<$%Wjs7QNAUYtJtJT4WcJ?}lL8pW{<~!(xO56(Y?uz(OcD2^< ztOjJxhNYOUO6>2AUS@nTaclOV3dflDVj*5ZcXAOHFUDMgi3LOfEf0=_TGd|Al-`^u z)&Kbtn!`EtHT+u<+v#iPtt$D#f7O=p0*P+G%!2ac=ef>i9D6Qv)k21$f#gXIFr8k? zXZwew!F05x5fhD01Irj?#x#miWnKJ|L)&=_aUh=v?&AaayNM-C&xzH-O8z5_!)}FZ z%2{`beQm9EU@&JU-Wk~BA_Yk{Vv-|~Fp zF4W1wcfBxSOs&Jr_4@3(qM4hZ0@_|x(aXgr87ztiGw{tW`xq?PdwjsZs*g}3$KPFc z9~c(uSK<#5GCIG$wx)d~ zm+V6!eA+2GT5FXdrq6zB!v@>+GDcCZy&{ugPk*WcUp zOHxi_Bj}z~P3i>{PU$xwnpC)%{l{H_&|nrdnU^P`dtK@w{B*-H>2_D%)7N_?B$0dHq(jox-#xJl!U0Krl>b9Wff?cXaJ;=${mAoLG`xQ6X zAX6DTo92T!N{&qF5QH?aLrY!TKw@E$ZCVk8vrE;oyM_<`J`TZvBh@PJShs{DXgdcQ zYv?yNoC`K|{KnY%2QzZnqfY`E}Y@Z2Fl=<%LhLe?r#@^c@SEGsi;zW}m|e~lTT z+#@N|{P@W3)>uIhqjT8BEF!!B9c>sd=+S%|u=SL%I^!Kp^=~@<_S(dK8v69JDP^yp zRNH3M?hEYXWGAB-EF2rB%M zX4K&0Rq@DT4iX#ipNE4{@4h0z)Bf=F^&h9GLI2LYDe+t@^i$Q>2^R^0Yu^vSAy}Hu zl#T{}Y%hig!s7S75~+;4A^mrFiE;S$eLNbwy(G881mRFh)_M&~3*;XitAa~vt>XB0 zxzc(w`zp=d&h^Z%hsd>6_FNbFk<%WqAEk8*oY?&qOZ_jL`N4uDXVpY*xS*TB_{OjA z!1jTf$I$qZB}Ng^D++KY?8vB$poRXo*gDMbx)M$%x7eMcFyuduw8mGZ6hcfP#1*qE z0g%jiq*;N@ITK6ohP`@A@IvPI6?OD7^HVZ|YG5*}3Hu9lwn0QR#tpRdF zIuSb^)XLbpqDV91+;&QgHiYi^qWYijq;8VLC{nD=gQNN&I4SU$8?WfZh;~1pmK#Jj zs~bwG#eLkz@;t?5uD*7+hIs8Qc7)m{jR#ABN=e#T2 z{p6D@Ualf~X|a7DrJQW4n+{xkJ#m=YBC4(L6;n@8>Kkh+nHJh(@& zOkEF=3wb2|a-df8CXO(la#N`k!4H#~nZA_NWPMUwc!?eOW3r(EQhD6Rlmu0-vzK~ht529)!Ec~wE8o`jZAoTG4 z0l!;Fk9c~e&9fq3$wMYQFK3Q1q43@LQkDc7CpC1dmOrTKtCV6(_E74n_9CQ1=Fc@o zdF~7}=EabH#!VzE7tRxLiTF;oDO@Ee1i5QOc7atApN?VZZgJHLj3?Ah_`c7W+d(Ja zipaj2i|J#G#KOxjPv#wfkj9cba-Tn7%cEdri@ zKWWtc`MxOz1CV;Og!)EoX}OSJzrs7WE~~+iB1R@0Kxf8n8#bNM5$MTgsrRSkS;6zbd@(1mFVx($_LK^_Yz2N_Wc zzTcA$6Fy~rxZS9j(R3k&EAgFUmdUR#(6fRsRx<=QatlS?Yv$4gd0ez!1Ng2#D_>I8 z4g^xMAq~z82)`%=Rz2)4b+MaZfKe=QMRXNiTonPFSjBnF@FOHs9P4}yE5sv@4ThF= z`k4_@mlc~*VM$ibFhSGz;(84df}S6O{>I2#wcv4~do*jp{>;9D><}L@3s^9F*)D8< zrIG$IuAo)hMBYdYb}bW!M1pJUw(xy(|MeeWc@OtZY_=YaL}}vfpKpG3;I;yRK-(Yw z5O+{2KDHiJ;l1n|SzK$aG~ziZ9JL7k7;}t|RCwlCa9$ zd~S4LjDDq7n+C`Q`5en^dOHe*phZPLmT8iYf4AUuSP4Jfva`!M+8ZvT+kAor+cX*f zz0EafDcZ7vwU_tpe1;*vvei(##Ag@q@RZNDP~?nau2&nZ%vQ|=OxZ3E3))mmnI8%A zm6T8EStyU$juyMbJNK#ZW+B6A_@7sWA7;3F<;faO9zPpS@Vh)@+UH`N#OSJcHxZ06 z&~UEvplm%BEHU{n$1RdZ(cCq4b7<{Dz+xsA;CEyD8iU7ni}b&!1R9hTcq~zsOOk_Zg5SakDhC02f=Wp7( z8(%}6T<)5xJ-c=W-#AuPhB_s{09Yr#W-UM9E*1q%2qDuVy$=kB-BU_=DD1O>^83S$ zXmt2(a%;2EQuku>n`v#)0jjd*)EcuQe_3L!be_&;?I#6@0Zbf>=F^kBV39;?)du=2 z?>B&5%D3o^8`dJ=#FPPg^_l`%vWNAYhh^yWyPVKr%AH309tDUe;0V4q}qs*4z$2Y>&_ zGRVDi3vE|&=U?W>JbTkraA3EXmxV>R1nhNz$0RBgitp;iBj*iJM6S6hLp3Ue*wW!l4GJ$y zitk_ncvS$L3_m4R=u=4-sa8zIpu0;#*KS3X<2fKo;BZ1p*!&mA)}0zW|~yXt=bj5LT~k&V~6|YuBAROoulY-v`2X z#GNYe7(#LEv$^{vFrywLqYTr_1{^U`6b;50B?tNWNYmbCE2qJ(D*8r#Z3S zJDsFP42;xSd5r*vC?tk4k=t@(=MvQ{?FHMdS*(0H9 zaQdzO6890Nk6={=tLO2eKJ26!Cxo+}!hjPQGlScg#n*W)vu8*{RzOU7snmTX4@Jb^zK(iD#gj+s zM5E5A$z)c|=bVa*k-%7{h8F2di0FG%L!Xh8fm91Ey#7FBf!jrOOW&eXbB0rrKdc}$ zfARC-uAG6p)ql+Hj*b4uqDnu9V}H3}{IdBi3vObQwK5uH#<<@`wQ+fcom#bI{=ki8 zT1{dc43&_RED}NWc!;Z`oAtKYlh+zwD|=wjC88S?LBYSGCfIv~AMdUI^s zxi0bA8b6Qe`A6H*u6)5raKNp}a&qg);?{!S+?#XXgf9*vIY$^G4V#!5EHh@xgy>lm z>odz5QJopob}1%ek)-07>2en3d>1}a@dxs0L)uUxOh$PmXn#!#O}6?aidB{VjWu1m zKz1F6SAw#8MvjCP^$&p4=CkpMNObqBJ}k4Um#>HqPUXYah4wCq*D!pGEMd}O+kRu^ zQX0>CwW*)|sVRTn*xHtqViyki{q`1>fnZ?~#fYrjS3Zrpi70*akHT3sCc; z{)$ELcf~6`y7$}3SQ%cC-^tNS*WIh%#aI-B7R$H=br||p7H@(hSheWW4+jbezb87~DMa>R0jW#sZ z3@R3faz8VF9d??~-I-6sFo<+#as_fI8LZea5j3>yl_)0skr)TSoN4CrzTeh59)FOV ze0$G-^fjW1vHDI8ZOPl219l^Z(D|LqcYWl$y_qW1()Qt|Exta-ZaQU7fly;gZ8LIm zHD_TWb*!Jx>bnrxy+#twIbM%)k$_@U`RGM@P4y%6ybNvtG6Z^HWgF$b={om#0xJfb zi`z28rWC6BYGFlR`!~ur!#~UH;*-A>;LEe9P2#YNAJ;3BZ;n9CGSxnpg0R$*|FGvL zbRBNf_Aydrgt?OA2K=Hg$lz^En!rx!Hay2f6E>*{94!~R5O}d$fuF+h%e4r zegAE?Lc?i|K>y2hLKEeP@d>}QqxV3jc@C9=l1S$8-XMc09;j1)#2l6tZC4~zh+RDx zJV3{U4Av#==+Q`@AHg-pK9=2x$Iprl7IA~ez@=b@s9XyhA9@Jy*gsj8)u|0N{OKI_J@i zvPE3Fn|83>8B-ek>{=&IERc7=AKA=P>uL79s%Ri&(}dd%1NAfs%zx(f32kj#Sln;F zB08R57qR9531^kHMzmpN!T|oN0{_6cfezBg7yOz8QHKYaVV_J4*nOi}c{~p*e_2N4 z7N&u>i75}&JaORgc|*f&6rdK@BnH3|J;CD_eUlY0rWF3z2jT-PE~VwH{18JX`X;Z$ zEK)o?X3zp8TM9KTA2a$*r&sllxwPUfYis(X=*H5+!$IGP*X~p!1rbB?j-u*`grH;U zhae|@$<`G)85B2F!o9riw{TZ1C^74ck*A7Mi5Va;pmO{s^FHRfcnf% zp_y0!gX34%`*WgyiAOLv)>Yenry4fMEaXDlk-Pofu}g{(87ByM9KuCboVUMaD~IGO z$Ja=J+&vEYMr$%sHPXcphI5Ss%wAoH(%jokhZ5AgNF}@Un0Slr<3Oz7^fO!*sv;LqOiy&5D7NQ{E(%|B$j96tDR>d7Fa`uxHrz zMqeCkI;gKe_pjtV^xsn3k-vB3eGx=f&?=A;AxvE!6O>cNTi5pve?(HHK?o%_YN5*k z&`4rk1afGkD>7z)KjLo4Rdlo34Xy#6l&a+ZHQ`zEj3@o0^x$wmCrmMvRNo_MT#U$@ z>3;RO34Mlh;mQ#b7M+K*sk7%581PD}4ZIXK>&^onP2!pn`DSN|LL+$li?};9{RK`* zm>fGoCF1oaCCc5QpU$^&7V&gjdP-x?bV97xaPnMdICsuitjtQ;vu*f_g~UvVR(EBO zD*p+$GWWx-L)*v?WVO$kT*wrptmQdVht4LJ9K;O8``qed#k>+Eo*t9?WUUGK4_axi zOx_kBf&-bj-Ex|h*3w|MSTIGVBMg7}>c$AeQ1&y({Zg!Axc%>$B%+FYDj1N})iS5L zSo}D^frZ@1;Xujr!#3^Da7h)Yako#MZ{U6MigUh1Oz$>ocsF_0vUy)-G5cBCZjt%b zEc)V`Vu~z}7Vgtj;ZNGq&x{7If$W#-M!`M|Z6%rOx5+=3m)LJAxX6`1{y*zJ=WX|u ath>82{00_^WO?wtfujo3gjOiLM*R \ No newline at end of file diff --git a/src/frontend/src/assets/icons/nunit-icon.svg b/src/frontend/src/assets/icons/nunit-icon.svg new file mode 100644 index 000000000..207cdbbd1 --- /dev/null +++ b/src/frontend/src/assets/icons/nunit-icon.svg @@ -0,0 +1,34 @@ + + + NUnit Icon + + + + + + + + + + + + diff --git a/src/frontend/src/assets/icons/opentelemetry-icon.svg b/src/frontend/src/assets/icons/opentelemetry-icon.svg new file mode 100644 index 000000000..21172b7e0 --- /dev/null +++ b/src/frontend/src/assets/icons/opentelemetry-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/playwright-icon.svg b/src/frontend/src/assets/icons/playwright-icon.svg new file mode 100644 index 000000000..4f961ddff --- /dev/null +++ b/src/frontend/src/assets/icons/playwright-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/podman-icon.svg b/src/frontend/src/assets/icons/podman-icon.svg new file mode 100644 index 000000000..b1476b05a --- /dev/null +++ b/src/frontend/src/assets/icons/podman-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/polly-icon.png b/src/frontend/src/assets/icons/polly-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bf778688b0c096e78e4aa141360544a714087bf4 GIT binary patch literal 7934 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 literal 0 HcmV?d00001 diff --git a/src/frontend/src/assets/icons/sharp-icon.svg b/src/frontend/src/assets/icons/sharp-icon.svg new file mode 100644 index 000000000..fc185469f --- /dev/null +++ b/src/frontend/src/assets/icons/sharp-icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/src/assets/icons/spectreconsole-icon.png b/src/frontend/src/assets/icons/spectreconsole-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..23be19f17418207655dfc9d749af645b398e4dc7 GIT binary patch literal 17764 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 a`TzfjZotC}HW4{M4uhwwpUXO@geCwsnh-ev literal 0 HcmV?d00001 diff --git a/src/frontend/src/assets/icons/starlight-icon.webp b/src/frontend/src/assets/icons/starlight-icon.webp new file mode 100644 index 0000000000000000000000000000000000000000..8f36d2d590d7f51a3b3314c7b2ab3dd515c20e41 GIT binary patch literal 32236 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

-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 fhjq=cytZccdvif \ No newline at end of file diff --git a/src/frontend/src/content/docs/community/thanks.mdx b/src/frontend/src/content/docs/community/thanks.mdx new file mode 100644 index 000000000..b68c3250f --- /dev/null +++ b/src/frontend/src/content/docs/community/thanks.mdx @@ -0,0 +1,1068 @@ +--- +title: Thank you +description: Celebrating the open-source projects and communities that make Aspire possible. +editUrl: false +giscus: false +tableOfContents: true +pageActions: false +lastUpdated: false +--- + +import { Image } from 'astro:assets'; +import { LinkCard, CardGrid, Badge } from '@astrojs/starlight/components'; +import ThemeImage from '@components/ThemeImage.astro'; +import CTABanner from '@components/CTABanner.astro'; + +{/* ── Observability & Resilience ── */} +import opentelemetryIcon from '@assets/icons/opentelemetry-icon.svg'; +import pollyIcon from '@assets/icons/polly-icon.png'; + +{/* ── Databases & Storage ── */} +import postgresqlIcon from '@assets/icons/postgresql-icon.png'; +import mongodbIcon from '@assets/icons/mongodb-icon.png'; +import redisIcon from '@assets/icons/redis-icon.png'; +import valkeyIcon from '@assets/icons/valkey-icon.png'; +import garnetIcon from '@assets/icons/garnet-icon.png'; +import milvusIcon from '@assets/icons/milvus-icon.png'; +import qdrantIcon from '@assets/icons/qdrant-icon.svg'; +import sqliteIcon from '@assets/icons/sqlite-icon.png'; + +{/* ── Messaging & Eventing ── */} +import rabbitmqIcon from '@assets/icons/rabbitmq-icon.svg'; +import natsIcon from '@assets/icons/nats-icon.png'; +import kafkaIcon from '@assets/icons/apache-kafka-icon.svg'; + +{/* ── Reverse Proxy & Networking ── */} +import yarpIcon from '@assets/icons/yarp-icon.svg'; +import grpcIcon from '@assets/icons/grpc-icon.svg'; + +{/* ── Containers & Orchestration ── */} +import dockerIcon from '@assets/icons/docker.svg'; +import podmanIcon from '@assets/icons/podman-icon.svg'; +import kubernetesIcon from '@assets/icons/kubernetes.svg'; + +{/* ── Web Stack & Documentation ── */} +import astroIcon from '@assets/icons/astro-icon.svg'; +import astroLightIcon from '@assets/icons/astro-icon-light.svg'; +import starlightIcon from '@assets/icons/starlight-icon.webp'; +import expressivecodeIcon from '@assets/icons/expressivecode-icon.svg'; +import mermaidIcon from '@assets/icons/mermaid-icon.svg'; +import sharpIcon from '@assets/icons/sharp-icon.svg'; +import pnpmIcon from '@assets/icons/pnpm.svg'; +import pnpmLightIcon from '@assets/icons/pnpm-light.svg'; + +{/* ── UI & Design ── */} +import fluentuiIcon from '@assets/icons/fluentui-icon.svg'; +import fluentuiLightIcon from '@assets/icons/fluentui-icon-light.svg'; + +{/* ── Polyglot ── */} +import nodejsIcon from '@assets/icons/nodejs-icon.png'; +import nodejsLightIcon from '@assets/icons/nodejs-light-icon.png'; +import goIcon from '@assets/icons/go-icon.png'; +import goLightIcon from '@assets/icons/go-light-icon.png'; +import pythonIcon from '@assets/icons/python.svg'; +import javaIcon from '@assets/icons/java-icon.png'; +import rustIcon from '@assets/icons/rust-icon.png'; +import denoIcon from '@assets/icons/deno-icon.png'; +import denoLightIcon from '@assets/icons/deno-light-icon.png'; +import bunIcon from '@assets/icons/bun-icon.png'; +import powershellIcon from '@assets/icons/powershell-icon.png'; + +{/* ── .NET Ecosystem ── */} +import orleansIcon from '@assets/icons/microsoft-orleans.png'; +import mauiIcon from '@assets/icons/maui-icon.png'; + +{/* ── AI & ML ── */} +import ollamaIcon from '@assets/icons/ollama-icon.png'; +import openaiIcon from '@assets/icons/openai-icon.png'; +import openaiLightIcon from '@assets/icons/openai-light-icon.png'; + +{/* ── Dapr ── */} +import daprIcon from '@assets/icons/dapr-icon.png'; +import daprLightIcon from '@assets/icons/dapr-light-icon.png'; + +{/* ── Email ── */} +import mailpitIcon from '@assets/icons/mailpit-icon.svg'; +import mailpitLightIcon from '@assets/icons/mailpit-light-icon.svg'; + +{/* ── Testing ── */} +import xunitIcon from '@assets/icons/xunit-icon.svg'; +import nunitIcon from '@assets/icons/nunit-icon.svg'; +import playwrightIcon from '@assets/icons/playwright-icon.svg'; + +{/* ── Community Toolkit ── */} +import spectreconsoleIcon from '@assets/icons/spectreconsole-icon.png'; + +{/* ── Runtime & Framework ── */} +import dotnetIcon from '@assets/icons/dotnet.svg'; +import csharpIcon from '@assets/icons/csharp.svg'; +import blazorIcon from '@assets/icons/blazor-icon.svg'; +import aspireIcon from '@assets/icons/aspire-icon.png'; + +{/* ── DevEx & CLI ── */} +import hex1bIcon from '@assets/icons/hex1b-icon.svg'; + +
+ + + +

Thank you, open source

+

+ Standing on the
shoulders of giants +

+

+ Aspire wouldn't exist without the incredible open-source projects and communities + that power the distributed apps ecosystem. This page is our thank-you to every contributor, + maintainer, and community member behind the tools we depend on. +

+ +

We 💜 open source

+
+ +## Observability & resilience + +The eyes, ears, and safety nets of distributed systems. + +
+ +
+
+ Polly logo + Polly +
+

The resilience and transient-fault-handling library behind Aspire's default retry and circuit-breaker policies.

+ +
+
+ +## Databases & storage + +The data engines Aspire integrates with out of the box. + +
+
+
+ PostgreSQL logo + PostgreSQL +
+

The world's most advanced open-source relational database.

+ +
+
+
+ MongoDB logo + MongoDB +
+

The document database for modern application development.

+ +
+
+
+ Redis logo + Redis +
+

The high-performance in-memory data store used for caching, messaging, and more.

+ +
+
+
+ Valkey logo + Valkey +
+

The open-source, high-performance key/value store.

+ +
+
+
+ Garnet logo + Garnet +
+

A high-performance cache-store from Microsoft Research.

+ +
+
+
+ Milvus logo + Milvus +
+

The open-source vector database for AI-powered similarity search.

+ +
+
+
+ Qdrant logo + Qdrant +
+

The vector search engine for next-generation AI applications.

+ +
+
+
+ SQLite logo + SQLite +
+

The most widely deployed database engine in the world.

+ +
+
+ +## Messaging & eventing + +The plumbing that keeps distributed services talking to each other. + +
+
+
+ RabbitMQ logo + RabbitMQ +
+

The most widely deployed open-source message broker.

+ +
+
+
+ NATS logo + NATS +
+

High-performance messaging for distributed apps and edge computing.

+ +
+
+
+ Apache Kafka logo + Apache Kafka +
+

The distributed event streaming platform used by thousands of companies.

+ +
+
+ +## Reverse proxy & networking + +The traffic directors and protocol layers that connect services. + +
+
+
+ YARP logo + YARP +
+

Yet Another Reverse Proxy — a highly customizable reverse proxy library built on .NET.

+ +
+
+
+ gRPC logo + gRPC +
+

The high-performance, open-source universal RPC framework.

+ +
+
+ +## Containers & orchestration + +The engines that package, ship, and run distributed workloads. + +
+
+
+ Docker logo + Docker +
+

The platform that popularized containers and makes local development with Aspire seamless.

+ +
+
+
+ Podman logo + Podman +
+

The daemonless container engine for developing, managing, and running OCI containers.

+ +
+
+
+ Kubernetes logo + Kubernetes +
+

The open-source system for automating deployment, scaling, and management of containerized applications.

+ +
+
+ +## Email & developer services + +Tools that simplify common dev-time workflows. + +
+
+
+ + Mailpit +
+

An email and SMTP testing tool with a modern web UI, perfect for local development.

+ +
+
+ +## AI & machine learning + +The projects powering Aspire's AI integrations. + +
+
+
+ Ollama logo + Ollama +
+

Run large language models locally — the easiest way to bring AI into your Aspire apps.

+ +
+
+
+ + OpenAI +
+

The AI research lab behind GPT, DALL-E, and the APIs that Aspire integrates with natively.

+ +
+
+ +## Polyglot ecosystem + +Aspire speaks many languages — thanks to these communities. + +
+
+
+ + Node.js +
+

The JavaScript runtime that enables Aspire to orchestrate front-end and full-stack JS apps.

+ +
+
+
+ + Go +
+

The simple, efficient language for building reliable distributed services alongside Aspire.

+ +
+
+
+ Python logo + Python +
+

The versatile language powering data science, AI, and web services in the Aspire ecosystem.

+ +
+
+
+ Java logo + Java +
+

The enterprise workhorse that Aspire can orchestrate as part of polyglot architectures.

+ +
+
+
+ Rust logo + Rust +
+

The systems programming language bringing safety and speed to distributed apps.

+ +
+
+
+ + Deno +
+

The secure runtime for JavaScript and TypeScript with built-in tooling and web standards.

+ +
+
+
+ Bun logo + Bun +
+

The all-in-one JavaScript runtime and toolkit built for speed.

+ +
+
+
+ PowerShell logo + PowerShell +
+

The cross-platform task automation and configuration management framework.

+ +
+
+
+ Orleans logo + Orleans +
+

The virtual actor framework for building distributed, high-scale applications in .NET.

+ +
+
+
+ .NET MAUI logo + .NET MAUI +
+

The cross-platform framework for creating native mobile and desktop apps with .NET.

+ +
+
+ +## Testing frameworks + +The tools that help keep Aspire apps reliable. + +
+
+
+ xUnit.net logo + xUnit.net +
+

The community-focused unit testing tool for .NET — the backbone of Aspire's test story.

+ +
+
+
+ NUnit logo + NUnit +
+

The widely-used unit testing framework for all .NET languages.

+ +
+
+
+ Playwright logo + Playwright +
+

The end-to-end testing framework for modern web apps — reliable cross-browser automation.

+ +
+
+ +## Web stack & documentation + +The tools that power this very website. + +
+
+
+ + Astro +
+

The web framework for content-driven websites — the engine behind aspire.dev.

+ +
+
+
+ Starlight logo + Starlight +
+

The beautiful documentation theme for Astro that makes aspire.dev shine.

+ +
+
+
+ Expressive Code logo + Expressive Code +
+

The code block engine that makes our documentation examples beautiful and interactive.

+ +
+
+
+ Mermaid logo + Mermaid +
+

The JavaScript-based diagramming and charting tool that renders our architecture diagrams.

+ +
+
+
+ sharp logo + sharp +
+

The high-performance image processing library that optimizes every image on this site.

+ +
+
+
+ + pnpm +
+

The fast, disk-space efficient package manager that builds the aspire.dev front end.

+ +
+
+ +## UI & design + +The design systems that make Aspire look and feel polished. + +
+
+
+ + Fluent UI +
+

Microsoft's design system that powers the Aspire dashboard's components and visual language.

+ +
+
+
+ Spectre.Console logo + Spectre.Console +
+

The beautiful console library that powers the Aspire CLI's rich terminal experience.

+ +
+
+ +## Runtime & framework + +The bedrock of everything Aspire does — from the SDK and runtime to the Blazor-powered dashboard. + +
+
+
+ .NET logo + .NET +
+

The free, open-source, cross-platform framework that is the foundation of Aspire.

+ +
+
+
+ C# logo + C# +
+

The modern, type-safe language that makes Aspire's app model expressive and powerful.

+ +
+
+
+ Blazor logo + Blazor +
+

Powers the Aspire dashboard — a rich, interactive UI built entirely in .NET.

+ +
+
+
+ + Dapr +
+

The Distributed Application Runtime — portable, event-driven building blocks for microservices.

+ +
+
+ +## Developer experience & CLI + +The tools that make the Aspire developer experience smooth. + +
+
+
+ hex1b logo + hex1b +
+

The CLI automation tool for terminal applications — used to test and validate Aspire's CLI experiences.

+ +
+
+ +## And everyone else + +This page can't capture every dependency, every pull request, or every community conversation that +shaped Aspire into what it is today. To every contributor who filed an issue, opened a PR, answered +a question on Discord, or shipped a NuGet package that Aspire depends on — **thank you**. + + + + diff --git a/src/frontend/src/data/github-stats.json b/src/frontend/src/data/github-stats.json index c55a75ea0..3b59903cc 100644 --- a/src/frontend/src/data/github-stats.json +++ b/src/frontend/src/data/github-stats.json @@ -9,7 +9,7 @@ }, { "name": "dotnet/aspire-samples", - "stars": 1141, + "stars": 1142, "description": null, "license": "https://github.com/dotnet/aspire-samples/blob/main/LICENSE", "licenseName": "MIT License", @@ -25,7 +25,7 @@ }, { "name": "microsoft/aspire.dev", - "stars": 100, + "stars": 101, "description": "The official website for all things aspire.dev.", "license": "https://github.com/microsoft/aspire.dev/blob/main/LICENSE", "licenseName": "MIT License", From 9e5fdb4d6f38e0ea067e3ed41136ef3dbc8d4f2e Mon Sep 17 00:00:00 2001 From: David Pine Date: Tue, 24 Feb 2026 08:01:02 -0600 Subject: [PATCH 80/90] chore: add a few more OSS projects to highlight. --- .../src/assets/icons/asciinema-icon.svg | 10 + src/frontend/src/assets/icons/astro-icon.svg | 30 +- .../src/assets/icons/github-copilot.webp | Bin 0 -> 27164 bytes .../src/assets/icons/lunaria-icon.svg | 22 + .../src/content/docs/community/thanks.mdx | 1040 ++++++++++++++--- 5 files changed, 920 insertions(+), 182 deletions(-) create mode 100644 src/frontend/src/assets/icons/asciinema-icon.svg create mode 100644 src/frontend/src/assets/icons/github-copilot.webp create mode 100644 src/frontend/src/assets/icons/lunaria-icon.svg diff --git a/src/frontend/src/assets/icons/asciinema-icon.svg b/src/frontend/src/assets/icons/asciinema-icon.svg new file mode 100644 index 000000000..ac02ab5a6 --- /dev/null +++ b/src/frontend/src/assets/icons/asciinema-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/frontend/src/assets/icons/astro-icon.svg b/src/frontend/src/assets/icons/astro-icon.svg index 9a05073eb..f4e1ad58f 100644 --- a/src/frontend/src/assets/icons/astro-icon.svg +++ b/src/frontend/src/assets/icons/astro-icon.svg @@ -1 +1,29 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + diff --git a/src/frontend/src/assets/icons/github-copilot.webp b/src/frontend/src/assets/icons/github-copilot.webp new file mode 100644 index 0000000000000000000000000000000000000000..db1861fa0a0750d05fbc81ce809650d8a9edc619 GIT binary patch literal 27164 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 LegFUf000006D`6n literal 0 HcmV?d00001 diff --git a/src/frontend/src/assets/icons/lunaria-icon.svg b/src/frontend/src/assets/icons/lunaria-icon.svg new file mode 100644 index 000000000..3344cfe78 --- /dev/null +++ b/src/frontend/src/assets/icons/lunaria-icon.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/src/content/docs/community/thanks.mdx b/src/frontend/src/content/docs/community/thanks.mdx index b68c3250f..80cf59cb4 100644 --- a/src/frontend/src/content/docs/community/thanks.mdx +++ b/src/frontend/src/content/docs/community/thanks.mdx @@ -74,8 +74,6 @@ import mauiIcon from '@assets/icons/maui-icon.png'; {/* ── AI & ML ── */} import ollamaIcon from '@assets/icons/ollama-icon.png'; -import openaiIcon from '@assets/icons/openai-icon.png'; -import openaiLightIcon from '@assets/icons/openai-light-icon.png'; {/* ── Dapr ── */} import daprIcon from '@assets/icons/dapr-icon.png'; @@ -99,22 +97,38 @@ import csharpIcon from '@assets/icons/csharp.svg'; import blazorIcon from '@assets/icons/blazor-icon.svg'; import aspireIcon from '@assets/icons/aspire-icon.png'; +{/* ── Localization ── */} +import lunariaIcon from '@assets/icons/lunaria-icon.svg'; + {/* ── DevEx & CLI ── */} import hex1bIcon from '@assets/icons/hex1b-icon.svg'; +import asciinemaIcon from '@assets/icons/asciinema-icon.svg';
- +

Thank you, open source

-

- Standing on the
shoulders of giants -

-

- Aspire wouldn't exist without the incredible open-source projects and communities - that power the distributed apps ecosystem. This page is our thank-you to every contributor, - maintainer, and community member behind the tools we depend on. -

+
+
Standing on the
+
+ shoulders of giants +
+
+
+ Aspire wouldn't exist without the incredible open-source projects and + communities that power the distributed apps ecosystem. This page is our + thank-you to every contributor, maintainer, and community member behind the + tools we depend on. +

We 💜 open source

@@ -126,23 +140,47 @@ The eyes, ears, and safety nets of distributed systems.
- OpenTelemetry logo + OpenTelemetry logo OpenTelemetry
-

The vendor-neutral observability standard that gives Aspire its distributed traces, metrics, and logs.

+

+ The vendor-neutral observability standard that gives Aspire its + distributed traces, metrics, and logs. +

- Polly logo + Polly logo Polly
-

The resilience and transient-fault-handling library behind Aspire's default retry and circuit-breaker policies.

+

+ The resilience and transient-fault-handling library behind Aspire's + default retry and circuit-breaker policies. +

@@ -154,90 +192,188 @@ The data engines Aspire integrates with out of the box.
- PostgreSQL logo + PostgreSQL logo PostgreSQL

The world's most advanced open-source relational database.

- MongoDB logo + MongoDB logo MongoDB

The document database for modern application development.

- Redis logo + Redis logo Redis
-

The high-performance in-memory data store used for caching, messaging, and more.

+

+ The high-performance in-memory data store used for caching, messaging, and + more. +

- Valkey logo + Valkey logo Valkey

The open-source, high-performance key/value store.

- Garnet logo + Garnet logo Garnet

A high-performance cache-store from Microsoft Research.

- Milvus logo + Milvus logo Milvus

The open-source vector database for AI-powered similarity search.

- Qdrant logo + Qdrant logo Qdrant

The vector search engine for next-generation AI applications.

- SQLite logo + SQLite logo SQLite

The most widely deployed database engine in the world.

@@ -249,35 +385,67 @@ The plumbing that keeps distributed services talking to each other.
- RabbitMQ logo + RabbitMQ logo RabbitMQ

The most widely deployed open-source message broker.

- NATS logo + NATS logo NATS

High-performance messaging for distributed apps and edge computing.

- Apache Kafka logo + Apache Kafka logo Apache Kafka
-

The distributed event streaming platform used by thousands of companies.

+

+ The distributed event streaming platform used by thousands of companies. +

@@ -289,23 +457,47 @@ The traffic directors and protocol layers that connect services.
- YARP logo + YARP logo YARP
-

Yet Another Reverse Proxy — a highly customizable reverse proxy library built on .NET.

+

+ Yet Another Reverse Proxy — a highly customizable reverse proxy library + built on .NET. +

- gRPC logo + gRPC logo gRPC

The high-performance, open-source universal RPC framework.

@@ -317,34 +509,77 @@ The engines that package, ship, and run distributed workloads.
- Docker logo + Docker logo Docker
-

The platform that popularized containers and makes local development with Aspire seamless.

+

+ The platform that popularized containers and makes local development with + Aspire seamless. +

- Podman logo + Podman logo Podman
-

The daemonless container engine for developing, managing, and running OCI containers.

+

+ The daemonless container engine for developing, managing, and running OCI + containers. +

- Kubernetes logo + Kubernetes logo Kubernetes
-

The open-source system for automating deployment, scaling, and management of containerized applications.

+

+ The open-source system for automating deployment, scaling, and management + of containerized applications. +

@@ -356,42 +591,59 @@ Tools that simplify common dev-time workflows.
- + Mailpit
-

An email and SMTP testing tool with a modern web UI, perfect for local development.

+

+ An email and SMTP testing tool with a modern web UI, perfect for local + development. +

## AI & machine learning -The projects powering Aspire's AI integrations. +The open-source projects powering Aspire's AI integrations.
- Ollama logo + Ollama logo Ollama
-

Run large language models locally — the easiest way to bring AI into your Aspire apps.

+

+ Run large language models locally — the easiest way to bring AI into your + Aspire apps. +

-
-
-
- - OpenAI -
-

The AI research lab behind GPT, DALL-E, and the APIs that Aspire integrates with natively.

-
@@ -403,112 +655,253 @@ Aspire speaks many languages — thanks to these communities.
- + Node.js
-

The JavaScript runtime that enables Aspire to orchestrate front-end and full-stack JS apps.

+

+ The JavaScript runtime that enables Aspire to orchestrate front-end and + full-stack JS apps. +

- + Go
-

The simple, efficient language for building reliable distributed services alongside Aspire.

+

+ The simple, efficient language for building reliable distributed services + alongside Aspire. +

- Python logo + Python logo Python
-

The versatile language powering data science, AI, and web services in the Aspire ecosystem.

+

+ The versatile language powering data science, AI, and web services in the + Aspire ecosystem. +

- Java logo + Java logo Java
-

The enterprise workhorse that Aspire can orchestrate as part of polyglot architectures.

+

+ The enterprise workhorse that Aspire can orchestrate as part of polyglot + architectures. +

- Rust logo + Rust logo Rust
-

The systems programming language bringing safety and speed to distributed apps.

+

+ The systems programming language bringing safety and speed to distributed + apps. +

- + Deno
-

The secure runtime for JavaScript and TypeScript with built-in tooling and web standards.

+

+ The secure runtime for JavaScript and TypeScript with built-in tooling and + web standards. +

- Bun logo + Bun logo Bun

The all-in-one JavaScript runtime and toolkit built for speed.

- PowerShell logo + PowerShell logo PowerShell
-

The cross-platform task automation and configuration management framework.

+

+ The cross-platform task automation and configuration management framework. +

- Orleans logo + Orleans logo Orleans
-

The virtual actor framework for building distributed, high-scale applications in .NET.

+

+ The virtual actor framework for building distributed, high-scale + applications in .NET. +

- .NET MAUI logo + .NET MAUI logo .NET MAUI
-

The cross-platform framework for creating native mobile and desktop apps with .NET.

+

+ The cross-platform framework for creating native mobile and desktop apps + with .NET. +

@@ -520,32 +913,108 @@ The tools that help keep Aspire apps reliable.
- xUnit.net logo + xUnit.net logo xUnit.net
-

The community-focused unit testing tool for .NET — the backbone of Aspire's test story.

+

+ The community-focused unit testing tool for .NET — the backbone of + Aspire's test story. +

- NUnit logo + NUnit logo NUnit

The widely-used unit testing framework for all .NET languages.

- Playwright logo + Playwright logo Playwright
-

The end-to-end testing framework for modern web apps — reliable cross-browser automation.

+

+ The end-to-end testing framework for modern web apps — reliable + cross-browser automation. +

+ +
+
+ +## Localization + +The tools that help us speak every language. + +
+
+
+ Lunaria logo + Lunaria +
+

+ The localization management tool that tracks translation status for Astro + and Starlight sites. +

@@ -557,62 +1026,131 @@ The tools that power this very website.
- + Astro
-

The web framework for content-driven websites — the engine behind aspire.dev.

+

+ The web framework for content-driven websites — the engine behind + aspire.dev. +

- Starlight logo + Starlight logo Starlight
-

The beautiful documentation theme for Astro that makes aspire.dev shine.

+

+ The beautiful documentation theme for Astro that makes aspire.dev shine. +

- Expressive Code logo + Expressive Code logo Expressive Code
-

The code block engine that makes our documentation examples beautiful and interactive.

+

+ The code block engine that makes our documentation examples beautiful and + interactive. +

- Mermaid logo + Mermaid logo Mermaid
-

The JavaScript-based diagramming and charting tool that renders our architecture diagrams.

+

+ The JavaScript-based diagramming and charting tool that renders our + architecture diagrams. +

- sharp logo + sharp logo sharp
-

The high-performance image processing library that optimizes every image on this site.

+

+ The high-performance image processing library that optimizes every image + on this site. +

- + pnpm
-

The fast, disk-space efficient package manager that builds the aspire.dev front end.

+

+ The fast, disk-space efficient package manager that builds the aspire.dev + front end. +

@@ -624,22 +1162,52 @@ The design systems that make Aspire look and feel polished.
- + Fluent UI
-

Microsoft's design system that powers the Aspire dashboard's components and visual language.

+

+ Microsoft's design system that powers the Aspire dashboard's components + and visual language. +

- Spectre.Console logo + Spectre.Console logo Spectre.Console
-

The beautiful console library that powers the Aspire CLI's rich terminal experience.

+

+ The beautiful console library that powers the Aspire CLI's rich terminal + experience. +

@@ -651,44 +1219,100 @@ The bedrock of everything Aspire does — from the SDK and runtime to the Blazor
- .NET logo + .NET logo .NET
-

The free, open-source, cross-platform framework that is the foundation of Aspire.

+

+ The free, open-source, cross-platform framework that is the foundation of + Aspire. +

- C# logo + C# logo C#
-

The modern, type-safe language that makes Aspire's app model expressive and powerful.

+

+ The modern, type-safe language that makes Aspire's app model expressive + and powerful. +

- Blazor logo + Blazor logo Blazor
-

Powers the Aspire dashboard — a rich, interactive UI built entirely in .NET.

+

+ Powers the Aspire dashboard — a rich, interactive UI built entirely in + .NET. +

- + Dapr
-

The Distributed Application Runtime — portable, event-driven building blocks for microservices.

+

+ The Distributed Application Runtime — portable, event-driven building + blocks for microservices. +

@@ -700,12 +1324,44 @@ The tools that make the Aspire developer experience smooth.
- hex1b logo + hex1b logo hex1b
-

The CLI automation tool for terminal applications — used to test and validate Aspire's CLI experiences.

+

+ The CLI automation tool for terminal applications — used to test and + validate Aspire's CLI experiences. +

+
+
+
+ asciinema logo + asciinema +
+

+ The terminal session recorder that powers the animated CLI demos on + aspire.dev. +

+
@@ -719,8 +1375,14 @@ a question on Discord, or shipped a NuGet package that Aspire depends on — **t diff --git a/src/frontend/src/content/docs/community/thanks.mdx b/src/frontend/src/content/docs/community/thanks.mdx index ed166f8b6..c989affd9 100644 --- a/src/frontend/src/content/docs/community/thanks.mdx +++ b/src/frontend/src/content/docs/community/thanks.mdx @@ -3,7 +3,7 @@ title: Thank you description: Celebrating the open-source projects and communities that make Aspire possible. editUrl: false giscus: false -tableOfContents: true +tableOfContents: false pageActions: false lastUpdated: false --- diff --git a/src/frontend/src/content/i18n/da.json b/src/frontend/src/content/i18n/da.json index 3aacf6d34..be48ddcf1 100644 --- a/src/frontend/src/content/i18n/da.json +++ b/src/frontend/src/content/i18n/da.json @@ -40,6 +40,14 @@ "uniqueTags": "Unikke tags", "totalDownloads": "Samlede downloads", "clear": "Ryd", + "official": "Officiel", + "officialTooltip": "Skift officielle Aspire-integrationer", + "community": "Fællesskab", + "communityTooltip": "Skift fællesskabsintegrationer", + "hosting": "Hosting", + "hostingTooltip": "Vis/skjul hosting-integrationer", + "client": "Klient", + "clientTooltip": "Vis/skjul klient-integrationer", "search": "Søg integrationer...", "noResults": "Prøv at søge efter f.eks. \"SQL\", \"Cache\" eller \"Testing\" for at finde integrationer!", "explore": "Udforsk {{integration}}-integrationer" diff --git a/src/frontend/src/content/i18n/de.json b/src/frontend/src/content/i18n/de.json index 9fab998bb..781efbaa1 100644 --- a/src/frontend/src/content/i18n/de.json +++ b/src/frontend/src/content/i18n/de.json @@ -40,6 +40,14 @@ "uniqueTags": "Eindeutige Tags", "totalDownloads": "Gesamt-Downloads", "clear": "Leeren", + "official": "Offiziell", + "officialTooltip": "Offizielle Aspire-Integrationen ein-/ausblenden", + "community": "Community", + "communityTooltip": "Community-Integrationen ein-/ausblenden", + "hosting": "Hosting", + "hostingTooltip": "Hosting-Integrationen ein-/ausblenden", + "client": "Client", + "clientTooltip": "Client-Integrationen ein-/ausblenden", "search": "Integrationen suchen...", "noResults": "Such z.B. nach \"SQL\", \"Cache\" oder \"Testing\" um Integrationen zu entdecken!", "explore": "Erkunde {{integration}}-Integrationen" diff --git a/src/frontend/src/content/i18n/en.json b/src/frontend/src/content/i18n/en.json index 5b52a63f6..90f8ede55 100644 --- a/src/frontend/src/content/i18n/en.json +++ b/src/frontend/src/content/i18n/en.json @@ -40,6 +40,14 @@ "uniqueTags": "Unique Tags", "totalDownloads": "Total Downloads", "clear": "Clear", + "official": "Official", + "officialTooltip": "Toggle official Aspire integrations", + "community": "Community", + "communityTooltip": "Toggle community integrations", + "hosting": "Hosting", + "hostingTooltip": "Toggle hosting integrations", + "client": "Client", + "clientTooltip": "Toggle client integrations", "search": "Search integrations...", "noResults": "Try searching for things like \"SQL\", \"Cache\", or \"Testing\" to discover integrations!", "explore": "Explore {{integration}} integrations" diff --git a/src/frontend/src/content/i18n/es.json b/src/frontend/src/content/i18n/es.json index 8804c43a3..9d899b0ad 100644 --- a/src/frontend/src/content/i18n/es.json +++ b/src/frontend/src/content/i18n/es.json @@ -40,6 +40,14 @@ "uniqueTags": "Etiquetas únicas", "totalDownloads": "Descargas totales", "clear": "Limpiar", + "official": "Oficial", + "officialTooltip": "Mostrar/ocultar integraciones oficiales de Aspire", + "community": "Comunidad", + "communityTooltip": "Mostrar/ocultar integraciones de la comunidad", + "hosting": "Hosting", + "hostingTooltip": "Mostrar/ocultar integraciones de hosting", + "client": "Cliente", + "clientTooltip": "Mostrar/ocultar integraciones de cliente", "search": "Buscar integraciones...", "noResults": "Prueba a buscar cosas como \"SQL\", \"Cache\" o \"Testing\" para descubrir integraciones!", "explore": "Explora las integraciones de {{integration}}" diff --git a/src/frontend/src/content/i18n/fr.json b/src/frontend/src/content/i18n/fr.json index 0abae2e46..e3ad7e87e 100644 --- a/src/frontend/src/content/i18n/fr.json +++ b/src/frontend/src/content/i18n/fr.json @@ -40,6 +40,14 @@ "uniqueTags": "Tags uniques", "totalDownloads": "Téléchargements totaux", "clear": "Effacer", + "official": "Officiel", + "officialTooltip": "Afficher/masquer les intégrations officielles Aspire", + "community": "Communauté", + "communityTooltip": "Afficher/masquer les intégrations communautaires", + "hosting": "Hébergement", + "hostingTooltip": "Afficher/masquer les intégrations d'hébergement", + "client": "Client", + "clientTooltip": "Afficher/masquer les intégrations client", "search": "Rechercher des intégrations...", "noResults": "Essayez des recherches comme \"SQL\", \"Cache\" ou \"Testing\" pour découvrir des intégrations !", "explore": "Explorez les intégrations {{integration}}" diff --git a/src/frontend/src/content/i18n/hi.json b/src/frontend/src/content/i18n/hi.json index 60bc1a201..a40960c6e 100644 --- a/src/frontend/src/content/i18n/hi.json +++ b/src/frontend/src/content/i18n/hi.json @@ -40,6 +40,14 @@ "uniqueTags": "अद्वितीय टैग", "totalDownloads": "कुल डाउनलोड", "clear": "साफ़ करें", + "official": "आधिकारिक", + "officialTooltip": "आधिकारिक Aspire इंटीग्रेशन टॉगल करें", + "community": "समुदाय", + "communityTooltip": "समुदाय इंटीग्रेशन टॉगल करें", + "hosting": "होस्टिंग", + "hostingTooltip": "होस्टिंग इंटीग्रेशन टॉगल करें", + "client": "क्लाइंट", + "clientTooltip": "क्लाइंट इंटीग्रेशन टॉगल करें", "search": "इंटीग्रेशन खोजें...", "noResults": "इंटीग्रेशन खोजने के लिए \"SQL\", \"Cache\" या \"Testing\" जैसे शब्द आज़माएँ!", "explore": "{{integration}} इंटीग्रेशन का अन्वेषण करें" diff --git a/src/frontend/src/content/i18n/id.json b/src/frontend/src/content/i18n/id.json index d88fa8a74..1b408f78e 100644 --- a/src/frontend/src/content/i18n/id.json +++ b/src/frontend/src/content/i18n/id.json @@ -40,6 +40,14 @@ "uniqueTags": "Tag Unik", "totalDownloads": "Total Unduhan", "clear": "Bersihkan", + "official": "Resmi", + "officialTooltip": "Tampilkan/sembunyikan integrasi resmi Aspire", + "community": "Komunitas", + "communityTooltip": "Tampilkan/sembunyikan integrasi komunitas", + "hosting": "Hosting", + "hostingTooltip": "Tampilkan/sembunyikan integrasi hosting", + "client": "Klien", + "clientTooltip": "Tampilkan/sembunyikan integrasi klien", "search": "Cari integrasi...", "noResults": "Coba cari \"SQL\", \"Cache\" atau \"Testing\" untuk menemukan integrasi!", "explore": "Jelajahi integrasi {{integration}}" diff --git a/src/frontend/src/content/i18n/it.json b/src/frontend/src/content/i18n/it.json index 449465512..808f01462 100644 --- a/src/frontend/src/content/i18n/it.json +++ b/src/frontend/src/content/i18n/it.json @@ -40,6 +40,14 @@ "uniqueTags": "Tag unici", "totalDownloads": "Download totali", "clear": "Pulisci", + "official": "Ufficiale", + "officialTooltip": "Mostra/nascondi integrazioni ufficiali Aspire", + "community": "Community", + "communityTooltip": "Mostra/nascondi integrazioni della community", + "hosting": "Hosting", + "hostingTooltip": "Mostra/nascondi integrazioni di hosting", + "client": "Client", + "clientTooltip": "Mostra/nascondi integrazioni client", "search": "Cerca integrazioni...", "noResults": "Prova a cercare \"SQL\", \"Cache\" o \"Testing\" per scoprire integrazioni!", "explore": "Esplora le integrazioni {{integration}}" diff --git a/src/frontend/src/content/i18n/ja.json b/src/frontend/src/content/i18n/ja.json index 2172daaf2..bc875657e 100644 --- a/src/frontend/src/content/i18n/ja.json +++ b/src/frontend/src/content/i18n/ja.json @@ -40,6 +40,14 @@ "uniqueTags": "ユニークタグ", "totalDownloads": "総ダウンロード数", "clear": "クリア", + "official": "公式", + "officialTooltip": "公式Aspireインテグレーションの表示切り替え", + "community": "コミュニティ", + "communityTooltip": "コミュニティインテグレーションの表示切り替え", + "hosting": "ホスティング", + "hostingTooltip": "ホスティングインテグレーションの表示切り替え", + "client": "クライアント", + "clientTooltip": "クライアントインテグレーションの表示切り替え", "search": "連携を検索...", "noResults": "統合を探すには \"SQL\"、\"Cache\"、\"Testing\" などを検索してみてください!", "explore": "{{integration}} の連携を探索" diff --git a/src/frontend/src/content/i18n/ko.json b/src/frontend/src/content/i18n/ko.json index c199bb04a..6b6bad1ee 100644 --- a/src/frontend/src/content/i18n/ko.json +++ b/src/frontend/src/content/i18n/ko.json @@ -40,6 +40,14 @@ "uniqueTags": "고유 태그", "totalDownloads": "총 다운로드 수", "clear": "지우기", + "official": "공식", + "officialTooltip": "공식 Aspire 통합 토글", + "community": "커뮤니티", + "communityTooltip": "커뮤니티 통합 토글", + "hosting": "호스팅", + "hostingTooltip": "호스팅 통합 토글", + "client": "클라이언트", + "clientTooltip": "클라이언트 통합 토글", "search": "통합 검색...", "noResults": "\"SQL\", \"Cache\", \"Testing\" 등을 검색해 통합을 찾아보세요!", "explore": "{{integration}} 통합을 탐색" diff --git a/src/frontend/src/content/i18n/pt-BR.json b/src/frontend/src/content/i18n/pt-BR.json index 9c60513e2..8614353cd 100644 --- a/src/frontend/src/content/i18n/pt-BR.json +++ b/src/frontend/src/content/i18n/pt-BR.json @@ -40,6 +40,14 @@ "uniqueTags": "Tags Únicas", "totalDownloads": "Total de Downloads", "clear": "Limpar", + "official": "Oficial", + "officialTooltip": "Mostrar/ocultar integrações oficiais do Aspire", + "community": "Comunidade", + "communityTooltip": "Mostrar/ocultar integrações da comunidade", + "hosting": "Hospedagem", + "hostingTooltip": "Mostrar/ocultar integrações de hospedagem", + "client": "Cliente", + "clientTooltip": "Mostrar/ocultar integrações de cliente", "search": "Pesquisar integrações...", "noResults": "Tente pesquisar por \"SQL\", \"Cache\" ou \"Testing\" para descobrir integrações!", "explore": "Explore integrações de {{integration}}" diff --git a/src/frontend/src/content/i18n/pt-PT.json b/src/frontend/src/content/i18n/pt-PT.json index cd33c6271..9bf94040a 100644 --- a/src/frontend/src/content/i18n/pt-PT.json +++ b/src/frontend/src/content/i18n/pt-PT.json @@ -40,6 +40,14 @@ "uniqueTags": "Tags Únicas", "totalDownloads": "Total de Downloads", "clear": "Limpar", + "official": "Oficial", + "officialTooltip": "Mostrar/ocultar integrações oficiais do Aspire", + "community": "Comunidade", + "communityTooltip": "Mostrar/ocultar integrações da comunidade", + "hosting": "Alojamento", + "hostingTooltip": "Mostrar/ocultar integrações de alojamento", + "client": "Cliente", + "clientTooltip": "Mostrar/ocultar integrações de cliente", "search": "Procurar integrações...", "noResults": "Experimenta procurar por \"SQL\", \"Cache\" ou \"Testing\" para descobrir integrações!", "explore": "Explora integrações de {{integration}}" diff --git a/src/frontend/src/content/i18n/ru.json b/src/frontend/src/content/i18n/ru.json index d8d8140e4..d42839f8f 100644 --- a/src/frontend/src/content/i18n/ru.json +++ b/src/frontend/src/content/i18n/ru.json @@ -40,6 +40,14 @@ "uniqueTags": "Уникальные теги", "totalDownloads": "Всего загрузок", "clear": "Очистить", + "official": "Официальный", + "officialTooltip": "Показать/скрыть официальные интеграции Aspire", + "community": "Сообщество", + "communityTooltip": "Показать/скрыть интеграции сообщества", + "hosting": "Хостинг", + "hostingTooltip": "Показать/скрыть интеграции хостинга", + "client": "Клиент", + "clientTooltip": "Показать/скрыть клиентские интеграции", "search": "Поиск интеграций...", "noResults": "Попробуйте искать \"SQL\", \"Cache\" или \"Testing\", чтобы найти интеграции!", "explore": "Исследуйте интеграции {{integration}}" diff --git a/src/frontend/src/content/i18n/tr.json b/src/frontend/src/content/i18n/tr.json index fb1189e15..9f5719e75 100644 --- a/src/frontend/src/content/i18n/tr.json +++ b/src/frontend/src/content/i18n/tr.json @@ -40,6 +40,14 @@ "uniqueTags": "Benzersiz Etiketler", "totalDownloads": "Toplam İndirme", "clear": "Temizle", + "official": "Resmi", + "officialTooltip": "Resmi Aspire entegrasyonlarını göster/gizle", + "community": "Topluluk", + "communityTooltip": "Topluluk entegrasyonlarını göster/gizle", + "hosting": "Barındırma", + "hostingTooltip": "Barındırma entegrasyonlarını göster/gizle", + "client": "İstemci", + "clientTooltip": "İstemci entegrasyonlarını göster/gizle", "search": "Entegrasyon ara...", "noResults": "Entegrasyon bulmak için \"SQL\", \"Cache\" veya \"Testing\" aramayı deneyin!", "explore": "{{integration}} entegrasyonlarını keşfet" diff --git a/src/frontend/src/content/i18n/uk.json b/src/frontend/src/content/i18n/uk.json index d88f3919f..a6a037c2e 100644 --- a/src/frontend/src/content/i18n/uk.json +++ b/src/frontend/src/content/i18n/uk.json @@ -40,6 +40,14 @@ "uniqueTags": "Унікальні теги", "totalDownloads": "Всього завантажень", "clear": "Очистити", + "official": "Офіційний", + "officialTooltip": "Показати/сховати офіційні інтеграції Aspire", + "community": "Спільнота", + "communityTooltip": "Показати/сховати інтеграції спільноти", + "hosting": "Хостинг", + "hostingTooltip": "Показати/сховати інтеграції хостингу", + "client": "Клієнт", + "clientTooltip": "Показати/сховати клієнтські інтеграції", "search": "Шукати інтеграції...", "noResults": "Спробуйте пошукати \"SQL\", \"Cache\" або \"Testing\" щоб знайти інтеграції!", "explore": "Досліджуйте інтеграції {{integration}}" diff --git a/src/frontend/src/content/i18n/zh-CN.json b/src/frontend/src/content/i18n/zh-CN.json index 9069d8f9a..a2c2e1441 100644 --- a/src/frontend/src/content/i18n/zh-CN.json +++ b/src/frontend/src/content/i18n/zh-CN.json @@ -40,6 +40,14 @@ "uniqueTags": "唯一标签", "totalDownloads": "总下载量", "clear": "清除", + "official": "官方", + "officialTooltip": "切换官方 Aspire 集成", + "community": "社区", + "communityTooltip": "切换社区集成", + "hosting": "托管", + "hostingTooltip": "显示/隐藏托管集成", + "client": "客户端", + "clientTooltip": "显示/隐藏客户端集成", "search": "搜索集成...", "noResults": "尝试搜索 \"SQL\"、\"Cache\" 或 \"Testing\" 来发现集成!", "explore": "探索 {{integration}} 集成" From cbdb8cfe595d60975dd9cee3723ff2e573940b54 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 25 Feb 2026 14:58:17 -0600 Subject: [PATCH 89/90] Add Azure Container Registry WithPurgeTask documentation. (#474) See https://github.com/dotnet/aspire/pull/14683 --- .../cloud/azure/azure-container-registry.mdx | 30 +++++++++++++++++-- .../content/docs/whats-new/aspire-13-2.mdx | 15 ++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-container-registry.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-container-registry.mdx index f676d0822..46c926d6c 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-container-registry.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-container-registry.mdx @@ -36,6 +36,7 @@ The Azure Container Registry integration supports the following scenarios: - **Referencing an existing registry**: Use an existing Azure Container Registry by providing its name and resource group. - **Credential management**: Automatically flow credentials to compute environments for secure image pulls. - **Role assignments**: Assign specific roles (for example, `AcrPush`) to enable services to push images to the registry. +- **Scheduled image cleanup**: Automatically remove old or unused container images on a cron schedule with purge tasks. ## Hosting integration @@ -111,20 +112,45 @@ The preceding code: ### Access the registry from a compute environment -Compute environments such as `AzureContainerAppEnvironment` and `AzureAppServiceEnvironment` automatically provision a default Azure Container Registry. You can also specify an explicit registry with `WithAzureContainerRegistry`. In either case, access the registry through the `ContainerRegistry` property: +Compute environments such as `AzureContainerAppEnvironment` and `AzureAppServiceEnvironment` automatically provision a default Azure Container Registry. You can also specify an explicit registry with `WithAzureContainerRegistry`. To get a resource builder for the associated registry, use the `GetAzureContainerRegistry` method: ```csharp title="C# — Access the registry from the compute environment" var env = builder.AddAzureContainerAppEnvironment("env"); // A default registry is auto-provisioned — no need to call // WithAzureContainerRegistry unless you want a specific one -var registry = env.Resource.ContainerRegistry; +var registry = env.GetAzureContainerRegistry(); ``` +This returns an `IResourceBuilder` that you can use for further configuration, such as adding [purge tasks](#schedule-image-cleanup-with-purge-tasks). + +### Schedule image cleanup with purge tasks + +Over time, container registries accumulate old images that consume storage and increase costs. The `WithPurgeTask` method adds a scheduled [ACR purge task](https://learn.microsoft.com/azure/container-registry/container-registry-auto-purge) that automatically removes old or unused container images on a cron schedule: + +```csharp title="C# — Add a purge task" +var acr = builder.AddAzureContainerRegistry("my-acr") + .WithPurgeTask("0 1 * * *", ago: TimeSpan.FromDays(7), keep: 5); +``` + +The preceding code creates a purge task that runs daily at 1:00 AM, removing images older than 7 days while keeping the 5 most recent images per repository. + +#### Multiple purge tasks + +You can add multiple purge tasks to a single registry, each with different schedules and filters: + +```csharp title="C# — Multiple purge tasks" +var acr = builder.AddAzureContainerRegistry("my-acr") + .WithPurgeTask("0 1 * * *", filter: "app1:.*", keep: 3) + .WithPurgeTask("0 2 * * 0", filter: "app2:.*", ago: TimeSpan.FromDays(30), keep: 10); +``` + +Each purge task is given a unique name automatically. You can also specify a custom task name with the `taskName` parameter. + ### Key features **Automatic credential flow** 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 ac22f4681..b22d8dfd5 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 @@ -330,6 +330,21 @@ For more details, see [Azure AI Inference integration](/integrations/cloud/azure For more details, see [Azure App Service integration](/integrations/cloud/azure/azure-app-service/). +### Azure Container Registry + +The Azure Container Registry integration now supports scheduled image cleanup with the new `WithPurgeTask` method. This provisions an [ACR purge task](https://learn.microsoft.com/azure/container-registry/container-registry-auto-purge) that automatically removes old or unused container images on a cron schedule: + +```csharp title="C# — Schedule ACR image cleanup" +var acr = builder.AddAzureContainerRegistry("my-acr") + .WithPurgeTask("0 1 * * *", ago: TimeSpan.FromDays(7), keep: 5); +``` + +Additionally, the new `GetAzureContainerRegistry` method makes it easy to access the registry from a compute environment for further configuration. + + +For more details, see [Azure Container Registry integration](/integrations/cloud/azure/azure-container-registry/). + + ### Database integrations - **MongoDB**: Connection string options now correctly prepend forward slash From da7d55c1ba6394c82b84b2c797f00026354fc3b4 Mon Sep 17 00:00:00 2001 From: David Pine Date: Wed, 25 Feb 2026 15:29:21 -0600 Subject: [PATCH 90/90] Add samples catalog: skill, data pipeline, and browsable samples page (#479) * chore: Add samples data and update SKILL based on aspire-samples repo. * feat: add SampleCard and SampleGrid components for displaying sample projects - Implemented SampleCard component to render individual sample details including title, description, tags, and thumbnail. - Created SampleGrid component to manage and display a grid of SampleCard components, including search and filter functionality. - Added a new documentation page for samples, integrating SampleGrid to showcase available sample projects. * feat: refactor tag label handling into a shared utility module * feat: enhance tag handling and improve error management in sample updates --- .github/skills/update-samples/SKILL.md | 153 +++++++ .../config/sidebar/reference.topics.ts | 23 + src/frontend/package.json | 10 +- src/frontend/pnpm-lock.yaml | 10 + src/frontend/scripts/update-samples.js | 300 +++++++++++++ .../samples/Metrics/dashboard-screenshot.png | Bin 0 -> 448100 bytes .../aspireshop-frontend-complete.png | Bin 0 -> 1037441 bytes .../aspire-with-functions.png | Bin 0 -> 214611 bytes .../aspire-with-javascript/angular-app.png | Bin 0 -> 84454 bytes .../aspire-dashboard.png | Bin 0 -> 86990 bytes .../aspire-with-javascript/react-app.png | Bin 0 -> 77131 bytes .../aspire-with-javascript/vue-app.png | Bin 0 -> 69327 bytes .../client-apps-dashboard-winforms.png | Bin 0 -> 115072 bytes .../aspire-dashboard-container-build.png | Bin 0 -> 53239 bytes .../db-containers-apiservice-swagger-ui.png | Bin 0 -> 109756 bytes .../samples/health-checks-ui/aca-diagram.svg | 21 + .../health-checks-ui/healthchecksui.png | Bin 0 -> 106333 bytes .../aspire-dashboard-container-log.png | Bin 0 -> 101706 bytes .../aspire-dashboard-screenshot.png | Bin 0 -> 286207 bytes ...lume-mount-frontend-account-registered.png | Bin 0 -> 115903 bytes .../volume-mount-frontend-dbcontext-error.png | Bin 0 -> 118181 bytes .../volume-mount-frontend-email-confirmed.png | Bin 0 -> 95526 bytes .../volume-mount-frontend-login.png | Bin 0 -> 159175 bytes .../volume-mount-frontend-register.png | Bin 0 -> 153433 bytes src/frontend/src/components/SampleCard.astro | 362 +++++++++++++++ src/frontend/src/components/SampleGrid.astro | 417 ++++++++++++++++++ .../src/content/docs/reference/overview.mdx | 18 + .../src/content/docs/reference/samples.mdx | 17 + src/frontend/src/data/github-stats.json | 4 +- src/frontend/src/data/samples.json | 231 ++++++++++ src/frontend/src/utils/sample-tags.ts | 40 ++ 31 files changed, 1600 insertions(+), 6 deletions(-) create mode 100644 .github/skills/update-samples/SKILL.md create mode 100644 src/frontend/scripts/update-samples.js create mode 100644 src/frontend/src/assets/samples/Metrics/dashboard-screenshot.png create mode 100644 src/frontend/src/assets/samples/aspire-shop/aspireshop-frontend-complete.png create mode 100644 src/frontend/src/assets/samples/aspire-with-azure-functions/aspire-with-functions.png create mode 100644 src/frontend/src/assets/samples/aspire-with-javascript/angular-app.png create mode 100644 src/frontend/src/assets/samples/aspire-with-javascript/aspire-dashboard.png create mode 100644 src/frontend/src/assets/samples/aspire-with-javascript/react-app.png create mode 100644 src/frontend/src/assets/samples/aspire-with-javascript/vue-app.png create mode 100644 src/frontend/src/assets/samples/client-apps-integration/client-apps-dashboard-winforms.png create mode 100644 src/frontend/src/assets/samples/container-build/aspire-dashboard-container-build.png create mode 100644 src/frontend/src/assets/samples/database-containers/db-containers-apiservice-swagger-ui.png create mode 100644 src/frontend/src/assets/samples/health-checks-ui/aca-diagram.svg create mode 100644 src/frontend/src/assets/samples/health-checks-ui/healthchecksui.png create mode 100644 src/frontend/src/assets/samples/standalone-dashboard/aspire-dashboard-container-log.png create mode 100644 src/frontend/src/assets/samples/standalone-dashboard/aspire-dashboard-screenshot.png create mode 100644 src/frontend/src/assets/samples/volume-mount/volume-mount-frontend-account-registered.png create mode 100644 src/frontend/src/assets/samples/volume-mount/volume-mount-frontend-dbcontext-error.png create mode 100644 src/frontend/src/assets/samples/volume-mount/volume-mount-frontend-email-confirmed.png create mode 100644 src/frontend/src/assets/samples/volume-mount/volume-mount-frontend-login.png create mode 100644 src/frontend/src/assets/samples/volume-mount/volume-mount-frontend-register.png create mode 100644 src/frontend/src/components/SampleCard.astro create mode 100644 src/frontend/src/components/SampleGrid.astro create mode 100644 src/frontend/src/content/docs/reference/samples.mdx create mode 100644 src/frontend/src/data/samples.json create mode 100644 src/frontend/src/utils/sample-tags.ts diff --git a/.github/skills/update-samples/SKILL.md b/.github/skills/update-samples/SKILL.md new file mode 100644 index 000000000..eb1c24888 --- /dev/null +++ b/.github/skills/update-samples/SKILL.md @@ -0,0 +1,153 @@ +--- +name: update-samples +description: Update the samples data file by fetching sample metadata from the dotnet/aspire-samples GitHub repository. Use when adding new samples, refreshing sample data, or ensuring samples.json stays in sync with the upstream repo. +--- + +# Update Samples Data + +This skill synchronizes the samples data file with the `dotnet/aspire-samples` GitHub repository. It enumerates all sample projects in the `samples/` directory, fetches each sample's README.md, and generates a structured JSON catalog. + +## Overview + +The aspire.dev site maintains a data file for samples: + +- **`src/frontend/src/data/samples.json`** — Sample metadata including titles, descriptions, tags, deep links, and README content extracted from the upstream repo. + +This skill keeps that file in sync with the `dotnet/aspire-samples` repository on GitHub. + +## Prerequisites + +- Node.js installed and available on `PATH` +- Working directory is the repository root +- The frontend project dependencies are installed (`pnpm install` in `src/frontend/`) +- Optional: `GITHUB_TOKEN` environment variable for higher GitHub API rate limits + +## Step-by-Step Process + +### 1. Run the update script + +Fetch the latest sample data from the GitHub API: + +```bash +cd src/frontend && node scripts/update-samples.js +``` + +This writes updated sample metadata to `src/frontend/src/data/samples.json`. The script queries the GitHub Contents API for directories in `dotnet/aspire-samples/samples/`, fetches each sample's README.md, and extracts structured metadata. + +### 2. What the script does + +For each subdirectory in `samples/`: + +1. **Lists directories** — Calls the GitHub Contents API to enumerate entries in `samples/` and filters to directories only (skipping files like `global.json`, `Directory.Build.props`). + +2. **Fetches README.md** — Downloads the raw README.md for each sample directory. + +3. **Extracts metadata** from the README: + - **`name`** — The directory name (e.g., `aspire-shop`) + - **`title`** — Extracted from the first `# heading` in the README + - **`description`** — The first paragraph of body text after the title (before any `##` heading) + - **`href`** — Deep link to the sample on GitHub: `https://github.com/dotnet/aspire-samples/tree/main/samples/{name}` + - **`readme`** — The full Markdown content of the README.md, with image paths rewritten to local assets (see below) + - **`tags`** — Auto-detected tags based on technologies, languages, services, and features mentioned in the README and directory name + - **`thumbnail`** — Local asset path to the first image referenced in the README (if any), or `null` + +4. **Downloads images** — For each image referenced in the README (`![alt](src)`): + - Resolves the remote URL (relative paths are resolved against the GitHub raw content URL) + - Downloads the image to `src/frontend/src/assets/samples/{name}/{filename}` + - Rewrites the image reference in the README to use the local asset path: `~/assets/samples/{name}/{filename}` + - This ensures images are bundled with the site and served locally rather than hotlinked from GitHub + +5. **Writes output** — Saves the result as a sorted JSON array to `src/frontend/src/data/samples.json`. + +### 3. Tag detection + +Tags are automatically inferred from the README content and sample name. The script detects: + +#### Languages +| Tag | Matched by | +|---|---| +| `csharp` | C#, .NET references | +| `python` | Python references | +| `javascript` | JavaScript references | +| `node` | Node.js references | +| `go` | Go/Golang references | + +#### Services & Technologies +| Tag | Matched by | +|---|---| +| `redis` | Redis references | +| `postgresql` | PostgreSQL, Postgres, Npgsql references | +| `sql-server` | SQL Server, MSSQL references | +| `mysql` | MySQL references | +| `mongodb` | MongoDB references | +| `rabbitmq` | RabbitMQ references | +| `kafka` | Kafka references | +| `prometheus` | Prometheus references | +| `grafana` | Grafana references | +| `docker` | Docker, container references | + +#### Azure Services +| Tag | Matched by | +|---|---| +| `azure` | Azure references | +| `azure-functions` | Azure Functions references | +| `azure-storage` | Azure Storage references | +| `azure-service-bus` | Azure Service Bus references | + +#### Frameworks & Features +| Tag | Matched by | +|---|---| +| `blazor` | Blazor references | +| `orleans` | Orleans references | +| `grpc` | gRPC references | +| `ef-core` | Entity Framework Core references | +| `metrics` | Metrics, OpenTelemetry references | +| `health-checks` | Health check references | +| `containers` | Container build/deployment references | +| `databases` | Database-related references | +| `migrations` | Database migration references | +| `volumes` | Volume mount references | +| `dashboard` | Dashboard references | + +### 4. Output format + +The output `samples.json` is a JSON array with entries like: + +```json +[ + { + "name": "aspire-shop", + "title": "Aspire Shop", + "description": "The app consists of four .NET services including a Blazor frontend, catalog API, catalog database manager, and basket service.", + "href": "https://github.com/dotnet/aspire-samples/tree/main/samples/aspire-shop", + "readme": "# Aspire Shop\n\n![Screenshot...](~/assets/samples/aspire-shop/aspireshop-frontend-complete.png)...", + "tags": ["csharp", "blazor", "postgresql", "redis", "grpc", "ef-core"], + "thumbnail": "~/assets/samples/aspire-shop/aspireshop-frontend-complete.png" + } +] +``` + +### 5. Manual review + +After running the script: + +- **Review new entries** — Verify titles and descriptions are meaningful +- **Check tags** — The auto-detection may miss niche technologies; manually add tags if needed +- **Verify thumbnails** — Ensure image URLs resolve correctly +- **Remove stale samples** — The script automatically handles this since it rebuilds from source + +### 6. Environment variables + +| Variable | Required | Description | +|---|---|---| +| `GITHUB_TOKEN` | No | GitHub personal access token for higher API rate limits (60 → 5000 requests/hour) | + +### 7. Integration with build + +The script is registered as an npm script in `src/frontend/package.json`: + +```bash +pnpm update:samples +``` + +It is also included in the `update:all` aggregate script so it runs alongside other data updates during builds. diff --git a/src/frontend/config/sidebar/reference.topics.ts b/src/frontend/config/sidebar/reference.topics.ts index 39df43e28..0a678137c 100644 --- a/src/frontend/config/sidebar/reference.topics.ts +++ b/src/frontend/config/sidebar/reference.topics.ts @@ -46,6 +46,29 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig = { }, slug: 'reference/overview', }, + { + label: 'Samples', + translations: { + da: 'Eksempler', + de: 'Beispiele', + en: 'Samples', + es: 'Muestras', + fr: 'Exemples', + hi: 'नमूने', + id: 'Sampel', + it: 'Esempi', + ja: 'サンプル', + ko: '샘플', + pt: 'Exemplos', + 'pt-BR': 'Exemplos', + 'pt-PT': 'Exemplos', + ru: 'Примеры', + tr: 'Örnekler', + uk: 'Зразки', + 'zh-CN': '示例', + }, + slug: 'reference/samples', + }, { label: 'API reference', translations: { diff --git a/src/frontend/package.json b/src/frontend/package.json index c485f59f9..32f982763 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -28,9 +28,10 @@ "lint": "eslint . --max-warnings 0", "format": "prettier -w --cache --plugin prettier-plugin-astro .", "linkcheck": "pnpm git-env && pnpm update:all && cross-env CHECK_LINKS=true astro build", - "update:all": "pnpm update:integrations && pnpm update:github-stats", + "update:all": "pnpm update:integrations && pnpm update:github-stats && pnpm update:samples", "update:integrations": "node ./scripts/update-integrations.js", - "update:github-stats": "node ./scripts/update-github-stats.js" + "update:github-stats": "node ./scripts/update-github-stats.js", + "update:samples": "node ./scripts/update-samples.js" }, "dependencies": { "@astro-community/astro-embed-bluesky": "^0.1.5", @@ -52,6 +53,7 @@ "astro": "^5.16.15", "astro-mermaid": "^1.3.1", "astro-tooltips": "^0.6.2", + "marked": "^17.0.3", "mermaid": "^11.12.2", "remark-directive": "^4.0.0", "sharp": "^0.34.5", @@ -68,6 +70,7 @@ }, "devDependencies": { "@eslint/js": "^9.39.2", + "@playwright/cli": "^0.1.1", "astro-embed": "^0.12.0", "astro-vtbot": "^2.1.10", "cross-env": "^10.1.0", @@ -77,8 +80,7 @@ "node-fetch": "^3.3.2", "prettier": "^3.8.1", "prettier-plugin-astro": "^0.14.1", - "typescript-eslint": "^8.54.0", - "@playwright/cli": "^0.1.1" + "typescript-eslint": "^8.54.0" }, "pnpm": { "overrides": { diff --git a/src/frontend/pnpm-lock.yaml b/src/frontend/pnpm-lock.yaml index d71a2f073..a94d0e87c 100644 --- a/src/frontend/pnpm-lock.yaml +++ b/src/frontend/pnpm-lock.yaml @@ -72,6 +72,9 @@ importers: astro-tooltips: specifier: ^0.6.2 version: 0.6.2 + marked: + specifier: ^17.0.3 + version: 17.0.3 mermaid: specifier: ^11.12.2 version: 11.12.2 @@ -2425,6 +2428,11 @@ packages: engines: {node: '>= 20'} hasBin: true + marked@17.0.3: + resolution: {integrity: sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==} + engines: {node: '>= 20'} + hasBin: true + mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} @@ -6362,6 +6370,8 @@ snapshots: marked@16.4.2: {} + marked@17.0.3: {} + mdast-util-definitions@6.0.0: dependencies: '@types/mdast': 4.0.4 diff --git a/src/frontend/scripts/update-samples.js b/src/frontend/scripts/update-samples.js new file mode 100644 index 000000000..5d2f2d4a7 --- /dev/null +++ b/src/frontend/scripts/update-samples.js @@ -0,0 +1,300 @@ +import fs from 'fs'; +import path from 'path'; +import { pipeline } from 'stream/promises'; +import fetch from 'node-fetch'; + +const REPO = 'dotnet/aspire-samples'; +const BRANCH = 'main'; +const SAMPLES_DIR = 'samples'; +const OUTPUT_PATH = './src/data/samples.json'; +const ASSETS_DIR = './src/assets/samples'; +const ASSETS_IMPORT_PREFIX = '~/assets/samples'; +const GITHUB_API = 'https://api.github.com'; +const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/${BRANCH}`; +const TREE_BASE = `https://github.com/${REPO}/tree/${BRANCH}`; + +const CONCURRENCY = 5; + +const headers = { + 'User-Agent': 'aspire-samples-script', + Accept: 'application/vnd.github.v3+json', +}; +if (process.env.GITHUB_TOKEN) { + headers.Authorization = `token ${process.env.GITHUB_TOKEN}`; +} + +// ---------- Tag detection ---------- + +const TAG_RULES = [ + // Languages + { tag: 'csharp', patterns: [/\bC#\b/i, /\.NET\b/i, /\bcsproj\b/i] }, + { tag: 'python', patterns: [/\bPython\b/i, /\.py\b/] }, + { tag: 'javascript', patterns: [/\bJavaScript\b/i, /\bJS\b/, /\.js\b/] }, + { tag: 'node', patterns: [/\bNode\.?js\b/i, /\bnpm\b/i] }, + { tag: 'go', patterns: [/\bGolang\b/i, /\bGo\s+(?:app|service|project)\b/i, /\b(?:written|built)\s+(?:in|using)\s+Go\b/i, /\bGo\b.*\bGin\b/i] }, + + // Services & Technologies + { tag: 'redis', patterns: [/\bRedis\b/i] }, + { tag: 'postgresql', patterns: [/\bPostgre(?:SQL|s)\b/i, /\bNpgsql\b/i] }, + { tag: 'sql-server', patterns: [/\bSQL\s*Server\b/i, /\bMSSQL\b/i] }, + { tag: 'mysql', patterns: [/\bMySQL\b/i] }, + { tag: 'mongodb', patterns: [/\bMongoDB\b/i] }, + { tag: 'rabbitmq', patterns: [/\bRabbitMQ\b/i] }, + { tag: 'kafka', patterns: [/\bKafka\b/i] }, + { tag: 'prometheus', patterns: [/\bPrometheus\b/i] }, + { tag: 'grafana', patterns: [/\bGrafana\b/i] }, + { tag: 'docker', patterns: [/\bDocker\b/i] }, + + // Azure + { tag: 'azure', patterns: [/\bAzure\b/i] }, + { tag: 'azure-functions', patterns: [/\bAzure\s+Functions?\b/i] }, + { tag: 'azure-storage', patterns: [/\bAzure\s+Storage\b/i] }, + { tag: 'azure-service-bus', patterns: [/\bAzure\s+Service\s+Bus\b/i] }, + + // Frameworks & Features + { tag: 'blazor', patterns: [/\bBlazor\b/i] }, + { tag: 'orleans', patterns: [/\bOrleans\b/i] }, + { tag: 'grpc', patterns: [/\bgRPC\b/i] }, + { tag: 'ef-core', patterns: [/\bEntity\s+Framework\s+Core\b/i, /\bEF\s*Core\b/i] }, + { tag: 'metrics', patterns: [/\bmetrics\b/i, /\bOpenTelemetry\b/i] }, + { tag: 'health-checks', patterns: [/\bhealth\s*check/i] }, + { tag: 'containers', patterns: [/\bcontainer\s+build\b/i, /\bcontaineriz/i] }, + { tag: 'databases', patterns: [/\bdatabase\b/i] }, + { tag: 'migrations', patterns: [/\bmigration/i] }, + { tag: 'volumes', patterns: [/\bvolume\s+mount/i, /\bvolume\b/i] }, + { tag: 'dashboard', patterns: [/\bdashboard\b/i] }, +]; + +function detectTags(name, readme) { + const corpus = `${name} ${readme}`; + const tags = new Set(); + + for (const rule of TAG_RULES) { + for (const pattern of rule.patterns) { + if (pattern.test(corpus)) { + tags.add(rule.tag); + break; + } + } + } + + return [...tags].sort(); +} + +// ---------- README parsing ---------- + +function extractTitle(readme) { + const match = readme.match(/^#\s+(.+)$/m); + return match ? match[1].trim() : null; +} + +function extractDescription(readme) { + // Get text between the first # heading and the first ## heading (or end) + const lines = readme.split('\n'); + let started = false; + const descLines = []; + + for (const line of lines) { + if (!started) { + // Skip until we pass the first # heading + if (/^#\s+/.test(line)) { + started = true; + } + continue; + } + + // Stop at next ## heading + if (/^##\s+/.test(line)) break; + + // Skip image lines and empty lines at the start + const trimmed = line.trim(); + if (trimmed === '') { + if (descLines.length > 0) descLines.push(''); + continue; + } + + // Skip standalone image references + if (/^!\[.*\]\(.*\)$/.test(trimmed)) continue; + + descLines.push(trimmed); + } + + // Clean up: trim trailing empty lines and join preserving structure + while (descLines.length > 0 && descLines[descLines.length - 1] === '') { + descLines.pop(); + } + + // Preserve newlines so markdown structure (lists, paragraphs) is kept + return descLines.join('\n').trim() || null; +} + +// ---------- Image downloading ---------- + +function resolveRemoteImageUrl(name, src) { + if (src.startsWith('http')) return src; + const relative = src.startsWith('./') ? src.slice(2) : src; + return `${RAW_BASE}/${SAMPLES_DIR}/${name}/${relative}`; +} + +function ensureDir(dir) { + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } +} + +async function downloadImage(url, destPath) { + const res = await fetch(url, { + headers: { 'User-Agent': 'aspire-samples-script' }, + }); + if (!res.ok) { + console.warn(` ⚠️ Failed to download image: ${url} (${res.status})`); + return false; + } + ensureDir(path.dirname(destPath)); + const fileStream = fs.createWriteStream(destPath); + try { + await pipeline(res.body, fileStream); + return true; + } catch (err) { + // Remove partial file on failure so we don't leave corrupt assets on disk + try { fs.unlinkSync(destPath); } catch { /* ignore */ } + console.warn(` ⚠️ Failed to write image: ${destPath} (${err.message})`); + return false; + } +} + +function collectImageRefs(readme) { + // Match all markdown image references: ![alt](src) + const regex = /!\[([^\]]*)\]\(([^)]+)\)/g; + const refs = []; + let match; + while ((match = regex.exec(readme)) !== null) { + refs.push({ full: match[0], alt: match[1], src: match[2] }); + } + return refs; +} + +async function downloadAndRewriteImages(name, readme) { + const imageRefs = collectImageRefs(readme); + if (imageRefs.length === 0) return { readme, images: [] }; + + const sampleAssetsDir = path.join(ASSETS_DIR, name); + let rewritten = readme; + const downloadedImages = []; + + for (const ref of imageRefs) { + const remoteUrl = resolveRemoteImageUrl(name, ref.src); + const filename = path.basename(ref.src.split('?')[0]); // strip query params + const localPath = path.join(sampleAssetsDir, filename); + const assetImportPath = `${ASSETS_IMPORT_PREFIX}/${name}/${filename}`; + + const ok = await downloadImage(remoteUrl, localPath); + if (ok) { + // Rewrite the markdown image reference to the local asset path + rewritten = rewritten.replace(ref.full, `![${ref.alt}](${assetImportPath})`); + downloadedImages.push({ filename, localPath, remoteUrl }); + console.log(` 🖼️ Downloaded: ${filename}`); + } + } + + return { readme: rewritten, images: downloadedImages }; +} + +function extractThumbnail(_name, readme) { + // Find the first image reference in the (already-rewritten) README + const match = readme.match(/!\[.*?\]\((.+?)\)/); + if (!match) return null; + return match[1]; +} + +// ---------- GitHub API ---------- + +async function fetchJson(url) { + const res = await fetch(url, { headers }); + if (!res.ok) { + throw new Error(`GitHub API error: ${res.status} ${res.statusText} for ${url}`); + } + return res.json(); +} + +async function fetchText(url) { + const res = await fetch(url, { + headers: { 'User-Agent': 'aspire-samples-script' }, + }); + if (!res.ok) return null; + return res.text(); +} + +async function listSampleDirs() { + const contents = await fetchJson( + `${GITHUB_API}/repos/${REPO}/contents/${SAMPLES_DIR}?ref=${BRANCH}` + ); + return contents + .filter((entry) => entry.type === 'dir') + .map((entry) => entry.name) + .sort(); +} + +async function fetchReadme(sampleName) { + const url = `${RAW_BASE}/${SAMPLES_DIR}/${sampleName}/README.md`; + return fetchText(url); +} + +// ---------- Main ---------- + +async function processSample(name) { + const rawReadme = await fetchReadme(name); + if (!rawReadme) { + console.warn(`⚠️ No README.md found for sample: ${name}`); + return null; + } + + // Download images and rewrite paths in README + const { readme } = await downloadAndRewriteImages(name, rawReadme); + + const title = extractTitle(readme) || name; + const description = extractDescription(readme); + const tags = detectTags(name, readme); + const thumbnail = extractThumbnail(name, readme); + const href = `${TREE_BASE}/${SAMPLES_DIR}/${name}`; + + return { + name, + title, + description, + href, + readme, + tags, + thumbnail, + }; +} + +async function main() { + console.log(`📦 Fetching sample directories from ${REPO}...`); + const dirs = await listSampleDirs(); + console.log(`📂 Found ${dirs.length} sample directories`); + + const results = []; + // Process in batches for concurrency control + for (let i = 0; i < dirs.length; i += CONCURRENCY) { + const batch = dirs.slice(i, i + CONCURRENCY); + const batchResults = await Promise.all(batch.map((name) => processSample(name))); + for (const result of batchResults) { + if (result) { + results.push(result); + console.log(` ✅ ${result.name} — ${result.tags.length} tags`); + } + } + } + + // Sort by name + results.sort((a, b) => a.name.localeCompare(b.name)); + + fs.writeFileSync(OUTPUT_PATH, JSON.stringify(results, null, 2)); + console.log(`\n✅ Saved ${results.length} samples to ${OUTPUT_PATH}`); +} + +main().catch((err) => { + console.error('❌ Error:', err); + process.exit(1); +}); diff --git a/src/frontend/src/assets/samples/Metrics/dashboard-screenshot.png b/src/frontend/src/assets/samples/Metrics/dashboard-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..1cabee334523beb5b944ba1146382b2a5f4f2f85 GIT binary patch literal 448100 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 Vnfl)Yvbpb|tm_FQvTS{}WN-A~dc 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�*6NZ(}sj~4QeE>gDi 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