.NET Aspire Azure integrations overview
Azure is the most popular cloud platform for building and deploying .NET applications. The Azure SDK for .NET allows for easy management and use of Azure services. .NET Aspire provides a set of integrations with Azure services, where you're free to add new resources or connect to existing ones. This article details some common aspects of all Azure integrations in .NET Aspire and aims to help you understand how to use them.
Add connection to existing Azure resources
.NET Aspire provides the ability to connect to existing resources, including Azure resources. Expressing connection strings is useful when you have existing Azure resources that you want to use in your .NET Aspire app. The AddConnectionString API is used with the app host's execution context to conditionally add a connection string to the app model.
Note
Connection strings are used to represent a wide range of connection information, including database connections, message brokers, endpoint URIs, and other services. In .NET Aspire nomenclature, the term "connection string" is used to represent any kind of connection information.
Consider the following example, where in publish mode you add an Azure Storage resource while in run mode you add a connection string to an existing Azure Storage:
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.ExecutionContext.IsPublishMode
? builder.AddAzureStorage("storage")
: builder.AddConnectionString("storage");
builder.AddProject<Projects.Api>("api")
.WithReference(storage);
// After adding all resources, run the app...
The preceding code:
- Creates a new
builder
instance. - Adds a Azure Storage resource named
storage
in "publish" mode. - Adds a connection string to an existing Azure Storage named
storage
in "run" mode. - Adds a project named
api
to the builder. - The
api
project references thestorage
resource regardless of the mode.
The consuming API project uses the connection string information with no knowledge of how the app host configured it. In "publish" mode, the code adds a new Azure Storage resource—which would be reflected in the deployment manifest accordingly. When in "run" mode, the connection string corresponds to a configuration value visible to the app host. It's assumed that any and all role assignments for the target resource have been configured. This means, you'd likely configure an environment variable or a user secret to store the connection string. The configuration is resolved from the ConnectionStrings__storage
(or ConnectionStrings:storage
) configuration key. These configuration values can be viewed when the app runs. For more information, see Resource details.
Add Azure resources
All .NET Aspire Azure hosting integrations expose Azure resources and by convention are added using AddAzure*
APIs. When you add these resources to your .NET Aspire app host, they represent an Azure service. The AddAzure*
API returns an IResourceBuilder<T> where T
is the type of Azure resource. These IResourceBuilder<T>
(builder) interfaces provide a fluent API that allows you to configure the underlying Azure resource within the app model.
Typical developer experience
When your .NET Aspire app host contains Azure resources, and you run it locally (typical developer F5 or dotnet run
experience), the Azure resources are provisioned in your Azure subscription. This allows you as the developer to debug against them locally in the context of your app host.
.NET Aspire aims to minimize costs by defaulting to Basic or Standard Stock Keeping Unit (SKU) for its Azure integrations. While these sensible defaults are provided, you can customize the Azure resources to suit your needs. Additionally, some integrations support emulators or containers, which are useful for local development, testing, and debugging. By default, when you run your app locally, the Azure resources use the actual Azure service. However, you can configure them to use local emulators or containers, avoiding costs associated with the actual Azure service during local development.
Local emulators
Some Azure services can be run locally in emulators. Currently, .NET Aspire supports the following Azure emulators:
Hosting integration | Description |
---|---|
Azure Cosmos DB | Call AzureCosmosExtensions.RunAsEmulator on the IResourceBuilder<AzureCosmosDBResource> to configure the Cosmos DB resource to be emulated with the NoSQL API. |
Azure Event Hubs | Call AzureEventHubsExtensions.RunAsEmulator on the IResourceBuilder<AzureEventHubsResource> to configure the Event Hubs resource to be emulated. |
Azure Storage | Call AzureStorageExtensions.RunAsEmulator on the IResourceBuilder<AzureStorageResource> to configure the Storage resource to be emulated with Azurite. |
To have your Azure resources use the local emulators, chain a call the RunAsEmulator
method on the Azure resource builder. This method configures the Azure resource to use the local emulator instead of the actual Azure service.
Important
Calling any of the available RunAsEmulator
APIs on an Azure resource builder doesn't impact the publishing manifest. When you publish your app, generated Bicep file reflects the actual Azure service, not the local emulator.
Local containers
Some Azure services can be run locally in containers. To run an Azure service locally in a container, chain a call to the RunAsContainer
method on the Azure resource builder. This method configures the Azure resource to run locally in a container instead of the actual Azure service.
Currently, .NET Aspire supports the following Azure services as containers:
Hosting integration | Details |
---|---|
Azure Cache for Redis | Call AzureRedisExtensions.RunAsContainer on the IResourceBuilder<AzureRedisCacheResource> to configure it to run locally in a container, based on the docker.io/library/redis image. |
Azure PostgreSQL Flexible Server | Call AzurePostgresExtensions.RunAsContainer on the IResourceBuilder<AzurePostgresFlexibleServerResource> to configure it to run locally in a container, based on the docker.io/library/postgres image. |
Azure SQL Server | Call AzureSqlExtensions.RunAsContainer on the IResourceBuilder<AzureSqlServerResource> to configure it to run locally in a container, based on the mcr.microsoft.com/mssql/server image. |
Note
Like emulators, calling RunAsContainer
on an Azure resource builder doesn't impact the publishing manifest. When you publish your app, the generated Bicep file reflects the actual Azure service, not the local container.
Understand Azure integration APIs
.NET Aspire's strength lies in its ability to provide an amazing developer inner-loop. The Azure integrations are no different. They provide a set of common APIs and patterns that are shared across all Azure resources. These APIs and patterns are designed to make it easy to work with Azure resources in a consistent manner.
In the preceding containers section, you saw how to run Azure services locally in containers. If you're familiar with .NET Aspire, you might wonder how calling AddAzureRedis("redis").RunAsContainer()
to get a local docker.io/library/redis
container differs from AddRedis("redis")
—as they both result in the same local container.
The answer is that there's no difference when running locally. However, when they're published you get different resources:
API | Run mode | Publish mode |
---|---|---|
AddAzureRedis("redis").RunAsContainer() | Local Redis container | Azure Cache for Redis |
AddRedis("redis") | Local Redis container | Azure Container App with Redis image |
The same is true for SQL and PostgreSQL services:
API | Run mode | Publish mode |
---|---|---|
AddAzurePostgresFlexibleServer("postgres").RunAsContainer() | Local PostgreSQL container | Azure PostgreSQL Flexible Server |
AddPostgres("postgres") | Local PostgreSQL container | Azure Container App with PostgreSQL image |
AddAzureSqlServer("sql").RunAsContainer() | Local SQL Server container | Azure SQL Server |
AddSqlServer("sql") | Local SQL Server container | Azure Container App with SQL Server image |
For more information on the difference between run and publish modes, see .NET Aspire app host: Execution context.
Infrastructure as code
The Azure SDK for .NET provides the 📦 Azure.Provisioning NuGet package and a suite of service-specific Azure provisioning packages. These Azure provisioning libraries make it easy to declaratively specify Azure infrastructure natively in .NET. Their APIs enable you to write object-oriented infrastructure in C#, resulting in Bicep. Bicep is a domain-specific language (DSL) for deploying Azure resources declaratively.
While it's possible to provision Azure resources manually, .NET Aspire simplifies the process by providing a set of APIs to express Azure resources. These APIs are available as extension methods in .NET Aspire Azure hosting libraries, extending the IDistributedApplicationBuilder interface. When you add Azure resources to your app host, they add the appropriate provisioning functionality implicitly. In other words, you don't need to call any provisioning APIs directly.
Since .NET Aspire models Azure resources within Azure hosting integrations, the Azure SDK is used to provision these resources. Bicep files are generated that define the Azure resources you need. The generated Bicep files are output alongside the manifest file when you publish your app.
There are several ways to influence the generated Bicep files:
- Azure.Provisioning customization:
- Configure infrastructure: Customize Azure resource infrastructure.
- Add Azure infrastructure: Manually add Azure infrastructure to your app host.
- Use custom Bicep templates:
- Reference Bicep files: Add a reference to a Bicep file on disk.
- Reference Bicep inline: Add an inline Bicep template.
Local provisioning and Azure.Provisioning
To avoid conflating terms and to help disambiguate "provisioning," it's important to understand the distinction between local provisioning and Azure provisioning:
Local provisioning:
By default, when you call any of the Azure hosting integration APIs to add Azure resources, the AddAzureProvisioning(IDistributedApplicationBuilder) API is called implicitly. This API registers services in the dependency injection (DI) container that are used to provision Azure resources when the app host starts. This concept is known as local provisioning. For more information, see Local Azure provisioning.
Azure.Provisioning
:Azure.Provisioning
refers to the NuGet package, and is a set of libraries that lets you use C# to generate Bicep. The Azure hosting integrations in .NET Aspire use these libraries under the covers to generate Bicep files that define the Azure resources you need. For more information, seeAzure.Provisioning
customization.
Azure.Provisioning
customization
All .NET Aspire Azure hosting integrations expose various Azure resources, and they're all subclasses of the AzureProvisioningResource type—which itself inherits the AzureBicepResource. This enables extensions that are generically type-constrained to this type, allowing for a fluent API to customize the infrastructure to your liking. While .NET Aspire provides defaults, you're free to influence the generated Bicep using these APIs.
Configure infrastructure
Regardless of the Azure resource you're working with, to configure its underlying infrastructure, you chain a call to the ConfigureInfrastructure extension method. This method allows you to customize the infrastructure of the Azure resource by passing a configure
delegate of type Action<AzureResourceInfrastructure>
. The AzureResourceInfrastructure type is a subclass of the Azure.Provisioning.Infrastructure. This type exposes a massive API surface area for configuring the underlying infrastructure of the Azure resource.
Consider the following example:
var sku = builder.AddParameter("storage-sku");
var storage = builder.AddAzureStorage("storage")
.ConfigureInfrastructure(infra =>
{
var resources = infra.GetProvisionableResources();
var storageAccount = resources.OfType<StorageAccount>().Single();
storageAccount.Sku = new StorageSku
{
Name = sku.AsProvisioningParameter(infra)
};
});
The preceding code:
- Adds a parameter named
storage-sku
. - Adds Azure Storage with the AddAzureStorage API named
storage
. - Chains a call to
ConfigureInfrastructure
to customize the Azure Storage infrastructure:- Gets the provisionable resources.
- Filters to a single StorageAccount.
- Assigns the
storage-sku
parameter to the StorageAccount.Sku property:- A new instance of the StorageSku has its
Name
property assigned from the result of the AsProvisioningParameter API.
- A new instance of the StorageSku has its
This exemplifies flowing an external parameter into the Azure Storage infrastructure, resulting in the generated Bicep file reflecting the desired configuration.
Add Azure infrastructure
Not all Azure services are exposed as .NET Aspire integrations. While they might be at a later time, you can still provision services that are available in Azure.Provisioning.*
libraries. Imagine a scenario where you have worker service that's responsible for managing an Azure Container Registry. Now imagine that an app host project takes a dependency on the 📦 Azure.Provisioning.ContainerRegistry NuGet package.
You can use the AddAzureInfrastructure
API to add the Azure Container Registry infrastructure to your app host:
var acr = builder.AddAzureInfrastructure("acr", infra =>
{
var registry = new ContainerRegistryService("acr")
{
Sku = new()
{
Name = ContainerRegistrySkuName.Standard
},
};
infra.Add(registry);
var output = new ProvisioningOutput("registryName", typeof(string))
{
Value = registry.Name
};
infra.Add(output);
});
builder.AddProject<Projects.WorkerService>("worker")
.WithEnvironment(
"ACR_REGISTRY_NAME",
new BicepOutputReference("registryName", acr.Resource));
The preceding code:
- Calls AddAzureInfrastructure with a name of
acr
. - Provides a
configureInfrastructure
delegate to customize the Azure Container Registry infrastructure:- Instantiates a ContainerRegistryService with the name
acr
and a standard SKU. - Adds the Azure Container Registry service to the
infra
variable. - Instantiates a ProvisioningOutput with the name
registryName
, a type ofstring
, and a value that corresponds to the name of the Azure Container Registry. - Adds the output to the
infra
variable.
- Instantiates a ContainerRegistryService with the name
- Adds a project named
worker
to the builder. - Chains a call to WithEnvironment to set the
ACR_REGISTRY_NAME
environment variable in the project to the value of theregistryName
output.
The functionality demonstrates how to add Azure infrastructure to your app host project, even if the Azure service isn't directly exposed as a .NET Aspire integration. It further shows how to flow the output of the Azure Container Registry into the environment of a dependent project.
Consider the resulting Bicep file:
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: take('acr${uniqueString(resourceGroup().id)}', 50)
location: location
sku: {
name: 'Standard'
}
}
output registryName string = acr.name
The Bicep file reflects the desired configuration of the Azure Container Registry, as defined by the AddAzureInfrastructure
API.
Use custom Bicep templates
When you're targeting Azure as your desired cloud provider, you can use Bicep to define your infrastructure as code. It aims to drastically simplify the authoring experience with a cleaner syntax and better support for modularity and code reuse.
While .NET Aspire provides a set of prebuilt Bicep templates, there might be times when you either want to customize the templates or create your own. This section explains the concepts and corresponding APIs that you can use to customize the Bicep templates.
Important
This section isn't intended to teach you Bicep, but rather to provide guidance on how to create custom Bicep templates for use with .NET Aspire.
As part of the Azure deployment story for .NET Aspire, the Azure Developer CLI (azd
) provides an understanding of your .NET Aspire project and the ability to deploy it to Azure. The azd
CLI uses the Bicep templates to deploy the application to Azure.
Install Aspire.Hosting.Azure
package
When you want to reference Bicep files, it's possible that you're not using any of the Azure hosting integrations. In this case, you can still reference Bicep files by installing the Aspire.Hosting.Azure
package. This package provides the necessary APIs to reference Bicep files and customize the Azure resources.
Tip
If you're using any of the Azure hosting integrations, you don't need to install the Aspire.Hosting.Azure
package, as it's a transitive dependency.
To use any of this functionality, the 📦 Aspire.Hosting.Azure NuGet package must be installed:
dotnet add package Aspire.Hosting.Azure
For more information, see dotnet add package or Manage package dependencies in .NET applications.
What to expect from the examples
All the examples in this section assume that you're using the Aspire.Hosting.Azure namespace. Additionally, the examples assume you have an IDistributedApplicationBuilder instance:
using Aspire.Hosting.Azure;
var builder = DistributedApplication.CreateBuilder(args);
// Examples go here...
builder.Build().Run();
By default, when you call any of the Bicep-related APIs, a call is also made to AddAzureProvisioning that adds support for generating Azure resources dynamically during application startup. For more information, see Local provisioning and Azure.Provisioning
.
Reference Bicep files
Imagine that you have a Bicep template in a file named storage.bicep
that provisions an Azure Storage Account:
param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}
To add a reference to the Bicep file on disk, call the AddBicepTemplate method. Consider the following example:
builder.AddBicepTemplate(
name: "storage",
bicepFile: "../infra/storage.bicep");
The preceding code adds a reference to a Bicep file located at ../infra/storage.bicep
. The file paths should be relative to the app host project. This reference results in an AzureBicepResource being added to the application's resources collection with the "storage"
name, and the API returns an IResourceBuilder<AzureBicepResource>
instance that can be used to further customize the resource.
Reference Bicep inline
While having a Bicep file on disk is the most common scenario, you can also add Bicep templates inline. Inline templates can be useful when you want to define a template in code or when you want to generate the template dynamically. To add an inline Bicep template, call the AddBicepTemplateString method with the Bicep template as a string
. Consider the following example:
builder.AddBicepTemplateString(
name: "ai",
bicepContent: """
@description('That name is the name of our application.')
param cognitiveServiceName string = 'CognitiveService-${uniqueString(resourceGroup().id)}'
@description('Location for all resources.')
param location string = resourceGroup().location
@allowed([
'S0'
])
param sku string = 'S0'
resource cognitiveService 'Microsoft.CognitiveServices/accounts@2021-10-01' = {
name: cognitiveServiceName
location: location
sku: {
name: sku
}
kind: 'CognitiveServices'
properties: {
apiProperties: {
statisticsEnabled: false
}
}
}
"""
);
In this example, the Bicep template is defined as an inline string
and added to the application's resources collection with the name "ai"
. This example provisions an Azure AI resource.
Pass parameters to Bicep templates
Bicep supports accepting parameters, which can be used to customize the behavior of the template. To pass parameters to a Bicep template from .NET Aspire, chain calls to the WithParameter method as shown in the following example:
var region = builder.AddParameter("region");
builder.AddBicepTemplate("storage", "../infra/storage.bicep")
.WithParameter("region", region)
.WithParameter("storageName", "app-storage")
.WithParameter("tags", ["latest","dev"]);
The preceding code:
- Adds a parameter named
"region"
to thebuilder
instance. - Adds a reference to a Bicep file located at
../infra/storage.bicep
. - Passes the
"region"
parameter to the Bicep template, which is resolved using the standard parameter resolution. - Passes the
"storageName"
parameter to the Bicep template with a hardcoded value. - Passes the
"tags"
parameter to the Bicep template with an array of strings.
For more information, see External parameters.
Well-known parameters
.NET Aspire provides a set of well-known parameters that can be passed to Bicep templates. These parameters are used to provide information about the application and the environment to the Bicep templates. The following well-known parameters are available:
Field | Description | Value |
---|---|---|
AzureBicepResource.KnownParameters.KeyVaultName | The name of the key vault resource used to store secret outputs. | "keyVaultName" |
AzureBicepResource.KnownParameters.Location | The location of the resource. This is required for all resources. | "location" |
AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId | The resource ID of the log analytics workspace. | "logAnalyticsWorkspaceId" |
AzureBicepResource.KnownParameters.PrincipalId | The principal ID of the current user or managed identity. | "principalId" |
AzureBicepResource.KnownParameters.PrincipalName | The principal name of the current user or managed identity. | "principalName" |
AzureBicepResource.KnownParameters.PrincipalType | The principal type of the current user or managed identity. Either User or ServicePrincipal . |
"principalType" |
To use a well-known parameter, pass the parameter name to the WithParameter method, such as WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
. You don't pass values for well-known parameters, as .NET Aspire resolves them on your behalf.
Consider an example where you want to set up an Azure Event Grid webhook. You might define the Bicep template as follows:
param topicName string
param webHookEndpoint string
param principalId string
param principalType string
param location string = resourceGroup().location
// The topic name must be unique because it's represented by a DNS entry.
// must be between 3-50 characters and contain only values a-z, A-Z, 0-9, and "-".
resource topic 'Microsoft.EventGrid/topics@2023-12-15-preview' = {
name: toLower(take('${topicName}${uniqueString(resourceGroup().id)}', 50))
location: location
resource eventSubscription 'eventSubscriptions' = {
name: 'customSub'
properties: {
destination: {
endpointType: 'WebHook'
properties: {
endpointUrl: webHookEndpoint
}
}
}
}
}
resource EventGridRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(topic.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7'))
scope: topic
properties: {
principalId: principalId
principalType: principalType
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7')
}
}
output endpoint string = topic.properties.endpoint
This Bicep template defines several parameters, including the topicName
, webHookEndpoint
, principalId
, principalType
, and the optional location
. To pass these parameters to the Bicep template, you can use the following code snippet:
var webHookApi = builder.AddProject<Projects.WebHook_Api>("webhook-api");
var webHookEndpointExpression = ReferenceExpression.Create(
$"{webHookApi.GetEndpoint("https")}/hook");
builder.AddBicepTemplate("event-grid-webhook", "../infra/event-grid-webhook.bicep")
.WithParameter("topicName", "events")
.WithParameter(AzureBicepResource.KnownParameters.PrincipalId)
.WithParameter(AzureBicepResource.KnownParameters.PrincipalType)
.WithParameter("webHookEndpoint", () => webHookEndpointExpression);
- The
webHookApi
project is added as a reference to thebuilder
. - The
topicName
parameter is passed a hardcoded name value. - The
webHookEndpoint
parameter is passed as an expression that resolves to the URL from theapi
project references' "https" endpoint with the/hook
route. - The
principalId
andprincipalType
parameters are passed as well-known parameters.
The well-known parameters are convention-based and shouldn't be accompanied with a corresponding value when passed using the WithParameter
API. Well-known parameters simplify some common functionality, such as role assignments, when added to the Bicep templates, as shown in the preceding example. Role assignments are required for the Event Grid webhook to send events to the specified endpoint. For more information, see Event Grid Data Sender role assignment.
Get outputs from Bicep references
In addition to passing parameters to Bicep templates, you can also get outputs from the Bicep templates. Consider the following Bicep template, as it defines an output
named endpoint
:
param storageName string
param location string = resourceGroup().location
resource myStorageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku:{
name:'Standard_LRS'
tier: 'Standard'
}
properties: {
accessTier: 'Hot'
}
}
output endpoint string = myStorageAccount.properties.primaryEndpoints.blob
The Bicep defines an output named endpoint
. To get the output from the Bicep template, call the GetOutput method on an IResourceBuilder<AzureBicepResource>
instance as demonstrated in following C# code snippet:
var storage = builder.AddBicepTemplate(
name: "storage",
bicepFile: "../infra/storage.bicep"
);
var endpoint = storage.GetOutput("endpoint");
In this example, the output from the Bicep template is retrieved and stored in an endpoint
variable. Typically, you would pass this output as an environment variable to another resource that relies on it. For instance, if you had an ASP.NET Core Minimal API project that depended on this endpoint, you could pass the output as an environment variable to the project using the following code snippet:
var storage = builder.AddBicepTemplate(
name: "storage",
bicepFile: "../infra/storage.bicep"
);
var endpoint = storage.GetOutput("endpoint");
var apiService = builder.AddProject<Projects.AspireSample_ApiService>(
name: "apiservice"
)
.WithEnvironment("STORAGE_ENDPOINT", endpoint);
For more information, see Bicep outputs.
Get secret outputs from Bicep references
It's important to avoid outputs for secrets when working with Bicep. If an output is considered a secret, meaning it shouldn't be exposed in logs or other places, you can treat it as such. This can be achieved by storing the secret in Azure Key Vault and referencing it in the Bicep template. .NET Aspire's Azure integration provides a pattern for securely storing outputs from the Bicep template by allows resources to use the keyVaultName
parameter to store secrets in Azure Key Vault.
Consider the following Bicep template as an example the helps to demonstrate this concept of securing secret outputs:
param databaseAccountName string
param keyVaultName string
param databases array = []
@description('Tags that will be applied to all resources')
param tags object = {}
param location string = resourceGroup().location
var resourceToken = uniqueString(resourceGroup().id)
resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
name: replace('${databaseAccountName}-${resourceToken}', '-', '')
location: location
kind: 'GlobalDocumentDB'
tags: tags
properties: {
consistencyPolicy: { defaultConsistencyLevel: 'Session' }
locations: [
{
locationName: location
failoverPriority: 0
}
]
databaseAccountOfferType: 'Standard'
}
resource db 'sqlDatabases@2023-04-15' = [for name in databases: {
name: '${name}'
location: location
tags: tags
properties: {
resource: {
id: '${name}'
}
}
}]
}
var primaryMasterKey = cosmosDb.listKeys(cosmosDb.apiVersion).primaryMasterKey
resource vault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
resource secret 'secrets@2023-07-01' = {
name: 'connectionString'
properties: {
value: 'AccountEndpoint=${cosmosDb.properties.documentEndpoint};AccountKey=${primaryMasterKey}'
}
}
}
The preceding Bicep template expects a keyVaultName
parameter, among several other parameters. It then defines an Azure Cosmos DB resource and stashes a secret into Azure Key Vault, named connectionString
which represents the fully qualified connection string to the Cosmos DB instance. To access this secret connection string value, you can use the following code snippet:
var cosmos = builder.AddBicepTemplate("cosmos", "../infra/cosmosdb.bicep")
.WithParameter("databaseAccountName", "fallout-db")
.WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
.WithParameter("databases", ["vault-33", "vault-111"]);
var connectionString =
cosmos.GetSecretOutput("connectionString");
builder.AddProject<Projects.WebHook_Api>("api")
.WithEnvironment(
"ConnectionStrings__cosmos",
connectionString);
In the preceding code snippet, the cosmos
Bicep template is added as a reference to the builder
. The connectionString
secret output is retrieved from the Bicep template and stored in a variable. The secret output is then passed as an environment variable (ConnectionStrings__cosmos
) to the api
project. This environment variable is used to connect to the Cosmos DB instance.
When this resource is deployed, the underlying deployment mechanism will automatically Reference secrets from Azure Key Vault. To guarantee secret isolation, .NET Aspire creates a Key Vault per source.
Note
In local provisioning mode, the secret is extracted from Key Vault and set it in an environment variable. For more information, see Local Azure provisioning.
Publishing
When you publish your app, the Azure provisioning generated Bicep is used by the Azure Developer CLI to create the Azure resources in your Azure subscription. .NET Aspire outputs a publishing manifest, that's also a vital part of the publishing process. The Azure Developer CLI is a command-line tool that provides a set of commands to manage Azure resources.
For more information on publishing and deployment, see Deploy a .NET Aspire project to Azure Container Apps using the Azure Developer CLI (in-depth guide).
.NET Aspire