From 98d83905db6aa0fc781f524b11b88e9b9135e416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= <1165805+sebastienros@users.noreply.github.com> Date: Thu, 24 Sep 2026 15:22:19 -0700 Subject: [PATCH 1/3] docs: document Azure provisioning service coverage and limits Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../cloud/azure/customize-resources.mdx | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) 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 f76c89172..2a08d0631 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/customize-resources.mdx @@ -160,14 +160,27 @@ For TypeScript and other polyglot AppHosts, add the `Aspire.Hosting.Azure.Provis aspire add Aspire.Hosting.Azure.Provisioning.Storage ``` -The examples below use these packages, depending on the resource being customized: - -| Hosting integration | Opt-in provisioning package | -| ------------------- | --------------------------------------------------- | -| Azure Storage | `Aspire.Hosting.Azure.Provisioning.Storage` | -| Azure Service Bus | `Aspire.Hosting.Azure.Provisioning.ServiceBus` | -| Azure Key Vault | `Aspire.Hosting.Azure.Provisioning.KeyVault` | -| Azure Managed Redis | `Aspire.Hosting.Azure.Provisioning.RedisEnterprise` | +Select a provisioning package for the SDK models you want to customize: + +| Hosting integration | Opt-in provisioning package | Selected SDK models | +| ----------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| Azure App Configuration | `Aspire.Hosting.Azure.Provisioning.AppConfiguration` | `AppConfigurationStore` | +| Azure Container Apps | `Aspire.Hosting.Azure.Provisioning.AppContainers` | `ContainerAppManagedEnvironment`, `ContainerApp`, `ContainerAppJob` | +| Azure App Service | `Aspire.Hosting.Azure.Provisioning.AppService` | `AppServicePlan`, `WebSite` | +| Azure Front Door | `Aspire.Hosting.Azure.Provisioning.Cdn` | `CdnProfile` | +| Azure Kubernetes Service | `Aspire.Hosting.Azure.Provisioning.ContainerService` | `ContainerServiceManagedCluster` | +| Azure Data Explorer | `Aspire.Hosting.Azure.Provisioning.Kusto` | `KustoCluster` | +| Azure networking | `Aspire.Hosting.Azure.Provisioning.Network` | `VirtualNetwork`, `NetworkSecurityGroup`, `NatGateway`, `PublicIPAddress`, `PrivateEndpoint`, `NetworkSecurityPerimeter` | +| Azure private DNS | `Aspire.Hosting.Azure.Provisioning.PrivateDns` | `PrivateDnsZone` | +| Azure Database for PostgreSQL | `Aspire.Hosting.Azure.Provisioning.PostgreSql` | `PostgreSqlFlexibleServer` | +| Azure Cache for Redis | `Aspire.Hosting.Azure.Provisioning.Redis` | `RedisResource` | +| Azure Managed Redis | `Aspire.Hosting.Azure.Provisioning.RedisEnterprise` | `RedisEnterpriseCluster` | +| Azure SignalR Service | `Aspire.Hosting.Azure.Provisioning.SignalR` | `SignalRService` | +| Azure Storage | `Aspire.Hosting.Azure.Provisioning.Storage` | `StorageAccount` | +| Azure Service Bus | `Aspire.Hosting.Azure.Provisioning.ServiceBus` | `ServiceBusNamespace` | +| Azure Key Vault | `Aspire.Hosting.Azure.Provisioning.KeyVault` | `KeyVaultService` | + +Package names follow the Azure Provisioning SDK, which can differ from the hosting integration name: Front Door uses `Cdn`, Kubernetes uses `ContainerService`, and PostgreSQL uses the SDK spelling `PostgreSql`. Network and PrivateDns are separate opt-ins, as are Redis and RedisEnterprise. To customize supporting resources such as a container registry or Log Analytics workspace, also add the corresponding provisioning package; a transitive hosting dependency doesn't enable its SDK proxies. Each provisioning package references its hosting integration and the shared `Aspire.Hosting.Azure.Provisioning` runtime. Install only the SDK proxies your AppHost uses. Existing C# customization through `Azure.Provisioning.*` doesn't require these proxy packages. @@ -179,6 +192,31 @@ Proxy properties use asynchronous `get()` and `set(...)` operations. Dictionary Lookups are scoped to the current infrastructure callback. A no-argument root lookup matches the hosting resource's Bicep identifier, not its physical Azure name. Use an identifier-based lookup or typed resource list for child resources; a companion resource can have a separate callback. +### Service-specific lookups + +The selected models in the table aren't all no-argument lookup roots: + +- **App Configuration**: Use `getAppConfigurationStore()` in the store's infrastructure callback. +- **Container Apps**: Use `getContainerAppManagedEnvironment()` in the environment callback. Apps and jobs require identifier-based lookup in their publish callbacks. Their SDK Bicep identifiers use the normalized workload name, not the synthetic hosting resource identifier. +- **App Service**: Use `getAppServicePlanByIdentifier(...)` with the environment's Bicep identifier followed by `_asplan`. Sites use the Bicep identifier `webapp` and must be accessed in the website publish callback, not the environment callback. Neither plans nor sites have a no-argument root lookup. +- **Child resources**: Use identifier-based lookup for resources such as Kusto databases. Don't assume the parent resource's no-argument lookup selects a child. + +### IP address collections and projection limits + +The AppContainers SDK's `OutboundIPAddressList` and the AppService SDK's `IPAddresses`, `ExternalInboundIPAddresses`, `InternalInboundIPAddresses`, `LinuxOutboundIPAddresses`, and `WindowsOutboundIPAddresses` use IP address collection proxies. + +Writable collections accept IPv4 or IPv6 strings and compatible Bicep value handles for add, insert, and set operations. Invalid address strings fail validation. Element getters return Bicep value handles that preserve literal values, expressions, resource references, and secure-value metadata. An exported collection isn't necessarily writable: Azure SDK read-only output restrictions still apply. + +The projection deliberately excludes members without a type-safe representation: + +| Provisioning package suffix | Excluded member | Unsupported SDK shape | +| --------------------------- | --------------------------- | ----------------------------- | +| `ContainerService` | `CustomCATrustCertificates` | `BicepList` | +| `Network` | `AdditionalProperties` | `BicepDictionary` | +| `Redis` | `AdditionalProperties` | `BicepDictionary` | + +These exclusions apply to the polyglot proxy surface, not direct Azure Provisioning SDK access in C#. Adding a proxy package doesn't change authentication, resource lifecycles, or deployment defaults. + See the [provisioning SDK inventory and compatibility boundaries](https://github.com/microsoft/aspire/blob/a11eca9611073f7cf66fa87faac63c2119e87713/src/Aspire.Hosting.Azure.Provisioning/README.md#hosting-to-provisioning-inventory). From c86a640a025c5e570dcb0b4b1b5b64276c3837f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= <1165805+sebastienros@users.noreply.github.com> Date: Mon, 28 Sep 2026 09:04:39 -0700 Subject: [PATCH 2/3] docs: clarify provisioning models and demonstrate store lookup Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../cloud/azure/customize-resources.mdx | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) 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 2a08d0631..4ccc9ff15 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 @@ -162,6 +162,8 @@ aspire add Aspire.Hosting.Azure.Provisioning.Storage Select a provisioning package for the SDK models you want to customize: +The **Selected SDK models** column lists representative models, not every model exposed by each package. Packages can also expose child resources and supporting models. + | Hosting integration | Opt-in provisioning package | Selected SDK models | | ----------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | Azure App Configuration | `Aspire.Hosting.Azure.Provisioning.AppConfiguration` | `AppConfigurationStore` | @@ -201,6 +203,61 @@ The selected models in the table aren't all no-argument lookup roots: - **App Service**: Use `getAppServicePlanByIdentifier(...)` with the environment's Bicep identifier followed by `_asplan`. Sites use the Bicep identifier `webapp` and must be accessed in the website publish callback, not the environment callback. Neither plans nor sites have a no-argument root lookup. - **Child resources**: Use identifier-based lookup for resources such as Kusto databases. Don't assume the parent resource's no-argument lookup selects a child. +For example, add a tag to the App Configuration store that Aspire creates. The infrastructure callback runs before Aspire emits the resource's Bicep; the lookup selects the store within that callback, rather than querying an existing Azure deployment. + + + + +Add the App Configuration provisioning package from your AppHost directory: + +```bash title="Add typed App Configuration customization" +aspire add Aspire.Hosting.Azure.Provisioning.AppConfiguration +``` + +```typescript title="apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); +const configuration = await builder.addAzureAppConfiguration('configuration'); + +await configuration.configureInfrastructure(async (infrastructure) => { + const store = await infrastructure.getAppConfigurationStore(); + const tags = await store.tags.get(); + await tags.set('environment', 'production'); +}); + +await builder.build().run(); +``` + + + + +Add the hosting integration; C# accesses the Azure Provisioning SDK directly: + +```bash title="Add App Configuration hosting integration" +aspire add Aspire.Hosting.Azure.AppConfiguration +``` + +```csharp title="AppHost.cs" +using Azure.Provisioning.AppConfiguration; + +var builder = DistributedApplication.CreateBuilder(args); +var configuration = builder.AddAzureAppConfiguration("configuration"); + +configuration.ConfigureInfrastructure(infrastructure => +{ + var store = infrastructure.GetProvisionableResources() + .OfType() + .Single(); + store.Tags["environment"] = "production"; +}); + +builder.Build().Run(); +``` + + + + ### IP address collections and projection limits The AppContainers SDK's `OutboundIPAddressList` and the AppService SDK's `IPAddresses`, `ExternalInboundIPAddresses`, `InternalInboundIPAddresses`, `LinuxOutboundIPAddresses`, and `WindowsOutboundIPAddresses` use IP address collection proxies. From 7c07b854c311b8aec29a6b0a56b0de53a25b94e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= <1165805+sebastienros@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:38:38 -0700 Subject: [PATCH 3/3] docs: use existing Storage walkthrough for provisioning lookups Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../cloud/azure/customize-resources.mdx | 55 +------------------ 1 file changed, 1 insertion(+), 54 deletions(-) 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 4ccc9ff15..8def9fd0e 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 @@ -203,60 +203,7 @@ The selected models in the table aren't all no-argument lookup roots: - **App Service**: Use `getAppServicePlanByIdentifier(...)` with the environment's Bicep identifier followed by `_asplan`. Sites use the Bicep identifier `webapp` and must be accessed in the website publish callback, not the environment callback. Neither plans nor sites have a no-argument root lookup. - **Child resources**: Use identifier-based lookup for resources such as Kusto databases. Don't assume the parent resource's no-argument lookup selects a child. -For example, add a tag to the App Configuration store that Aspire creates. The infrastructure callback runs before Aspire emits the resource's Bicep; the lookup selects the store within that callback, rather than querying an existing Azure deployment. - - - - -Add the App Configuration provisioning package from your AppHost directory: - -```bash title="Add typed App Configuration customization" -aspire add Aspire.Hosting.Azure.Provisioning.AppConfiguration -``` - -```typescript title="apphost.mts" twoslash -import { createBuilder } from './.aspire/modules/aspire.mjs'; - -const builder = await createBuilder(); -const configuration = await builder.addAzureAppConfiguration('configuration'); - -await configuration.configureInfrastructure(async (infrastructure) => { - const store = await infrastructure.getAppConfigurationStore(); - const tags = await store.tags.get(); - await tags.set('environment', 'production'); -}); - -await builder.build().run(); -``` - - - - -Add the hosting integration; C# accesses the Azure Provisioning SDK directly: - -```bash title="Add App Configuration hosting integration" -aspire add Aspire.Hosting.Azure.AppConfiguration -``` - -```csharp title="AppHost.cs" -using Azure.Provisioning.AppConfiguration; - -var builder = DistributedApplication.CreateBuilder(args); -var configuration = builder.AddAzureAppConfiguration("configuration"); - -configuration.ConfigureInfrastructure(infrastructure => -{ - var store = infrastructure.GetProvisionableResources() - .OfType() - .Single(); - store.Tags["environment"] = "production"; -}); - -builder.Build().Run(); -``` - - - +For a complete TypeScript and C# example using Azure Storage, see [Basic infrastructure customization](#basic-infrastructure-customization). The example looks up the storage account inside its infrastructure callback and adds tags. The callback runs before Aspire emits the resource's Bicep; the lookup selects a generated resource rather than querying an existing Azure deployment. ### IP address collections and projection limits