.NET Aspire Azure Cosmos DB integration

Includes: Hosting integration and Client integration

Azure Cosmos DB is a fully managed NoSQL database service for modern app development. The .NET Aspire Azure Cosmos DB integration enables you to connect to existing Cosmos DB instances or create new instances from .NET with the Azure Cosmos DB emulator.

Hosting integration

The .NET Aspire Azure Cosmos DB hosting integration models the various Cosmos DB resources as the following types:

To access these types and APIs for expressing them, add the 📦 Aspire.Hosting.Azure.CosmosDB NuGet package in the app host project.

dotnet add package Aspire.Hosting.Azure.CosmosDB

For more information, see dotnet add package or Manage package dependencies in .NET applications.

Add Azure Cosmos DB resource

In your app host project, call AddAzureCosmosDB to add and return an Azure Cosmos DB resource builder.

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db");

// After adding all resources, run the app...

When you add an AzureCosmosDBResource to the app host, it exposes other useful APIs to add databases and containers. In other words, you must add an AzureCosmosDBResource before adding any of the other Cosmos DB resources.

Important

When you call AddAzureCosmosDB, it implicitly calls AddAzureProvisioning—which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see Local provisioning: Configuration.

Generated provisioning Bicep

If you're new to Bicep, it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Cosmos DB resource, the following Bicep is generated:


Toggle Azure Cosmos DB Bicep.

@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param keyVaultName string

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
  name: keyVaultName
}

resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2024-08-15' = {
  name: take('cosmos-${uniqueString(resourceGroup().id)}', 44)
  location: location
  properties: {
    locations: [
      {
        locationName: location
        failoverPriority: 0
      }
    ]
    consistencyPolicy: {
      defaultConsistencyLevel: 'Session'
    }
    databaseAccountOfferType: 'Standard'
  }
  kind: 'GlobalDocumentDB'
  tags: {
    'aspire-resource-name': 'cosmos'
  }
}

resource connectionString 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  name: 'connectionString'
  properties: {
    value: 'AccountEndpoint=${cosmos.properties.documentEndpoint};AccountKey=${cosmos.listKeys().primaryMasterKey}'
  }
  parent: keyVault
}

The preceding Bicep is a module that provisions an Azure Cosmos DB account with the following defaults:

  • kind: The kind of Cosmos DB account. The default is GlobalDocumentDB.
  • consistencyPolicy: The consistency policy of the Cosmos DB account. The default is Session.
  • locations: The locations for the Cosmos DB account. The default is the resource group's location.

In addition to the Cosmos DB account, it also provisions an Azure Key Vault resource. This is used to store the Cosmos DB account's connection string securely. The generated Bicep is a starting point and can be customized to meet your specific requirements.

Customize provisioning infrastructure

All .NET Aspire Azure resources are subclasses of the AzureProvisioningResource type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources—using the ConfigureInfrastructure<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure>) API. For example, you can configure the kind, consistencyPolicy, locations, and more. The following example demonstrates how to customize the Azure Cosmos DB resource:

builder.AddAzureCosmosDB("cosmos-db")
    .ConfigureInfrastructure(infra =>
    {
        var cosmosDbAccount = infra.GetProvisionableResources()
                                   .OfType<CosmosDBAccount>()
                                   .Single();

        cosmosDbAccount.Kind = CosmosDBAccountKind.MongoDB;
        cosmosDbAccount.ConsistencyPolicy = new()
        {
            DefaultConsistencyLevel = DefaultConsistencyLevel.Strong,
        };
        cosmosDbAccount.Tags.Add("ExampleKey", "Example value");
    });

The preceding code:

There are many more configuration options available to customize the Azure Cosmos DB resource. For more information, see Azure.Provisioning.CosmosDB. For more information, see Azure.Provisioning customization.

Connect to an existing Azure Cosmos DB account

You might have an existing Azure Cosmos DB account that you want to connect to. Instead of representing a new Azure Cosmos DB resource, you can add a connection string to the app host. To add a connection to an existing Azure Cosmos DB account, call the AddConnectionString method:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddConnectionString("cosmos-db");

builder.AddProject<Projects.WebApplication>("web")
       .WithReference(cosmos);

// After adding all resources, run the app...

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.

The connection string is configured in the app host's configuration, typically under User Secrets, under the ConnectionStrings section. The app host injects this connection string as an environment variable into all dependent resources, for example:

{
    "ConnectionStrings": {
        "cosmos-db": "AccountEndpoint=https://{account_name}.documents.azure.com:443/;AccountKey={account_key};"
    }
}

The dependent resource can access the injected connection string by calling the GetConnectionString method, and passing the connection name as the parameter, in this case "cosmos-db". The GetConnectionString API is shorthand for IConfiguration.GetSection("ConnectionStrings")[name].

Add Azure Cosmos DB database resource

To add an Azure Cosmos DB database resource, chain a call on an IResourceBuilder<AzureCosmosDBResource> to the AddDatabase API:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db")
                    .AddDatabase("db");

// After adding all resources, run the app...

When you call AddDatabase, it configures your Cosmos DB resources to have a database named db. The database is created in the Cosmos DB account that's represented by the AzureCosmosDBResource that you added earlier. The database is a logical container for collections and users. For more information, see Databases, containers, and items in Azure Cosmos DB.

Note

When using the AddDatabase API to add a database to an Azure Cosmos DB resource, if you're running the emulator, the database isn't actually created in the emulator. This API is intended to include a database in the Bicep generated by the provisioning infrastructure.

Add Azure Cosmos DB emulator resource

To add an Azure Cosmos DB emulator resource, chain a call on an IResourceBuilder<AzureCosmosDBResource> to the RunAsEmulator API:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db")
                    .RunAsEmulator();

// After adding all resources, run the app...

When you call RunAsEmulator, it configures your Cosmos DB resources to run locally using an emulator. The emulator in this case is the Azure Cosmos DB Emulator. The Azure Cosmos DB Emulator provides a free local environment for testing your Azure Cosmos DB apps and it's a perfect companion to the .NET Aspire Azure hosting integration. The emulator isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the mcr.microsoft.com/cosmosdb/emulator image, it creates and starts the container when the app host starts. For more information, see Container resource lifecycle.

Configure Cosmos DB emulator container

There are various configurations available to container resources, for example, you can configure the container's ports, environment variables, it's lifetime, and more.

Configure Cosmos DB emulator container gateway port

By default, the Cosmos DB emulator container when configured by .NET Aspire, exposes the following endpoints:

Endpoint Container port Host port
https 8081 dynamic

The port that it's listening on is dynamic by default. When the container starts, the port is mapped to a random port on the host machine. To configure the endpoint port, chain calls on the container resource builder provided by the RunAsEmulator method as shown in the following example:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db").RunAsEmulator(
                     emulator =>
                     {
                         emulator.WithGatewayPort(7777);
                     });

// After adding all resources, run the app...

The preceding code configures the Cosmos DB emulator container's existing https endpoint to listen on port 8081. The Cosmos DB emulator container's port is mapped to the host port as shown in the following table:

Endpoint name Port mapping (container:host)
https 8081:7777
Configure Cosmos DB emulator container with persistent lifetime

To configure the Cosmos DB emulator container with a persistent lifetime, call the WithLifetime method on the Cosmos DB emulator container resource and pass ContainerLifetime.Persistent:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db").RunAsEmulator(
                     emulator =>
                     {
                         emulator.WithLifetime(ContainerLifetime.Persistent);
                     });

// After adding all resources, run the app...

For more information, see Container resource lifetime.

Configure Cosmos DB emulator container with data volume

To add a data volume to the Azure Cosmos DB emulator resource, call the WithDataVolume method on the Azure Cosmos DB emulator resource:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db").RunAsEmulator(
                     emulator =>
                     {
                         emulator.WithDataVolume();
                     });

// After adding all resources, run the app...

The data volume is used to persist the Cosmos DB emulator data outside the lifecycle of its container. The data volume is mounted at the /tmp/cosmos/appdata path in the Cosmos DB emulator container and when a name parameter isn't provided, the name is generated. The emulator has its AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE environment variable set to true. For more information on data volumes and details on why they're preferred over bind mounts, see Docker docs: Volumes.

Configure Cosmos DB emulator container partition count

To configure the partition count of the Cosmos DB emulator container, call the WithPartitionCount method:

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos-db").RunAsEmulator(
                     emulator =>
                     {
                         emulator.WithPartitionCount(100); // Defaults to 25
                     });

// After adding all resources, run the app...

The preceding code configures the Cosmos DB emulator container to have a partition count of 100. This is a shorthand for setting the AZURE_COSMOS_EMULATOR_PARTITION_COUNT environment variable.

Hosting integration health checks

The Azure Cosmos DB hosting integration automatically adds a health check for the Cosmos DB resource. The health check verifies that the Cosmos DB is running and that a connection can be established to it.

The hosting integration relies on the 📦 AspNetCore.HealthChecks.CosmosDb NuGet package.

Client integration

To get started with the .NET Aspire Azure Cosmos DB client integration, install the 📦 Aspire.Microsoft.Azure.Cosmos NuGet package in the client-consuming project, that is, the project for the application that uses the Cosmos DB client. The Cosmos DB client integration registers a CosmosClient instance that you can use to interact with Cosmos DB.

dotnet add package Aspire.Microsoft.Azure.Cosmos

Add Cosmos DB client

In the Program.cs file of your client-consuming project, call the AddAzureCosmosClient extension method on any IHostApplicationBuilder to register a CosmosClient for use via the dependency injection container. The method takes a connection name parameter.

builder.AddAzureCosmosClient(connectionName: "cosmos-db");

Tip

The connectionName parameter must match the name used when adding the Cosmos DB resource in the app host project. In other words, when you call AddAzureCosmosDB and provide a name of cosmos-db that same name should be used when calling AddAzureCosmosClient. For more information, see Add Azure Cosmos DB resource.

You can then retrieve the CosmosClient instance using dependency injection. For example, to retrieve the connection from an example service:

public class ExampleService(CosmosClient client)
{
    // Use client...
}

For more information on dependency injection, see .NET dependency injection.

Add keyed Cosmos DB client

There might be situations where you want to register multiple CosmosClient instances with different connection names. To register keyed Cosmos DB clients, call the AddKeyedAzureCosmosClient method:

builder.AddKeyedAzureCosmosClient(name: "mainDb");
builder.AddKeyedAzureCosmosClient(name: "loggingDb");

Important

When using keyed services, it's expected that your Cosmos DB resource configured two named databases, one for the mainDb and one for the loggingDb.

Then you can retrieve the CosmosClient instances using dependency injection. For example, to retrieve the connection from an example service:

public class ExampleService(
    [FromKeyedServices("mainDb")] CosmosClient mainDbClient,
    [FromKeyedServices("loggingDb")] CosmosClient loggingDbClient)
{
    // Use clients...
}

For more information on keyed services, see .NET dependency injection: Keyed services.

Configuration

The .NET Aspire Azure Cosmos DB integration provides multiple options to configure the connection based on the requirements and conventions of your project.

Use a connection string

When using a connection string from the ConnectionStrings configuration section, you can provide the name of the connection string when calling the AddAzureCosmosClient method:

builder.AddAzureCosmosClient("cosmos-db");

Then the connection string is retrieved from the ConnectionStrings configuration section:

{
  "ConnectionStrings": {
    "cosmos-db": "AccountEndpoint=https://{account_name}.documents.azure.com:443/;AccountKey={account_key};"
  }
}

For more information on how to format this connection string, see the ConnectionString documentation.

Use configuration providers

The .NET Aspire Azure Cosmos DB integration supports Microsoft.Extensions.Configuration. It loads the MicrosoftAzureCosmosSettings from configuration by using the Aspire:Microsoft:Azure:Cosmos key. The following snippet is an example of a appsettings.json file that configures some of the options:

{
  "Aspire": {
    "Microsoft": {
      "Azure": {
        "Cosmos": {
          "DisableTracing": false,
        }
      }
    }
  }
}

For the complete Cosmos DB client integration JSON schema, see Aspire.Microsoft.Azure.Cosmos/ConfigurationSchema.json.

Use inline delegates

Also you can pass the Action<MicrosoftAzureCosmosSettings> configureSettings delegate to set up some or all the options inline, for example to disable tracing from code:

builder.AddAzureCosmosClient(
    "cosmos-db",
    static settings => settings.DisableTracing = true);

You can also set up the Microsoft.Azure.Cosmos.CosmosClientOptions using the optional Action<CosmosClientOptions> configureClientOptions parameter of the AddAzureCosmosClient method. For example to set the CosmosClientOptions.ApplicationName user-agent header suffix for all requests issues by this client:

builder.AddAzureCosmosClient(
    "cosmosConnectionName",
    configureClientOptions:
        clientOptions => clientOptions.ApplicationName = "myapp");

Client integration health checks

By default, .NET Aspire integrations enable health checks for all services. For more information, see .NET Aspire integrations overview.

The .NET Aspire Azure Cosmos DB integration:

  • Adds the health check when MicrosoftAzureCosmosSettings.DisableTracing is false, which attempts to connect to the Cosmos DB.
  • Integrates with the /health HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic.

Observability and telemetry

.NET Aspire integrations automatically set up Logging, Tracing, and Metrics configurations, which are sometimes known as the pillars of observability. For more information about integration observability and telemetry, see .NET Aspire integrations overview. Depending on the backing service, some integrations may only support some of these features. For example, some integrations support logging and tracing, but not metrics. Telemetry features can also be disabled using the techniques presented in the Configuration section.

Logging

The .NET Aspire Azure Cosmos DB integration uses the following log categories:

  • Azure-Cosmos-Operation-Request-Diagnostics

In addition to getting Azure Cosmos DB request diagnostics for failed requests, you can configure latency thresholds to determine which successful Azure Cosmos DB request diagnostics will be logged. The default values are 100 ms for point operations and 500 ms for non point operations.

builder.AddAzureCosmosClient(
    "cosmosConnectionName",
    configureClientOptions:
        clientOptions => {
            clientOptions.CosmosClientTelemetryOptions = new()
            {
                CosmosThresholdOptions = new()
                {
                    PointOperationLatencyThreshold = TimeSpan.FromMilliseconds(50),
                    NonPointOperationLatencyThreshold = TimeSpan.FromMilliseconds(300)
                }
            };
        });

Tracing

The .NET Aspire Azure Cosmos DB integration will emit the following tracing activities using OpenTelemetry:

  • Azure.Cosmos.Operation

Azure Cosmos DB tracing is currently in preview, so you must set the experimental switch to ensure traces are emitted.

AppContext.SetSwitch("Azure.Experimental.EnableActivitySource", true);

For more information, see Azure Cosmos DB SDK observability: Trace attributes.

Metrics

The .NET Aspire Azure Cosmos DB integration currently doesn't support metrics by default due to limitations with the Azure SDK.

See also