In this article, we are going to learn Azure Cosmos DB in detail.Â
We’ll start by learning what an Azure Cosmos DB is and the various APIs that it supports. Then we’ll create a Cosmos DB from the portal. After that, we’ll learn how to create an ASP.NET Core application that connects with the Cosmos DB using the Core (SQL) API. First, we’ll test it locally and then deploy it to Azure. Finally, we’ll verify that everything works well together in the cloud environment.
To read more about Azure, you can visit our Azure with ASP.NET Core page, where you can find all the articles from the series.
Let’s start
Azure Cosmos DB – Introduction & Various APIs
Modern applications need to store huge volumes of data and make this available to users very quickly. Users expect the apps to be highly responsive and always online. To achieve these, we usually deploy multiple instances of these applications in data centers that are close to the users.
Azure Cosmos DB is a fully managed NoSQL database in the cloud for modern app development. It supports many open source APIs and SDKs for popular languages. Being a PaaS service, we don’t have to worry about database administration, management, updates, and patching. It can also handle automatic scaling by responding to real-time usage.
Cosmos DB is a great choice for Web, Mobile, Gaming, and IoT applications that needs to handle massive amounts of data. It provides real-time access with fast read and writes latencies globally, high throughput, and configurable consistency. Cosmos DB gives us simplified application development with fast and open-source APIs and multiple SDKs. It supports various database APIs including the native Core (SQL) API, API for MongoDB, Cassandra API, Gremlin API, and Table API. In this article, we are going to explore the Core (SQL) API with an ASP.NET Core WEB API application.Â
Creating an Azure Cosmos DB
For creating a Cosmos DB, we can use the Azure Cosmos DB template from the Azure Marketplace:
In the Create Azure Cosmos DB Account screen, we need to provide a few details for the account:
- First, we need to select an existing <>Subscription.
- Then we need to either select an existing Resource Group or create a new one.
- After that, we need to choose an Account Name.
- As we discussed in the previous section, Azure Cosmos DB provides various APIs and we need to choose one. In this example, we are going to use Core (SQL)
- Then we need to choose a Location.
- Azure Cosmos DB provides two capacity modes. For working with traffic requiring predictable performance, we can choose Provisioned Throughput. Serverless is a good choice while working with unpredictable traffic.
- While creating a Cosmos DB, we have an option to apply Free Tier Discount. Choosing this option will give us 400 Request Units per second and 5 GB of storage in one account for free.Â
- There is an option to choose Production or Non-Production Account Type. This will just change the UI experience offered in the portal and Cosmos Explorer and will not impact the service behavior.Â
- Choosing Geo-Redundancy will enable global distribution of databases by pairing certain Regions together. Let’s disable it in this example.
- Finally, the Multi-region Writes option improves the throughput of our databases and containers. We can disable this option for now.
After providing these options, we can Review and Create the database by first clicking on the Review + Create button and then Create button. We can see the step by step progress of deployment till it is completed:
Once the database is created, we can navigate to it by clicking on the Go to resource link.
Exploring the Azure Cosmos DB
The Azure Cosmos DB organizes data in a hierarchical structure of Databases, Containers, and Items. We can add Database, Containers, and Items from the Data Explorer blade of the Cosmos DB.Â
On navigating to the Quickstart blade, there is an option to quickly create an Items container:
Using this option will create a database named ToDoList and a container named Items. We can use the Data Explorer blade to explore data inside the Cosmos DB:
As we can see, It will not have any data initially, but don’t worry we are going to learn how to add and modify data using code later. But before that, let’s copy the URL and keys required to connect with the Cosmos DB account:
Azure Cosmos DB has 2 types of keys – Read-write and Read-only keys. We are going to use Read-write keys as we want to perform both read and write operations.
Building APIs that Talks with Azure Cosmos DB
The next step is building an ASP.NET Core Web API project that connects to the Azure Cosmos DB and works on it. We have explained ASP.NET Core Web API in detail in our .NET Core Tutorial – Creating the restful Web API series. Following through the series, let’s create an ASP.NET Core Web API project. In this example, we are using ASP.NET Core 5, which is the latest version of ASP.NET at the time of writing this article, but the code should work pretty well with previous versions as well.
Configuring the App
First, we need to add the NuGet packages required to connect to Azure Cosmos DB. We can do that by running the below commands in the NuGet package manager console:
Install-Package Microsoft.Azure.Cosmos
This will download and install the Azure Cosmos DB package and its dependencies.
Then, we need to add the configuration values that we copied earlier to the appsettings file:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "CosmosDb": { "Account": "https://code-maze.documents.azure.com:443/", "Key": "<PRIMARY KEY of Azure Cosmos account>", "DatabaseName": "ToDoList", "ContainerName": "Items" } }
Creating the Service
The next step is creating a service class to work with Cosmos DB. But before that, we need to create a model for representing a ToDo Item:
public class Item { [JsonProperty(PropertyName = "id")] public string Id { get; set; } [JsonProperty(PropertyName = "name")] public string Name { get; set; } [JsonProperty(PropertyName = "description")] public string Description { get; set; } [JsonProperty(PropertyName = "isComplete")] public bool Completed { get; set; } }
Azure Cosmos DB uses JSON to store data. We can use the JsonProperty
 attribute to control how JSON serializes and deserializes objects. For the Item class, the JsonProperty
 attribute controls the format of the property name that goes into JSON. Also, note that we rename the Completed
 property to isComplete
.
Great!
Now let’s create the ICosmosDbService
interface:
public interface ICosmosDbService { Task<IEnumerable<Item>> GetMultipleAsync(string query); Task<Item> GetAsync(string id); Task AddAsync(Item item); Task UpdateAsync(string id, Item item); Task DeleteAsync(string id); }
After that, let’s create the CosmosDbService
class implementing the ICosmosDbService
interface:
public class CosmosDbService : ICosmosDbService { private Container _container; public CosmosDbService( CosmosClient cosmosDbClient, string databaseName, string containerName) { _container = cosmosDbClient.GetContainer(databaseName, containerName); } public async Task AddAsync(Item item) { await _container.CreateItemAsync(item, new PartitionKey(item.Id)); } public async Task DeleteAsync(string id) { await _container.DeleteItemAsync<Item>(id, new PartitionKey(id)); } public async Task<Item> GetAsync(string id) { try { var response = await _container.ReadItemAsync<Item>(id, new PartitionKey(id)); return response.Resource; } catch (CosmosException) //For handling item not found and other exceptions { return null; } } public async Task<IEnumerable<Item>> GetMultipleAsync(string queryString) { var query = _container.GetItemQueryIterator<Item>(new QueryDefinition(queryString)); var results = new List<Item>(); while (query.HasMoreResults) { var response = await query.ReadNextAsync(); results.AddRange(response.ToList()); } return results; } public async Task UpdateAsync(string id, Item item) { await _container.UpsertItemAsync(item, new PartitionKey(id)); } }
In the service class, we have implemented methods to perform Add, Delete, Get, List, and Update operations using Microsoft.Azure.Cosmos
package.
Initializing the Cosmos DB Client
The next step is to modify the Startup
class to read configuration values and initialize the Cosmos DB client. For that, first, let’s add a new method to the Startup
class:
private static async Task<CosmosDbService> InitializeCosmosClientInstanceAsync(IConfigurationSection configurationSection) { var databaseName = configurationSection["DatabaseName"]; var containerName = configurationSection["ContainerName"]; var account = configurationSection["Account"]; var key = configurationSection["Key"]; var client = new Microsoft.Azure.Cosmos.CosmosClient(account, key); var database = await client.CreateDatabaseIfNotExistsAsync(databaseName); await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id"); var cosmosDbService = new CosmosDbService(client, databaseName, containerName); return cosmosDbService; }
We need to call the new method from the ConfigureServices
method in the same class:
public void ConfigureServices(IServiceCollection services) { ... services.AddSingleton<ICosmosDbService>(InitializeCosmosClientInstanceAsync(Configuration.GetSection("CosmosDb")).GetAwaiter().GetResult()); }
Note that this code will create the specified database and container if it does not exist in the Azure Cosmos DB account. We can delete the database and container that we created earlier in our Cosmos DB account and verify that the application will recreate those when it starts.
That’s it. We have successfully configured and initialized the service. Now let’s proceed to create the API controller.
Creating the Controller
Let’s create an ItemsController
class for implementing the endpoints:
[Route("api/[controller]")] [ApiController] public class ItemsController : ControllerBase { private readonly ICosmosDbService _cosmosDbService; public ItemsController(ICosmosDbService cosmosDbService) { _cosmosDbService = cosmosDbService ?? throw new ArgumentNullException(nameof(cosmosDbService)); } // GET api/items [HttpGet] public async Task<IActionResult> List() { return Ok(await _cosmosDbService.GetMultipleAsync("SELECT * FROM c")); } // GET api/items/5 [HttpGet("{id}")] public async Task<IActionResult> Get(string id) { return Ok(await _cosmosDbService.GetAsync(id)); } // POST api/items [HttpPost] public async Task<IActionResult> Create([FromBody] Item item) { item.Id = Guid.NewGuid().ToString(); await _cosmosDbService.AddAsync(item); return CreatedAtAction(nameof(Get), new { id = item.Id }, item); } // PUT api/items/5 [HttpPut("{id}")] public async Task<IActionResult> Edit([FromBody] Item item) { await _cosmosDbService.UpdateAsync(item.Id, item); return NoContent(); } // DELETE api/items/5 [HttpDelete("{id}")] public async Task<IActionResult> Delete(string id) { await _cosmosDbService.DeleteAsync(id); return NoContent(); } }
We have created an API controller with List, Get, Add, Edit, and Delete endpoints. Note that by injecting the service into the controller, we are invoking service methods corresponding to each action.
Cool! Now let’s proceed to test the application.
Testing the APIs Locally
Once we run the application locally, we can see that the Swagger UI lists all the endpoints:
Since our database doesn’t have any data yet, let’s go ahead and create one record using the Create endpoint:
After that, let’s execute the endpoint to list all the records:
This will list the record that we just created.
It is possible to fetch the record using the Get endpoint as well:
Now let’s try modifying the record using the Edit endpoint:
We can verify that the record is updated by invoking the Get endpoint once again:
Perfect!
Now let’s take a look at how the record is organized in the Cosmos DB by using Data Explorer
:
We can see that Azure Cosmos DB stores data as JSON document structure. Note that there are a few additional fields as well for tracking the records internally.
Finally, let’s try deleting the record by invoking the Delete endpoint:
We can verify that the Delete operation was successful by invoking the endpoint to list all records once again:
This time it returns an empty list.Â
Great!
We have confirmed that all endpoints work as expected locally. Now let’s proceed to deploy the application to Azure.
Deploying the APIs to Azure
Let’s go ahead and deploy our application into Azure. We have explained the process of deploying an ASP.NET Core Web API project into Azure API App Service in detail in our Deploying ASP.NET Core Web API to Azure API Apps article. We can follow the same process here as well. Additionally, we can enable Swagger in the deployed version as we have explained in the Deploying the application section of Azure SQL article. This will make it easier to test the hosted application.
Testing the APIs in Azure
Once the application is deployed to Azure, let’s test it by navigating to its URL. First, let’s try adding a new record:
Once the record is added, let’s test the List endpoint:
Cool!
We have verified that everything works as expected in the Azure environment as well.
We can summarize the deployment architecture that we use in this article with a simple diagram:Â
After building an ASP.NET Core Web API application, we have deployed it into an Azure API app. The API app communicates with an Azure Cosmos DB that resides in the same resource group. Users can access the APIs over the internet using the URL.
Conclusion
We have learned the following topics in this article:
- An introduction to Azure Cosmos DB and the various APIs it supports.
- Creating and exploring an Azure Cosmos DB from the portal.
- Building and deploying an ASP.NET Core Web API that talks with Azure Cosmos DB using the Core (SQL) API.
- Testing the API endpoints that connect with Azure Cosmos DB locally and in Azure.