diff --git a/src/frontend/scripts/generate-twoslash-types.ts b/src/frontend/scripts/generate-twoslash-types.ts index 3fa817e29..f8a22d146 100644 --- a/src/frontend/scripts/generate-twoslash-types.ts +++ b/src/frontend/scripts/generate-twoslash-types.ts @@ -211,6 +211,15 @@ const PARAM_TYPE_OVERRIDES: Record> = { withEnvironment: { value: 'string | IResourceWithConnectionString | IValueProvider', }, + // The polyglot `withParameter` dispatcher accepts the full Bicep parameter + // value union (string / string[] / parameter / connection-string resource / + // bicep output / reference expression / endpoint), but the dumped JSON only + // encodes the trailing `EndpointReference` overload. Mirror the real + // `[AspireUnion]` surface so docs can pass strings and parameter references. + withParameter: { + value: + 'string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference', + }, // Accept parameter-resource references in addition to literal strings, matching // the real SDK's overload for "publish as an existing Azure resource". publishAsExisting: { 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 1a3aefc9d..ea2207209 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 @@ -388,39 +388,40 @@ servicebus.ConfigureInfrastructure(infra => ### Add Azure resources to the infrastructure -You can inject additional Azure constructs (for example, a private endpoint) into an integration's generated infrastructure: +For common scenarios, prefer Aspire's higher-level resource builders. For example, to add a private endpoint to a storage account, use `AddPrivateEndpoint` from the `Aspire.Hosting.Azure.Network` package, which automatically wires up the Private DNS Zone, VNet link, and DNS Zone Group: ```csharp title="AppHost.cs" -storage.ConfigureInfrastructure(infra => -{ - var privateEndpoint = new PrivateEndpoint("storagepe") - { - Location = "eastus", - Subnet = new SubnetReference - { - Id = "/subscriptions/.../subnets/mysubnet" - } - }; +var builder = DistributedApplication.CreateBuilder(args); - infra.Add(privateEndpoint); -}); +var vnet = builder.AddAzureVirtualNetwork("vnet"); +var peSubnet = vnet.AddSubnet("pe-subnet", "10.0.1.0/24"); + +var storage = builder.AddAzureStorage("storage"); +var blobs = storage.AddBlobs("blobs"); + +peSubnet.AddPrivateEndpoint(blobs); + +builder.Build().Run(); ``` +When no Aspire-native resource builder exists for what you need, fall back to `ConfigureInfrastructure` to add an `Azure.Provisioning` construct directly. See the [Azure.Provisioning API reference](https://learn.microsoft.com/dotnet/api/overview/azure/provisioning) for the available construct types and their properties. + ### Customize naming and provisioning with an infrastructure resolver Another way to customize Azure provisioning is to create an [`InfrastructureResolver`](https://learn.microsoft.com/dotnet/api/azure.provisioning.primitives.infrastructureresolver). This is a C#-only API that lets you apply organization-wide naming conventions or other centralized provisioning behavior across many Azure resources. @@ -512,7 +513,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { output connectionString string = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};...' ``` -Reference it from the AppHost: +Reference the file from the AppHost using `AddBicepTemplate` (C#) or `addBicepTemplate` (TypeScript). Use `WithParameter` / `withParameter` to supply input parameters, and `GetOutput` / `getOutput` to consume a named output by passing the resulting reference to another resource: @@ -520,13 +521,11 @@ Reference it from the AppHost: ```csharp title="AppHost.cs" var builder = DistributedApplication.CreateBuilder(args); -var storage = builder.AddAzureBicepResource( - name: "storage", - bicepFilePath: "./custom-storage.bicep") +var storage = builder.AddBicepTemplate("storage", "./custom-storage.bicep") .WithParameter("storageAccountName", "mystorageaccount"); builder.AddProject("webapp") - .WithReference(storage); + .WithEnvironment("STORAGE_CONNECTION_STRING", storage.GetOutput("connectionString")); builder.Build().Run(); ``` @@ -539,12 +538,70 @@ import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); -const storage = await builder.addBicepTemplate( - "storage", - "./custom-storage.bicep"); +const storage = await builder.addBicepTemplate("storage", "./custom-storage.bicep"); +await storage.withParameter("storageAccountName", { value: "mystorageaccount" }); + +const connectionString = await storage.getOutput("connectionString"); const webapp = await builder.addProject("webapp", "../WebApp/WebApp.csproj"); -await webapp.withReference(storage); +await webapp.withEnvironment("STORAGE_CONNECTION_STRING", connectionString); + +await builder.build().run(); +``` + + + + + + +### Pass parameters and read outputs + +`WithParameter` accepts several kinds of values beyond plain strings, so a custom Bicep template can take values that are computed at deployment time. Common sources include: + +- A `ParameterResource` declared with `AddParameter` (including secret parameters). +- A `BicepOutputReference` from another Bicep resource — useful when one template's output feeds another template's input. +- A `ReferenceExpression` that composes values from multiple resources. +- A connection-string-bearing resource via `IResourceBuilder`. +- An `EndpointReference` from a resource's endpoint. + +The example below adds a secret administrator password as a parameter and then reads the deployed SQL server name back out of the template so that another resource can consume it: + + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var adminPassword = builder.AddParameter("adminPassword", secret: true); + +var sql = builder.AddBicepTemplate("sql", "./custom-sql.bicep") + .WithParameter("administratorLoginPassword", adminPassword); + +builder.AddProject("api") + .WithEnvironment("SQL_SERVER_NAME", sql.GetOutput("sqlServerName")); + +builder.Build().Run(); +``` + + + + +```typescript title="apphost.mts" twoslash +import { createBuilder } from './.aspire/modules/aspire.mjs'; + +const builder = await createBuilder(); + +const adminPassword = await builder.addParameter("adminPassword", { secret: true }); + +const sql = await builder.addBicepTemplate("sql", "./custom-sql.bicep"); +await sql.withParameter("administratorLoginPassword", { value: adminPassword }); + +const sqlServerName = await sql.getOutput("sqlServerName"); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withEnvironment("SQL_SERVER_NAME", sqlServerName); await builder.build().run(); ``` @@ -552,14 +609,22 @@ await builder.build().run(); + +For more end-to-end examples — including chaining outputs between Bicep resources and using the `existing` Bicep keyword to reference resources that Aspire didn't provision — see the [Aspire `playground/bicep` sample](https://github.com/dotnet/aspire/tree/main/playground/bicep). + + ### Inspect generated Bicep -After customizing with `ConfigureInfrastructure`, inspect the Bicep that Aspire generates: +To see the Bicep that Aspire emits after applying your `ConfigureInfrastructure` callbacks, run a publish (or deploy) and read the files from the output folder: -1. Run your AppHost locally. -2. Open the `./infra` directory inside your AppHost project. +1. From the AppHost directory, run `aspire publish` (or `aspire deploy`). +2. Open the `aspire-output` folder next to your AppHost project. To write somewhere else, pass `--output-path` to the publish or deploy command. 3. Review the generated `.bicep` files to verify your customizations. + + @@ -570,5 +635,6 @@ Use the Azure Portal's **Export template** feature to view Bicep for manually co - [Manage Azure role assignments](/integrations/cloud/azure/role-assignments/) - [Local Azure provisioning](/integrations/cloud/azure/local-provisioning/) - [Azure.Provisioning API reference](https://learn.microsoft.com/dotnet/api/overview/azure/provisioning) +- [Aspire `playground/bicep` sample](https://github.com/dotnet/aspire/tree/main/playground/bicep) - [Deploy to Azure Container Apps](/deployment/azure/container-apps/) - [Deploy to Azure App Service](/deployment/azure/app-service/) diff --git a/src/frontend/src/data/twoslash/aspire.d.ts b/src/frontend/src/data/twoslash/aspire.d.ts index 3361ad54d..081f30dee 100644 --- a/src/frontend/src/data/twoslash/aspire.d.ts +++ b/src/frontend/src/data/twoslash/aspire.d.ts @@ -3682,12 +3682,12 @@ export interface AzureBicepResource extends IAzureResource, IResource, IResource * Adds a Bicep parameter */ - withParameter(name: string, options?: { value?: EndpointReference }): this; + withParameter(name: string, options?: { value?: string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference }): this; /** * Adds a Bicep parameter */ - withParameter(name: string, value?: EndpointReference): this; + withParameter(name: string, value?: string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference): this; } /** @@ -13757,12 +13757,12 @@ export interface AzureProvisioningResource { * Adds a Bicep parameter */ - withParameter(name: string, options?: { value?: EndpointReference }): this; + withParameter(name: string, options?: { value?: string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference }): this; /** * Adds a Bicep parameter */ - withParameter(name: string, value?: EndpointReference): this; + withParameter(name: string, value?: string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference): this; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Azure App Configuration resource. This replaces the default role assignments for the resource. */ @@ -14126,12 +14126,12 @@ export interface AzureUserAssignedIdentityResource { * Adds a Bicep parameter */ - withParameter(name: string, options?: { value?: EndpointReference }): this; + withParameter(name: string, options?: { value?: string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference }): this; /** * Adds a Bicep parameter */ - withParameter(name: string, value?: EndpointReference): this; + withParameter(name: string, value?: string | string[] | ParameterResource | IResourceWithConnectionString | BicepOutputReference | ReferenceExpression | EndpointReference): this; /** * Assigns the specified roles to the given resource, granting it the necessary permissions on the target Azure App Configuration resource. This replaces the default role assignments for the resource. */