Azure Cosmos DB SQL API CRUD Operations with C#

In this article, we will learn how to perform create, read, update, and delete (CRUD) operations in Azure Cosmos DB SQL API with C# in step by step tutorial.

Step 1: Set up Prerequisites

We need to set up one of the following required pre-requisites to perform the CRUD operation in the Azure Cosmos DB with C#.

    • Azure Subscription OR
    • Azure Cosmos DB Emulator 
refer the following articles to complete the preceding requirment 

I hope you have completed the required setup as explained in this article, including the creation of the Azure Cosmos account and database.

Now let's start creating the ASP.NET Core web API project with C# to create the CRUD operations.

Step 1: Create ASP.NET Core web api Project with C#

  1. Start then  All Programs and select "Microsoft Visual Studio".
  2. Once the Visual Studio Opens, Then click on Continue Without Code.
  3. Then Go to Visual Studio Menu, click on File => New Project then choose ASP.NET Core Web Api Project Template.
  4. Then define the project name, location of the project, then click on the next button.
  5. On the next screen, provide the additional details: framework, authentication type, and check the Enable Open API Support checkbox as shown below.


The preceding steps will create the ASP.NET Core Web API application and solution explorer. It will look like what is shown in the following image.



Step 2: Add Microsoft.Azure.Cosmos Nuget Package Reference

The Microsoft.Azure.Cosmos is the the latest nuget package to interact with the Azure cosmos DB. The Microsoft.Azure.Cosmos supports the basic to custom and complex database operations, follow the following steps to add the Nuget package.

  1. Right click on the Solution Explorer, find Manage NuGet Package Manager and click on it
  2. After as shown into the image and type in search box Microsoft.Azure.Cosmos
  3. Select Microsoft.Azure.Cosmos as shown into the image, 
  4. Choose version of Microsoft.Azure.Cosmos library and click on install button


I hope you have followed the same steps and installed the Microsoft.Azure.Cosmos nuget package.The next step is to delete the default controller and model class so we can start from scratch.


Step 3:Create the Model Class

  • First, delete the default model class, which is created outside the folder structure, so we can start from scratch. 
  • Next, create the folder named Model by right clicking on the solution explorer.
  • Create the model class Employee Model by right clicking on the Model folder, as shown in the following image


Now open the EmployeeModel.cs class file and add the following code.

EmployeeModel.cs

namespace EmployeeManagement.Model
{
    public class EmployeeModel
    {
        public string? id { get; set; }
        public string? Name { get; set; }
        public string? Country { get; set; }
        public string? City { get; set; }       
        public string? Department { get; set; }
        public string? Designation { get; set; }
        public DateTime? JoiningDate { get; set; }

    }
}

Step 4: Add the Controller

Create the Empty API Controller class EmployeeController by right clicking on the Controller folder as shown in the following image.



After adding the model class and API controller class, the solution explorer will look like the following:




Now open the EmployeeController.cs file and add the add the following configuration.
  • Define the following route at controller level, so that we can add the multiple Get, Post, Put, or Delete and avoid the name ambiguity exception.
    [ApiController]
    [Route("[api/[controller]/[action]]")]
    public class EmployeeController : ControllerBase
    {
    }

  • Declare the following variable and set the Azure Cosmos DB configuration by copying the details from step 2.
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class EmployeeController : ControllerBase
    {
       
        // Cosmos DB details, In real use cases, these details should be configured in secure configuraion file.
        private readonly string CosmosDBAccountUri = "https://localhost:8081/";
        private readonly string CosmosDBAccountPrimaryKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
        private readonly string CosmosDbName = "EmployeeManagementDB";
        private readonly string CosmosDbContainerName = "Employees";
}

Step 5: Create Method to Add Employee

Add the following code into the EmployeeController.cs class to Add the employees into the CosmosDB. This method takes input values using  the EmployeeModel class. 

        [HttpPost]
        public async Task<IActionResult> AddEmployee(EmployeeModel employee)
        {
            try
            {
                var container = ContainerClient();
                var response = await container.CreateItemAsync(employee, new PartitionKey(employee.Department));

                return Ok(response);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
               
        }


As explained in step 2, we are passing the ID and Department as a partition key as part of the employee input payload while adding the employee details. These parameters must be part of the input parameter payload.

Step 6:  Create Method to Get Employees

Add the following code into the EmployeeController.cs class to get all the employees from the Cosmos database.

        [HttpGet]
        public async Task<IActionResult> GetEmployeeDetails()
        {
            try
            {
                var container = ContainerClient();
                var sqlQuery = "SELECT * FROM c";
                QueryDefinition queryDefinition = new QueryDefinition(sqlQuery);
                FeedIterator<EmployeeModel> queryResultSetIterator = container.GetItemQueryIterator<EmployeeModel>(queryDefinition);


                List<EmployeeModel> employees = new List<EmployeeModel>();

                while (queryResultSetIterator.HasMoreResults)
                {
                    FeedResponse<EmployeeModel> currentResultSet = await queryResultSetIterator.ReadNextAsync();
                    foreach (EmployeeModel employee in currentResultSet)
                    {
                        employees.Add(employee);
                    }
                }

                return Ok(employees);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
           
        }


This example is not good practise since we are fetching all the employees without paging or a partition key filter, but we are doing this to learn how it works without making it complicated. In the next article, I will show how to get a list of records with the paging.

Step 7: Create Method to Get Employee by ID

Create the GetEmployeeDetailsById method in the EmployeeController.cs and add the following code to get the employee by employeeId and partition key from the Cosmos database.


        [HttpGet]
        public async Task<IActionResult> GetEmployeeDetailsById(string employeeId,string partitionKey)
        {

            try
            {
                var container = ContainerClient();
                ItemResponse<EmployeeModel> response = await container.ReadItemAsync<EmployeeModel>(employeeId, new PartitionKey(partitionKey));
                return Ok(response.Resource);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }

        }

Step 8: Create Method to Update Employee

Create the UpdateEmployee method in the EmployeeController.cs and add the following code to update  the employee by employeeId and partition key.

The CosmosDB does not support the partial update feature; rather, it actually replaces the existing item by getting the document to be updated and sending the same details to the database after fields to change or update.

       [HttpPut]
        public async Task<IActionResult> UpdateEmployee(EmployeeModel emp,string partitionKey)
        {

            try
            {

                var container = ContainerClient();
                ItemResponse<EmployeeModel> res = await container.ReadItemAsync<EmployeeModel>(emp.id, new PartitionKey(partitionKey));

                //Get Existing Item
                var existingItem = res.Resource;

                //Replace existing item values with new values 
                existingItem.Name = emp.Name;
                existingItem.Country = emp.Country;
                existingItem.City = emp.City;
                existingItem.Department = emp.Department;
                existingItem.Designation = emp.Designation;

              var updateRes=  await container.ReplaceItemAsync(existingItem, emp.id, new PartitionKey(partitionKey));

                return Ok(updateRes.Resource);

            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
          
        }

Step 9: Create Method to Delete Employee

Create the DeleteEmployee method in the EmployeeController.cs and add the following code to delete the employee by employeeId and partition key.

        [HttpDelete]
        public async Task<IActionResult> DeleteEmployee(string empId, string partitionKey)
        {

            try
            {

                var container = ContainerClient();
               var response= await container.DeleteItemAsync<EmployeeModel>(empId, new PartitionKey(partitionKey));
                return Ok(response.StatusCode);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
        }

    }

The entire code of the EmployeeController.cs class file will look like the following after adding all the methods together:

EmployeeController.cs

using EmployeeManagement.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Cosmos;

namespace EmployeeManagement.Controllers
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class EmployeeController : ControllerBase
    {
       
        // Cosmos DB details, In real use cases, these details should be configured in secure configuraion file.
        private readonly string CosmosDBAccountUri = "https://localhost:8081/";
        private readonly string CosmosDBAccountPrimaryKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
        private readonly string CosmosDbName = "EmployeeManagementDB";
        private readonly string CosmosDbContainerName = "Employees";


        /// <summary>
        /// Commom Container Client, you can also pass the configuration paramter dynamically.
        /// </summary>
        /// <returns> Container Client </returns>
        private  Container  ContainerClient()
        {

            CosmosClient cosmosDbClient = new CosmosClient(CosmosDBAccountUri, CosmosDBAccountPrimaryKey);
            Container containerClient = cosmosDbClient.GetContainer(CosmosDbName, CosmosDbContainerName);
            return containerClient;
           
        }


        [HttpPost]
        public async Task<IActionResult> AddEmployee(EmployeeModel employee)
        {
            try
            {
                var container = ContainerClient();
                var response = await container.CreateItemAsync(employee, new PartitionKey(employee.Department));

                return Ok(response);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
               
        }

        [HttpGet]
        public async Task<IActionResult> GetEmployeeDetails()
        {
            try
            {
                var container = ContainerClient();
                var sqlQuery = "SELECT * FROM c";
                QueryDefinition queryDefinition = new QueryDefinition(sqlQuery);
                FeedIterator<EmployeeModel> queryResultSetIterator = container.GetItemQueryIterator<EmployeeModel>(queryDefinition);


                List<EmployeeModel> employees = new List<EmployeeModel>();

                while (queryResultSetIterator.HasMoreResults)
                {
                    FeedResponse<EmployeeModel> currentResultSet = await queryResultSetIterator.ReadNextAsync();
                    foreach (EmployeeModel employee in currentResultSet)
                    {
                        employees.Add(employee);
                    }
                }

                return Ok(employees);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
           
        }
        [HttpGet]
        public async Task<IActionResult> GetEmployeeDetailsById(string employeeId,string partitionKey)
        {

            try
            {
                var container = ContainerClient();
                ItemResponse<EmployeeModel> response = await container.ReadItemAsync<EmployeeModel>(employeeId, new PartitionKey(partitionKey));
                return Ok(response.Resource);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }

        }
        [HttpPut]
        public async Task<IActionResult> UpdateEmployee(EmployeeModel emp,string partitionKey)
        {

            try
            {

                var container = ContainerClient();
                ItemResponse<EmployeeModel> res = await container.ReadItemAsync<EmployeeModel>(emp.id, new PartitionKey(partitionKey));

                //Get Existing Item
                var existingItem = res.Resource;

                //Replace existing item values with new values 
                existingItem.Name = emp.Name;
                existingItem.Country = emp.Country;
                existingItem.City = emp.City;
                existingItem.Department = emp.Department;
                existingItem.Designation = emp.Designation;

              var updateRes=  await container.ReplaceItemAsync(existingItem, emp.id, new PartitionKey(partitionKey));

                return Ok(updateRes.Resource);

            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
          
        }

        [HttpDelete]
        public async Task<IActionResult> DeleteEmployee(string empId, string partitionKey)
        {

            try
            {

                var container = ContainerClient();
               var response= await container.DeleteItemAsync<EmployeeModel>(empId, new PartitionKey(partitionKey));
                return Ok(response.StatusCode);
            }
            catch (Exception ex)
            {

                return BadRequest(ex.Message);
            }
        }

    }
}

Now, we have all the code and required configuration to work with Azure CosmosDB in our sample application.

Step 10: Run the ASP.NET Core API Application

Now press Keyboard F5 or the Visual Studio Run button to run the application. After running the application, the following screen will be shown in the browser with swagger UI having all the methods which we have created in our ASP.NET core web API, as shown in the following screenshot:


Now, we will test the functionality by using the Swagger UI, but you can use Postman or any other tool to execute the API endpoints.

Step 11: Azure Cosmos DB CRUD Demo 

Watch the following animated image to see how the insert, read, update, and delete operations of Azure Cosmos DB work.

Add Employees


Get List of Employees and Employee by Id




Update the Employee


Delete the Employee by Id




Summary

I hope, from all the examples above, you have learned how to make Azure Cosmos DB SQL API CRUD Operations with C#.

Post a Comment

www.CodeNirvana.in

Protected by Copyscape
Copyright © Compilemode