Posts

....
Technical Blog for .NET Developers ©

Saturday, June 22, 2024

Azure Cosmos DB

Azure Cosmos DB is the Cloud Database for AI Era, its features make it the option for globally and fast access distributed databases: Azure Cosmos DB




In this post we are implementing access from Web Api to Azure Cosmos DB with a Generic Repository. Previously we have set up the resource and filled the containers in the database

The implementation of the library to access the database needs the database name, container, and account data

 
public static class CosmosDbConfiguration
{
    public static void ConfigureCosmosDb(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddSingleton<ICosmosUsersLibrary>(InitializeCosmosClientInstanceAsync(configuration.GetSection("CosmosDbUsers")));
    }

    private static CosmosUsersLibrary InitializeCosmosClientInstanceAsync(IConfigurationSection configurationSection)
    {
        string databaseName = configurationSection.GetSection("DatabaseName")!.Value!;
        string containerName = configurationSection.GetSection("ContainerName")!.Value!;
        string account = configurationSection.GetSection("Account")!.Value!;

        // If key is not set, assume we're using managed identity
        string key = configurationSection.GetSection("Key")!.Value!;
        CosmosClient client;
        if (string.IsNullOrEmpty(key))
        {
            ManagedIdentityCredential miCredential = new ();
            client = new CosmosClient(account, miCredential);
        }
        else
        {
            client = new CosmosClient(account, key);
        }

        CosmosUsersLibrary cosmosDbService = new (client, databaseName, containerName);
        
        //DatabaseResponse database = await client.CreateDatabaseIfNotExistsAsync(databaseName);
        //await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id");

        return cosmosDbService;
    }
}


 
public class CosmosUsersLibrary(
    CosmosClient dbClient,
    string databaseName,
    string containerName) : CosmosLibrary<CosmosUser>, ICosmosUsersLibrary
{
    public override Container Container 
    {
        get
        {
            return dbClient.GetContainer(databaseName, containerName);
        }
    }
}  



The Generic Repository is implemented in a base class, the abstract pattern is important to override operations such as logical delete or updates with dependencies

   
using Microsoft.Azure.Cosmos;

namespace Cosmos.Infrastructure;

public abstract class CosmosLibrary<T> : ICosmosLibrary<T> where T : ICosmosItem
{
    public abstract Container Container { get; }

    public async Task AddItemAsync(T item)
    {
        await this.Container.CreateItemAsync<T>(item, new PartitionKey(item.Id));
    }

    public async Task DeleteItemAsync(string id)
    {
        await this.Container.DeleteItemAsync<CosmosUser>(id, new PartitionKey(id));
    }

    public async Task<T> GetItemAsync(string id)
    {
        try
        {
            ItemResponse<T> response = await this.Container.ReadItemAsync<T>(id, new PartitionKey(id));
            return response.Resource;
        }
        catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
        {
            return default;
        }
    }

    public async Task<IEnumerable<T>> GetItemsAsync(string queryString)
    {
        var query = this.Container.GetItemQueryIterator<T>(new QueryDefinition(queryString));
        List<T> results = [];
        while (query.HasMoreResults)
        {
            FeedResponse<T> response = await query.ReadNextAsync();

            results.AddRange([.. response]);
        }

        return results;
    }

    public async Task UpdateItemAsync(string id, T item)
    {
        await this.Container.UpsertItemAsync<T>(item, new PartitionKey(id));
    }
}



METHOD SOFTWARE ©©