Customize Azure resources
Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
When working with Azure integrations in .NET Aspire, you often need to customize the provisioned infrastructure beyond the default settings. The same customization patterns apply across Azure hosting integrations such as Storage, Service Bus, Key Vault, user-assigned identities, Azure Container Apps, and Azure App Service. This page documents all customization APIs supported across both C# and TypeScript AppHost projects.
For target-specific generated resource customization, see Deploy to Azure Container Apps and Deploy to Azure App Service.
Shared Azure customization patterns
Section titled “Shared Azure customization patterns”Use existing Azure resources
Section titled “Use existing Azure resources”Use AsExisting, RunAsExisting, and PublishAsExisting when you want Aspire to reference an Azure resource that already exists instead of provisioning a new one.
var builder = DistributedApplication.CreateBuilder(args);
var existingBusName = builder.AddParameter("existingServiceBusName");var existingBusResourceGroup = builder.AddParameter("existingServiceBusResourceGroup");
var serviceBus = builder.AddAzureServiceBus("messaging") .PublishAsExisting(existingBusName, existingBusResourceGroup);
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const existingBusName: ParameterResource
existingBusName = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addParameter(name: string, options?: { value?: string; publishValueAsDefault?: boolean; secret?: boolean;}): ParameterResource (+1 overload)
Adds a parameter resource
addParameter("existingServiceBusName");const const existingBusResourceGroup: ParameterResource
existingBusResourceGroup = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addParameter(name: string, options?: { value?: string; publishValueAsDefault?: boolean; secret?: boolean;}): ParameterResource (+1 overload)
Adds a parameter resource
addParameter("existingServiceBusResourceGroup");
const const serviceBus: AzureServiceBusResource
serviceBus = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureServiceBus(name: string): AzureServiceBusResource
Adds an Azure Service Bus namespace resource
addAzureServiceBus("messaging");await const serviceBus: AzureServiceBusResource
serviceBus.AzureBicepResource.publishAsExisting(name: string | ParameterResource, resourceGroup?: string | ParameterResource): AzureServiceBusResource (+1 overload)
Marks an Azure resource as existing in publish mode
publishAsExisting(const existingBusName: ParameterResource
existingBusName, const existingBusResourceGroup: ParameterResource
existingBusResourceGroup);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Use RunAsExisting when only local run mode should use the existing resource, PublishAsExisting when only deployed Azure environments should use it, and AsExisting when both modes should point at the same Azure resource.
Manage default role assignments
Section titled “Manage default role assignments”Aspire automatically assigns Azure RBAC roles based on how resources reference one another. When you need to opt out of those defaults before applying different permissions, use ClearDefaultRoleAssignments.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureServiceBus("messaging") .ClearDefaultRoleAssignments();
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const serviceBus: AzureServiceBusResource
serviceBus = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureServiceBus(name: string): AzureServiceBusResource
Adds an Azure Service Bus namespace resource
addAzureServiceBus("messaging");await const serviceBus: AzureServiceBusResource
serviceBus.AzureBicepResource.clearDefaultRoleAssignments(): IAzureResource
Clears the default Azure role assignments from a resource
clearDefaultRoleAssignments();
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();For built-in and custom RBAC guidance, see Manage Azure role assignments.
Read generated output values
Section titled “Read generated output values”Azure resources expose output references for values that Azure assigns during provisioning. Use those references when another resource, deployment step, or app setting needs the resolved Azure value.
var builder = DistributedApplication.CreateBuilder(args);
var identity = builder.AddAzureUserAssignedIdentity("identity");
builder.AddProject<Projects.Api>("api") .WithEnvironment("IDENTITY_CLIENT_ID", identity.Resource.ClientId);
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const identity: AzureUserAssignedIdentityResource
identity = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureUserAssignedIdentity(name: string): AzureUserAssignedIdentityResource
Adds an Azure user-assigned identity resource
addAzureUserAssignedIdentity("identity");const const clientId: BicepOutputReference
clientId = await const identity: AzureUserAssignedIdentityResource
identity.AzureUserAssignedIdentityResource.getOutput(name: string): BicepOutputReference
Gets an output reference from an Azure Bicep template resource
getOutput("clientId");
const const api: ProjectResource
api = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: { launchProfileOrOptions?: ProjectResourceOptions;}): ProjectResource (+1 overload)
Adds a .NET project resource
addProject("api", "../Api/Api.csproj");await const api: ProjectResource
api.ProjectResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ProjectResource
Sets an environment variable
withEnvironment("IDENTITY_CLIENT_ID", const clientId: BicepOutputReference
clientId);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Use GetBicepIdentifier() inside ConfigureInfrastructure or infrastructure resolvers when you need a stable identifier for a provisioned Azure construct. Use output references such as ClientId, NameOutputReference, or getOutput("...") when you need Azure-assigned values like a client ID, endpoint, or resource name.
Azure.Provisioning customization
Section titled “Azure.Provisioning customization”The ConfigureInfrastructure API lets you customize the Azure resources that Aspire generates during provisioning. In C#, it provides a strongly-typed surface over the Azure.Provisioning library, letting you modify any property of the generated Azure resource types before Bicep is emitted.
Basic infrastructure customization
Section titled “Basic infrastructure customization”All Azure hosting resources in Aspire inherit from AzureProvisioningResource, which exposes ConfigureInfrastructure. The callback receives an AzureResourceInfrastructure instance that gives you access to all provisioned constructs for that resource.
In C#, use GetProvisionableResources() with the strongly-typed Azure SDK types (for example StorageAccount, ServiceBusNamespace) to navigate and mutate each construct:
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage");
storage.ConfigureInfrastructure(infra =>{ var storageAccount = infra.GetProvisionableResources() .OfType<StorageAccount>() .Single();
storageAccount.Sku = new StorageSku { Name = StorageSkuName.PremiumLRS };
storageAccount.Tags["Environment"] = "Development"; storageAccount.Tags["CostCenter"] = "Engineering";});
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const storage: AzureStorageResource
storage = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureStorage(name: string): AzureStorageResource
Adds an Azure Storage resource
addAzureStorage("storage");
await const storage: AzureStorageResource
storage.AzureProvisioningResource.configureInfrastructure(configure: (obj: AzureResourceInfrastructure) => Promise<void>): AzureProvisioningResource
Configures the Azure provisioning infrastructure callback
configureInfrastructure(async (infra: AzureResourceInfrastructure
infra) => { // Strongly-typed Azure SDK types are not available in TypeScript. // Use getProvisionableResources() to access constructs dynamically. const const resources: any
resources = await infra: AzureResourceInfrastructure
infra.getProvisionableResources();Error ts(2339) ― // Work with resources generically as needed.});
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Configure SKUs and tiers
Section titled “Configure SKUs and tiers”storage.ConfigureInfrastructure(infra =>{ var account = infra.GetProvisionableResources() .OfType<StorageAccount>() .Single();
account.Sku = new StorageSku { Name = StorageSkuName.StandardGRS }; account.Kind = StorageKind.StorageV2;});serviceBus.ConfigureInfrastructure(infra =>{ var ns = infra.GetProvisionableResources() .OfType<ServiceBusNamespace>() .Single();
ns.Sku = new ServiceBusSku { Name = ServiceBusSkuName.Premium, Capacity = 2 };});redis.ConfigureInfrastructure(infra =>{ var cache = infra.GetProvisionableResources() .OfType<RedisCache>() .Single();
cache.Sku = new RedisCacheSku { Name = RedisCacheSkuName.Premium, Family = RedisCacheSkuFamily.P, Capacity = 1 };});Configure networking
Section titled “Configure networking”storage.ConfigureInfrastructure(infra =>{ var account = infra.GetProvisionableResources() .OfType<StorageAccount>() .Single();
account.NetworkRuleSet = new StorageAccountNetworkRuleSet { DefaultAction = StorageNetworkDefaultAction.Deny, Bypass = "AzureServices" };
account.NetworkRuleSet.IpRules.Add(new StorageAccountIPRule { IPAddressOrRange = "203.0.113.0/24", Action = "Allow" });});Configure security and compliance
Section titled “Configure security and compliance”storage.ConfigureInfrastructure(infra =>{ var account = infra.GetProvisionableResources() .OfType<StorageAccount>() .Single();
account.EnableHttpsTrafficOnly = true; account.MinimumTlsVersion = StorageMinimumTlsVersion.Tls1_2;
account.Encryption = new StorageAccountEncryption { KeySource = StorageAccountKeySource.MicrosoftStorage, Services = new StorageAccountEncryptionServices { Blob = new StorageEncryptionService { Enabled = true }, File = new StorageEncryptionService { Enabled = true } } };});Work with multiple resources
Section titled “Work with multiple resources”When an integration creates multiple resources (for example, a Service Bus namespace and its queues), you can customize each one inside a single ConfigureInfrastructure call:
var servicebus = builder.AddAzureServiceBus("messaging");var queue = servicebus.AddQueue("orders");
servicebus.ConfigureInfrastructure(infra =>{ var ns = infra.GetProvisionableResources() .OfType<ServiceBusNamespace>() .Single(); ns.Sku = new ServiceBusSku { Name = ServiceBusSkuName.Standard };
var queueResource = infra.GetProvisionableResources() .OfType<ServiceBusQueue>() .FirstOrDefault(q => q.Name.Contains("orders"));
if (queueResource != null) { queueResource.MaxDeliveryCount = 5; queueResource.DefaultMessageTimeToLive = TimeSpan.FromHours(24); }});Add Azure resources to the infrastructure
Section titled “Add Azure resources to the infrastructure”You can inject additional Azure constructs (for example, a private endpoint) into an integration’s generated infrastructure:
storage.ConfigureInfrastructure(infra =>{ var privateEndpoint = new PrivateEndpoint("storagepe") { Location = "eastus", Subnet = new SubnetReference { Id = "/subscriptions/.../subnets/mysubnet" } };
infra.Add(privateEndpoint);});Customize naming and provisioning with an infrastructure resolver
Section titled “Customize naming and provisioning with an infrastructure resolver”Another way to customize Azure provisioning is to create an InfrastructureResolver. This is a C#-only API that lets you apply organization-wide naming conventions or other centralized provisioning behavior across many Azure resources.
Define a resolver by inheriting from InfrastructureResolver and overriding the relevant virtual members:
using Azure.Provisioning;using Azure.Provisioning.CosmosDB;using Azure.Provisioning.Primitives;
internal sealed class FixedNameInfrastructureResolver : InfrastructureResolver{ public override void ResolveProperties(ProvisionableConstruct construct, ProvisioningBuildOptions options) { if (construct is CosmosDBAccount account) { account.Name = "ContosoCosmosDb"; }
base.ResolveProperties(construct, options); }}Register the resolver in the AppHost:
using Aspire.Hosting.Azure;using Microsoft.Extensions.DependencyInjection;
var builder = DistributedApplication.CreateBuilder(args);
builder.Services.Configure<AzureProvisioningOptions>(options =>{ options.ProvisioningBuildOptions.InfrastructureResolvers.Add(new FixedNameInfrastructureResolver());});
builder.Build().Run();Custom Bicep templates
Section titled “Custom Bicep templates”For scenarios requiring full control, you can supply a custom Bicep file and reference it from your AppHost. This approach works in both C# and TypeScript.
Use custom Bicep files
Section titled “Use custom Bicep files”Create a Bicep file in your AppHost project:
@description('Storage account name')param storageAccountName string
@description('Location')param location string = resourceGroup().location
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: storageAccountName location: location sku: { name: 'Premium_LRS' } kind: 'BlockBlobStorage' properties: { minimumTlsVersion: 'TLS1_2' allowBlobPublicAccess: false networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' } }}
output connectionString string = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};...'Reference it from the AppHost:
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureBicepResource( name: "storage", bicepFilePath: "./custom-storage.bicep") .WithParameter("storageAccountName", "mystorageaccount");
builder.AddProject<Projects.WebApp>("webapp") .WithReference(storage);
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const storage: AzureBicepResource
storage = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addBicepTemplate(name: string, bicepFile: string): AzureBicepResource
Adds an Azure Bicep template resource from a file
addBicepTemplate( "storage", "./custom-storage.bicep");
const const webapp: ProjectResource
webapp = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: { launchProfileOrOptions?: ProjectResourceOptions;}): ProjectResource (+1 overload)
Adds a .NET project resource
addProject("webapp", "../WebApp/WebApp.csproj");await const webapp: ProjectResource
webapp.ProjectResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ProjectResource (+2 overloads)
Adds a reference to another resource
withReference(const storage: AzureBicepResource
storage);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Inspect generated Bicep
Section titled “Inspect generated Bicep”After customizing with ConfigureInfrastructure, inspect the Bicep that Aspire generates:
- Run your AppHost locally.
- Open the
./infradirectory inside your AppHost project. - Review the generated
.bicepfiles to verify your customizations.