From d5a4308cb57ab9cbbd4107d20772aaa33f3cca40 Mon Sep 17 00:00:00 2001 From: "aspire-repo-bot[bot]" <268009190+aspire-repo-bot[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 23:10:42 +0000 Subject: [PATCH] docs: add [AspireValue] exported value catalogs to multi-language integration guide Documents the new [AspireValue] attribute introduced in microsoft/aspire#16287 (milestone 13.3). Covers: - How to annotate static fields/properties with [AspireValue] to export predefined value catalogs into guest SDKs (TypeScript, Python, Java, etc.) - Nested static class hierarchy mapping to nested catalog namespaces - Using catalog values in TypeScript and Python AppHosts - Overriding exported names with the Name property - Value catalog constraints (static, JSON-serializable, no handles) - Updated ASPIREATS001 diagnostics page to list [AspireValue] as protected - Updated supported types table to include exported values row Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../content/docs/diagnostics/aspireats001.mdx | 3 +- .../multi-language-integration-authoring.mdx | 103 +++++++++++++++++- 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/content/docs/diagnostics/aspireats001.mdx b/src/frontend/src/content/docs/diagnostics/aspireats001.mdx index 4857d47f4..f183d52ee 100644 --- a/src/frontend/src/content/docs/diagnostics/aspireats001.mdx +++ b/src/frontend/src/content/docs/diagnostics/aspireats001.mdx @@ -16,7 +16,7 @@ import { Badge } from '@astrojs/starlight/components'; This diagnostic warning is reported when using the experimental Aspire Type Specification (ATS) types and related APIs. These types enable multi-language AppHost support by defining runtime execution configurations for different languages. -The following types are protected by this diagnostic: +The following types and attributes are protected by this diagnostic: - `RuntimeSpec` — specifies the runtime execution configuration for a language. - `CommandSpec` — specifies a command to execute. @@ -25,6 +25,7 @@ The following types are protected by this diagnostic: - `AtsContext` — context for ATS operations. - `ICodeGenerator` — interface for code generation. - `ILanguageSupport` — interface for language support. +- `[AspireValue]` — marks a static field or property as an exported value catalog entry. ## Example diff --git a/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx b/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx index 149af0ee0..9e170ee22 100644 --- a/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx +++ b/src/frontend/src/content/docs/extensibility/multi-language-integration-authoring.mdx @@ -1,6 +1,6 @@ --- title: Multi-language integrations -description: Learn how to annotate your Aspire hosting integration so it works with TypeScript AppHosts. +description: Learn how to annotate your Aspire hosting integration so it works with TypeScript, Python, Java, and other language AppHosts. --- import { @@ -176,6 +176,106 @@ public sealed class AddMyDatabaseOptions DTOs should only contain properties that can be serialized to and from JSON. Avoid using complex .NET types—such as `IConfiguration`, `ILogger`, or delegate types like `Action` and `Func`—as they are not serializable and are not suitable for DTOs. +## Export value catalogs + +Use `[AspireValue]` to export immutable predefined values from your integration into guest SDKs as typed catalog objects. This is useful when your integration ships well-known constants or configuration presets—such as a list of supported model names or region identifiers—that polyglot AppHost authors should be able to reference without reconstructing them manually. + +`[AspireValue]` is an experimental API protected by the `ASPIREATS001` diagnostic. Suppress it in your project file along with the other ATS attributes: + +```xml title="XML — MyIntegration.csproj" + + $(NoWarn);ASPIREATS001 + +``` + +### Define a value catalog + +Apply `[AspireValue]` to `static readonly` fields or `static` properties on your type. The required `catalogName` argument sets the root name of the generated catalog in guest SDKs: + +```csharp title="C# — MyModels.cs" +using Aspire.Hosting; + +[AspireDto] +public sealed class MyModel +{ + public required string Name { get; init; } + public required string Version { get; init; } +} + +public static class MyModels +{ + public static class FastModels + { + /// A fast, lightweight model for simple tasks. + [AspireValue("MyModels")] + public static readonly MyModel Lite = new() { Name = "my-model-lite", Version = "1" }; + + /// A fast model with extended context support. + [AspireValue("MyModels")] + public static readonly MyModel LiteLong = new() { Name = "my-model-lite-long", Version = "1" }; + } + + public static class PowerModels + { + /// A high-capability model for complex tasks. + [AspireValue("MyModels")] + public static readonly MyModel Pro = new() { Name = "my-model-pro", Version = "2" }; + } +} +``` + +The scanner snaps the values at scan time by serializing each field or property to JSON. It also reads XML doc comments to include descriptions in the generated catalog. + +### Use catalog values in guest SDKs + +After generating the SDK (for example, with `aspire run`), the catalog is available as a nested object in each supported language. The nesting mirrors the static class hierarchy of the C# source: + +```typescript title="TypeScript — apphost.ts" +import { createBuilder } from './.modules/aspire.js'; +import { MyModels } from './.modules/my-integration.js'; + +const builder = await createBuilder(); + +// Use predefined catalog values directly +await builder + .addMyService('svc', { model: MyModels.FastModels.Lite }) + .build() + .run(); +``` + +```python title="Python — apphost.py" +from modules.my_integration import MyModels + +builder = await create_builder() + +await ( + builder + .add_my_service("svc", model=MyModels.FastModels.Lite) + .build() + .run() +) +``` + +### Override the exported name + +By default, the exported name matches the field or property name. Use the `Name` property to override it: + +```csharp title="C# — Override exported name" +[AspireValue("MyModels", Name = "lite")] +public static readonly MyModel Lite = new() { Name = "my-model-lite", Version = "1" }; +``` + +### Value catalog constraints + +- Exported fields and properties must be **static**. +- The value must be serializable to JSON. Avoid types that hold runtime handles, delegates, or other non-serializable state. +- Handles (`IResourceBuilder`, resource instances) are **not** valid as exported values. +- Values are snapped **once** at scan time. They are emitted as compile-time constants in generated SDKs and are not refreshed at runtime. + +:::note +`[AspireValue]` exports predefined constants into the generated SDK. It is not a mechanism for sharing live runtime state. For runtime interactions, use `[AspireExport]` methods instead. +::: + ## Handle incompatible overloads Some C# overloads use types that can't be represented in TypeScript (e.g., `Action` delegates with non-serializable contexts, interpolated string handlers, or C#-specific types). Mark these with `[AspireExportIgnore]`: @@ -325,6 +425,7 @@ The following types are ATS-compatible and can be used in exported method signat | **Enums** | Any enum type | | **Handles** | `IResourceBuilder`, `IDistributedApplicationBuilder`, resource types marked with `[AspireExport]` | | **DTOs** | Classes/structs marked with `[AspireDto]` | +| **Exported values** | Static fields/properties marked with `[AspireValue]` (emitted as catalog constants in guest SDKs) | | **Collections** | `List`, `Dictionary`, arrays — where `T` is ATS-compatible | | **Delegates** | `Action`, `Func`, and other delegate types (use `RunSyncOnBackgroundThread = true` for synchronous delegates invoked inline) | | **Services** | `ILogger`, `IServiceProvider`, `IConfiguration` (already exported by the core framework) |