Azure Cosmos DB Repository .NET SDK
This package wraps the NuGet: Microsoft.Azure.Cosmos package,
exposing a simple dependency-injection enabled IRepository<T>
interface.
The repository is responsible for all of the create, read, update, and delete (CRUD) operations on objects where T : Item
. The Item
type adds
several properties, one which is a globally unique identifier defined as:
[JsonProperty("id")]
public string Id { get; set; } = Guid.NewGuid().ToString();
Additionally, a type property exists which indicates the subclass name (this is used for filtering implicitly on your behalf):
[JsonProperty("type")]
public string Type { get; set; }
Finally, a partition key property is used internally to manage partitioning on your behalf. This can optionally be overridden on an item per item basis.
📣 Azure Cosmos DB - Official Blog
Getting started
-
Create an Azure Cosmos DB SQL resource.
-
Obtain the resource connection string from the Keys blade, be sure to get a connection string and not the key - these are different. The connection string is a compound key and endpoint URL.
-
Call
AddCosmosRepository
:public void ConfigureServices(IServiceCollection services) { services.AddCosmosRepository(); }
The optional
setupAction
allows consumers to manually configure theRepositoryOptions
object:public void ConfigureServices(IServiceCollection services) { services.AddCosmosRepository( options => { options.CosmosConnectionString = "< connection string >"; options.ContainerId = "data-store"; options.DatabaseId = "samples"; }); }
-
Define your object graph, objects must inherit
Item
, for example:using Microsoft.Azure.CosmosRepository; public class Person : Item { public string FirstName { get; set; } public string LastName { get; set; } }
-
Ask for an instance of
IRepository<TItem>
, in this case theTItem
isPerson
:using Microsoft.Azure.CosmosRepository; public class Consumer { readonly IRepository<Person> _repository; public Consumer(IRepository<Person> repository) => _repository = repository; // Use the repo... }
-
Perform any of the operations on the
_repository
instance, createPerson
records, update them, read them, or delete. -
Enjoy!
Configuration
When OptimizeBandwidth
is true
(its default value), the repository SDK reduces networking and
CPU load by not sending the resource back over the network and serializing it to the client. This is specific to writes,
such as create, update, and delete. For more information, see Optimizing bandwidth in the Azure Cosmos DB .NET SDK.
There is much debate with how to structure your database and corresponding containers. Many developers with relational
database design experience might prefer to have a single container per item type, while others understand that Azure Cosmos DB
will handle things correctly regardless. By default, the ContainerPerItemType
option is false
and
all items are persisted into the same container. However, when it is true
, each distinct subclass of
Item
gets its own container named by the class itself.
Well-known keys
Depending on the .NET configuration provider your app is using, there are several well-known keys that map to the repository options that configure your usage of the repository SDK. When using environment variables, such as those in Azure App Service configuration or Azure Key Vault secrets, the following keys map to the RepositoryOptions
instance:
Key | Data type | Default value |
---|---|---|
RepositoryOptions__CosmosConnectionString | string | null |
RepositoryOptions__AccountEndpoint | string | null |
RepositoryOptions__DatabaseId | string | "database" |
RepositoryOptions__ContainerId | string | "container" |
RepositoryOptions__OptimizeBandwidth | boolean | true |
RepositoryOptions__ContainerPerItemType | boolean | false |
RepositoryOptions__AllowBulkExecution | boolean | false |
RepositoryOptions__SerializationOptions__IgnoreNullValues | boolean | false |
RepositoryOptions__SerializationOptions__Indented | boolean | false |
RepositoryOptions__SerializationOptions__PropertyNamingPolicy | CosmosPropertyNamingPolicy | CosmosPropertyNamingPolicy.CamelCase |
appsettings.json
Example {
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"RepositoryOptions": {
"CosmosConnectionString": "<Your-CosmosDB-ConnectionString>",
"AccountEndpoint": "<Your-CosmosDB-URI>"
"DatabaseId": "<Your-CosmosDB-DatabaseName>",
"ContainerId": "<Your-CosmosDB-ContainerName>",
"OptimizeBandwidth": true,
"ContainerPerItemType": true,
"AllowBulkExecution": true,
"SerializationOptions": {
"IgnoreNullValues": true,
"PropertyNamingPolicy": "CamelCase"
}
}
}
For more information, see JSON configuration provider.
appsettings.json
with Azure Functions
Example {
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Values": {
"RepositoryOptions:CosmosConnectionString": "<Your-CosmosDB-ConnectionString>",
"RepositoryOptions:AccountEndpoint": "<Your-CosmosDB-URI>",
"RepositoryOptions:DatabaseId": "<Your-CosmosDB-DatabaseName>",
"RepositoryOptions:ContainerId": "<Your-CosmosDB-ContainerName>",
"RepositoryOptions:OptimizeBandwidth": true,
"RepositoryOptions:ContainerPerItemType": true,
"RepositoryOptions:AllowBulkExecution": true,
"RepositoryOptions:SerializationOptions:IgnoreNullValues": true,
"RepositoryOptions:SerializationOptions:PropertyNamingPolicy": "CamelCase"
}
}
For more information, see Customizing configuration sources.
Authenticating using an identity
The Azure Cosmos DB .NET SDK also supports authentication using identities, which are considered superior from an audit and granularity of permissions perspective. Authenticating using a connection string essentially provides full access to perform operations within the data plane of your Cosmos DB Account. More information on the Azure control plane and data plane is available here.
This libary also supports authentication using an identity. To authenticate using an identity (User, Group, Application Registration, or Managed Identity) you will need to set the AccountEndpoint
and TokenCredential
options that are available on the RepositoryOptions
class.
In a basic scenario, there are three steps that need to be completed:
1. If the idenditity that you would like to use, does not exist in Azure Active Directory, create it now.
1. Use the Azure CLI to assign the appropriate role to your identity at the desired scope.
- In most cases, using the built-in roles will be sufficient. However, there is support for creating custom role definitions using the Azure CLI, you can read more on this here.
1. Configure your application using the AddCosmosRepository
method in your Startup.cs
file:
```csharp
using Azure.Identity;
public void ConfigureServices(IServiceCollection services)
{
DefaultAzureCredential credential = new();
services.AddCosmosRepository(
options =>
{
options.TokenCredential = credential;
options.AccountEndpoint = "< account endpoint URI >";
options.ContainerId = "data-store";
options.DatabaseId = "samples";
});
}
```
The example above is using the DefaultAzureCredential
object provided by the Azure Identity NuGet package, which provides seamless integration with Azure Active Directory. More information on this package is available here.
Advanced partitioning strategy
As a consumer of Azure Cosmos DB, you can choose how to partition your data. By default, this repository SDK will partition items using their Item.Id
value as the /id
partition in the storage container. However, you can override this default behavior by:
- Declaratively specifying the partition key path with
PartitionKeyPathAttribute
- Override the
Item.GetPartitionKeyValue()
method - Ensure the the property value of the composite or synthetic key is serialized to match the partition key path
- Set
RepositoryOptions__ContainerPerItemType
totrue
, to ensure that your item with explicit partitioning is correctly maintained
As an example, considering the following:
using Microsoft.Azure.CosmosRepository;
using Microsoft.Azure.CosmosRepository.Attributes;
using Newtonsoft.Json;
using System;
namespace Example
{
[PartitionKeyPath("/synthetic")]
public class Person : Item
{
public string FirstName { get; set; } = null!;
public string? MiddleName { get; set; }
public string LastName { get; set; } = null!;
[JsonProperty("synthetic")]
public string SyntheticPartitionKey =>
$"{FirstName}-{LastName}"; // Also known as a "composite key".
protected override string GetPartitionKeyValue() => SyntheticPartitionKey;
}
}
In-memory Repository
This library also includes an in-memory version of IRepository<T>
. To use it swap out the normal
services.AddCosmosRepository()
for
services.AddInMemoryCosmosRepository()
and have all of your items stored in memory. This is a great tool for running integration tests using a package such as Microsoft.AspNetCore.Mvc.Testing
, and not having to incur the cost of data stored in an Azure Cosmos DB resource.
Samples
Visit the Microsoft.Azure.CosmosRepository.Samples
directory for samples on how to use the library with:
Deep-dive video
Discord
Get extra support on our dedicated Discord channel.
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!