Skip to content

Develop Solutions that Use Azure Cosmos DB

This guide covers the AZ-204 exam topics for developing solutions with Azure Cosmos DB:

  • Perform operations on containers and items by using the SDK
  • Set the appropriate consistency level for operations
  • Implement change feed notifications

Prerequisites

  • .NET SDK 8.0 (Install via winget: winget install Microsoft.DotNet.SDK.8)
  • Azure CLI (Install)
  • Azure Functions Core Tools (Install)
  • Azure Subscription (Free tier or $200 credit recommended)
  • Existing Resource Group (az204exam)

Set Up Cosmos DB

Follow these steps to set up Azure Cosmos DB:

  1. Create a Cosmos DB account in the Azure Portal.

  2. Create a database and container in the Cosmos DB account.

Step 1: Create a Cosmos DB Account

In the Azure Portal, go to Azure Cosmos DB > Create > Choose NoSQL API. Configure:

  • Resource group: az204exam.
  • Account name: taskmanagercosmos (or unique, e.g., taskmanagercosmosyourname).
  • Leave defaults (e.g., Free tier, multi-region writes off).
  • Review tabs for learning, then Create.

CosmosDB

Step 2: Create Database and Container

In your Cosmos DB account, go to Data Explorer:

  • Click New Database > Name: TasksDB > Provision throughput (leave default).
  • Click New Container > Use existing database: TasksDB.
  • Container ID: Tasks.
  • Partition key: /id.
  • Throughput: 400 RU/s (manual, minimal for Free tier).
  • Click OK.

Container Setup

Perform Operations with the SDK

Note: We’ll add a Function to create and read tasks in TasksDB/Tasks, keeping our web app in-memory for now.

Follow these steps to perform operations with the Cosmos DB SDK:

  1. Add the Cosmos DB SDK to the Function App.

  2. Get the Cosmos DB connection string and add it to the Function App.

  3. Create a ManageTask Function to handle task operations.

  4. Test locally (optional).

  5. Deploy and test in Azure.

Step 1: Add Cosmos DB SDK

In the TaskManagerFunctions directory, run:

dotnet add package Microsoft.Azure.Cosmos
dotnet add package Newtonsoft.Json

Step 2: Get Cosmos DB Connection

In the Azure Portal, go to your Cosmos DB account > Keys. Copy the Primary Connection String.

In your Function App (taskmanagerfunc-yourname), go to Settings > Environment Variables. Add:

  • Name: CosmosDBConnection.
  • Value: [your-connection-string].

Step 3: Create ManageTask Function

Create a new HTTP-triggered Function.

cd TaskManagerFunctions
func new --template "HttpTrigger" --name ManageTask

Edit ManageTask.cs:

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Azure.Cosmos;

namespace TaskManagerFunctions
{
    public class ManageTask
    {
        private readonly ILogger<ManageTask> _logger;
        private readonly CosmosClient _cosmosClient;

        public ManageTask(ILogger<ManageTask> logger)
        {
            _logger = logger;
            _cosmosClient = new CosmosClient(Environment.GetEnvironmentVariable("CosmosDBConnection"), new CosmosClientOptions { ConnectionMode = ConnectionMode.Direct });
        }

        public class TaskItem
        {
            public string id { get; set; } = Guid.NewGuid().ToString();
            public string Title { get; set; }
            public string Description { get; set; }
            public string DueDate { get; set; }
        }

        [Function("ManageTask")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", "get")] HttpRequest req)
        {
            _logger.LogInformation("Processing task in Cosmos DB.");

            var container = _cosmosClient.GetContainer("TasksDB", "Tasks");

            if (req.Method == "POST")
            {
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                TaskItem task = JsonConvert.DeserializeObject<TaskItem>(requestBody);

                if (string.IsNullOrEmpty(task?.Title))
                {
                    return new BadRequestObjectResult("Please provide a title.");
                }

                task.id = Guid.NewGuid().ToString();
                await container.CreateItemAsync(task, new PartitionKey(task.id));
                _logger.LogInformation($"Created task: {task.Title}");
                return new OkObjectResult(task);
            }
            else // GET
            {
                string taskId = req.Query["taskId"];
                if (string.IsNullOrEmpty(taskId))
                {
                    return new BadRequestObjectResult("Please provide taskId.");
                }

                try
                {
                    var task = await container.ReadItemAsync<TaskItem>(taskId, new PartitionKey(taskId));
                    _logger.LogInformation($"Read task: {task.Resource.Title}");
                    return new OkObjectResult(task.Resource);
                }
                catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    return new NotFoundResult();
                }
            }
        }
    }
}

Step 4: Test Locally (Optional)

Update local.settings.json (don’t overwrite values from previous lessons):

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
        "CosmosDBConnection": "[your-connection-string]"
    }
}

Run the Function locally:

func start

POST (create task):

curl -X POST http://localhost:7071/api/ManageTask -H "Content-Type: application/json" -d '{"Title":"Cosmos Task","Description":"Test SDK","DueDate":"2025-04-15"}'

GET (read task, use id from POST response):

curl http://localhost:7071/api/ManageTask?taskId=[task-id]

Check Azure Portal > Data Explorer > TasksDB/Tasks for the task.

Step 5: Deploy and Test

Deploy the Function to Azure:

func azure functionapp publish taskmanagerfunc-yourname

Test:

curl -X POST https://taskmanagerfunc-yourname.azurewebsites.net/api/managetask?code=[your-key] -H "Content-Type: application/json" -d '{"Title":"Azure Cosmos","Description":"Deployed","DueDate":"2025-04-15"}'
curl https://taskmanagerfunc-yourname.azurewebsites.net/api/managetask?code=[your-key]&taskId=[task-id]

Verify in Data Explorer.

Why

Creating and reading tasks with the SDK is a core exam skill, and it preps for web app integration.

Set the Appropriate Consistency Level

Note: Cosmos DB offers consistency levels (Strong, Session, Eventual, etc.). We’ll use Session for our tasks, balancing performance and accuracy.

Follow these steps to set and verify the consistency level:

  1. Configure the consistency level in the Azure Portal.

  2. Verify the consistency level in code.

  3. Test consistency with operations.

Step 1: Configure Consistency

In the Azure Portal, go to your Cosmos DB account > Settings > Default consistency. Select Session > Save.

Step 2: Verify in Code

In ManageTask.cs, we initialized:

_cosmosClient = new CosmosClient(Environment.GetEnvironmentVariable("CosmosDBConnection"), new CosmosClientOptions { ConnectionMode = ConnectionMode.Direct });

Session consistency ensures clients see their own writes, ideal for task creation/reading.

Step 3: Test Consistency

Run the POST/GET tests from the previous section:

  • POST a task, then GET it immediately.
  • Check Data Explorer to confirm the task matches (e.g., same Title).

Why

Session consistency is common for apps like ours and often tested in the exam.

Implement Change Feed Notifications

Note: Change feed tracks changes in Tasks. We’ll add a Function to log updates, useful for notifications.

Follow these steps to implement change feed notifications:

  1. Create a Change Feed Function.

  2. Test locally (optional).

  3. Deploy and test in Azure.

Step 1: Create Change Feed Function

Create a new Cosmos DB Trigger Function.

cd TaskManagerFunctions
func new --template "Azure Cosmos DB Trigger" --name TaskChangeFeed

Update TaskChangeFeed.cs:

using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace TaskManagerFunctions
{
    public class TaskChangeFeed
    {
        private readonly ILogger<TaskChangeFeed> _logger;

        public TaskChangeFeed(ILogger<TaskChangeFeed> logger)
        {
            _logger = logger;
        }

        [Function("TaskChangeFeed")]
        public void Run([CosmosDBTrigger(
            databaseName: "TasksDB",
            containerName: "Tasks",
            Connection = "CosmosDBConnection",
            LeaseContainerName = "leases",
            CreateLeaseContainerIfNotExists = true)] IReadOnlyList<TaskItem> tasks)
        {
            foreach (var task in tasks)
            {
                _logger.LogInformation($"Task updated: {task.Title}, ID: {task.id}");
            }
        }

        public class TaskItem
        {
            public string id { get; set; }
            public string Title { get; set; }
            public string Description { get; set; }
            public string DueDate { get; set; }
        }
    }
}

Step 2: Test Locally (Optional)

Ensure local.settings.json has CosmosDBConnection.

Run the Function locally:

func start

POST a task via ManageTask (as in the earlier section). Check the console for “Task updated: [title], ID: [id]”.

Step 3: Deploy and Test

Deploy the Function to Azure:

func azure functionapp publish taskmanagerfunc-yourname

POST a task via ManageTask. Check Azure Portal > Functions > TaskChangeFeed > Monitor > Logs for update logs.

Why

Change feed is a key exam topic, showing how to react to data changes (e.g., for notifications).