Skip to content

Cosmos DB

Integrate Azure Cosmos DB (NoSQL) with ASP.NET Core 8 using the Microsoft.Azure.Cosmos SDK and production-safe client lifecycle patterns.

flowchart TD
    A[Set Cosmos endpoint and database settings] --> B[Create singleton CosmosClient]
    B --> C[Resolve container]
    C --> D[Run CRUD with partition key]
    D --> E[Monitor RU and latency]

Prerequisites

  • Azure Cosmos DB account, database, and container created
  • App Service app with access to Cosmos endpoint and credentials or RBAC
  • Familiarity with partition keys and RU-based throughput

Main content

1) Add NuGet package

<ItemGroup>
  <PackageReference Include="Microsoft.Azure.Cosmos" Version="3.47.0" />
</ItemGroup>

2) Configuration model

Set configuration values in App Settings:

az webapp config appsettings set \
  --resource-group "$RESOURCE_GROUP_NAME" \
  --name "$WEB_APP_NAME" \
  --settings Cosmos__Endpoint="https://<cosmos-account>.documents.azure.com:443/" Cosmos__Database="GuideDb" Cosmos__Container="Items" \
  --output json
| Flag | Description | |---|---| | az webapp config appsettings set | Creates or updates app settings on the web app. | | --resource-group "$RESOURCE_GROUP_NAME" | Targets the resource group that contains the web app. | | --name "$WEB_APP_NAME" | Selects the web app whose Cosmos settings are being updated. | | --settings Cosmos__Endpoint=... Cosmos__Database=... Cosmos__Container=... | Stores the Cosmos endpoint, database name, and container name as app settings for the ASP.NET Core app. | | --output json | Returns the updated app-settings payload as JSON. |

Store keys in Key Vault or use managed identity with RBAC where available.

3) Register singleton CosmosClient

using Microsoft.Azure.Cosmos;

builder.Services.AddSingleton(serviceProvider =>
{
    var configuration = serviceProvider.GetRequiredService<IConfiguration>();
    var endpoint = configuration["Cosmos:Endpoint"] ?? throw new InvalidOperationException("Cosmos endpoint missing.");
    var key = configuration["Cosmos:Key"] ?? throw new InvalidOperationException("Cosmos key missing.");

    var options = new CosmosClientOptions
    {
        ConnectionMode = ConnectionMode.Direct,
        SerializerOptions = new CosmosSerializationOptions { PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase }
    };

    return new CosmosClient(endpoint, key, options);
});

4) Define model and repository

public sealed class CatalogItem
{
    public string Id { get; init; } = Guid.NewGuid().ToString("N");
    public string Category { get; init; } = "general"; // partition key
    public string Name { get; init; } = string.Empty;
    public decimal Price { get; init; }
}

public sealed class CatalogRepository
{
    private readonly Container _container;

    public CatalogRepository(CosmosClient client, IConfiguration configuration)
    {
        var databaseName = configuration["Cosmos:Database"]!;
        var containerName = configuration["Cosmos:Container"]!;
        _container = client.GetContainer(databaseName, containerName);
    }

    public Task<ItemResponse<CatalogItem>> CreateAsync(CatalogItem item, CancellationToken cancellationToken)
        => _container.CreateItemAsync(item, new PartitionKey(item.Category), cancellationToken: cancellationToken);
}

5) CRUD controller example

[ApiController]
[Route("api/catalog")]
public sealed class CatalogController : ControllerBase
{
    private readonly CatalogRepository _repository;
    public CatalogController(CatalogRepository repository) => _repository = repository;

    [HttpPost]
    public async Task<IActionResult> Create([FromBody] CatalogItem item, CancellationToken cancellationToken)
    {
        var response = await _repository.CreateAsync(item, cancellationToken);
        return Created($"/api/catalog/{response.Resource.Id}", response.Resource);
    }
}

6) Monitor RU and latency

Inspect request charge in application logs:

_logger.LogInformation("Cosmos request charge: {RequestCharge}", response.RequestCharge);

7) Azure DevOps config injection snippet

- task: AzureAppServiceSettings@1
  inputs:
    azureSubscription: $(azureSubscription)
    appName: $(webAppName)
    resourceGroupName: $(resourceGroupName)
    appSettings: |
      [
        { "name": "Cosmos__Endpoint", "value": "https://<cosmos-account>.documents.azure.com:443/", "slotSetting": false },
        { "name": "Cosmos__Database", "value": "GuideDb", "slotSetting": true },
        { "name": "Cosmos__Container", "value": "Items", "slotSetting": true }
      ]

Keep CosmosClient singleton

Creating CosmosClient per request causes socket churn and latency. Register a single client instance for the app lifetime.

Verification

curl --request POST "https://$WEB_APP_NAME.azurewebsites.net/api/catalog" \
  --header "Content-Type: application/json" \
  --data '{"category":"books","name":"Cloud Patterns","price":39.99}'

Validate item exists in Cosmos Data Explorer and check App Insights dependency telemetry for Cosmos calls.

Troubleshooting

401 or 403 from Cosmos

  • Validate key or RBAC permissions.
  • Confirm endpoint and account name are correct.
  • Ensure firewall/private network rules allow app connectivity.

High RU consumption

  • Revisit partition key choice.
  • Use point reads over cross-partition queries when possible.
  • Add selective indexing policy.

Serialization mismatch

Align CLR naming and JSON policy; use explicit attributes when integrating with pre-existing document schema.

See Also

Sources