Uniphar.Cosmos.Extensions
4.4.1
See the version list below for details.
dotnet add package Uniphar.Cosmos.Extensions --version 4.4.1
NuGet\Install-Package Uniphar.Cosmos.Extensions -Version 4.4.1
<PackageReference Include="Uniphar.Cosmos.Extensions" Version="4.4.1" />
<PackageVersion Include="Uniphar.Cosmos.Extensions" Version="4.4.1" />
<PackageReference Include="Uniphar.Cosmos.Extensions" />
paket add Uniphar.Cosmos.Extensions --version 4.4.1
#r "nuget: Uniphar.Cosmos.Extensions, 4.4.1"
#addin nuget:?package=Uniphar.Cosmos.Extensions&version=4.4.1
#tool nuget:?package=Uniphar.Cosmos.Extensions&version=4.4.1
cosmos-extensions
NuGet package repository for Cosmos Extensions
Purpose
This library is intended for provisioning Az Cosmos Database(s) and container(s).
It also updates TTL and indexing policy for existing containers.
Setup your project to use Cosmos Extension package
When using this NuGet package you need to setup a few things in your project
appsettings.json
Add this to structure to your appsettings.json
with the appropriate values needed in your solution.
Note that this contains examples from PIMS API. They are here to illustrate example values.
"StoreOptions": {
"DatabaseName": "pims-api",
"DatabaseThroughput": <provisioned database throughput in RUs>,
"Containers": [
{
"InstanceName": "responsePayloadContainer",
"PartitionKey": "/partition",
"DefaultTimeToLive": "128.0:0:0.0"
},
{
"InstanceName": "auditContainer",
"PartitionKey": "/partition",
"IncludedPaths": [
{
"Path": "/myProperty/*"
}
]
"ExcludedPaths": [
{
"Path": "/*"
}
]
},
{
"InstanceName": "sequenceContainer",
"PartitionKey": "/id",
"IndexingMode": "None"
},
//...more containers to be defined with potential settings
{
"InstanceName": "<name of container>",
"PartitionKey": "<name of partition key>",
"ContainerThroughput": <provisioned database throughput in RUs>,
"DefaultTimeToLive" :"128.0:0:0.0"
"IndexingMode": "<indexing mode value>"
"CompositeIndexes": [
{
"Paths": [
{
"Path": "/path1",
"Order": "Ascending"
},
{
"Path": "/path2",
"Order": "Ascending"
}
]
}
]
}
]
}
NOTE 1: The
PartitionKeyPath
(unless it is also "/id") is not indexed and should be included in the index.
NOTE 2: The
PartitionKey
should always be specified in the request options object in Linux/MacOS clients
NOTE 3: Worth noting on the settings.
DatabaseName
: Name of the database to be checked/created. Mandatory.DatabaseThroughput
: integer, if undefined (null) it will default to 400; it will provision database with auto scaling as Manual throughput has been dismissed.Containers:InstanceName
: string, name of container. Mandatory.Containers:PartitionKey
: string, if undefined (null), it will default to partitioning by/partition
Be aware that partitionKey in appsettings will need to define a name preceded with a forwards slashContainers:ContainerThroughput
: integer, if undefined (null) it will default to 400DefaultTimeToLiveAsTimeSpan
: Optional TimeSpan defining for how long data should be retained; if undefined (null) we implement it to default to -1 (items don’t expire by default). The example shows TTL defined as 128 days, zero days, zero minutes and zero secondsIndexingMode
: Optional If undefined (null), it will default toIndexingMode.Consistent
. If required, then use one of these enumerated values (with capitalization!!!):None
,Lazy
,Consistent
.CompositeIndexes
: Optional The set of composite indexes to add to the parent container.
Range Indexes
https://learn.microsoft.com/en-us/azure/cosmos-db/index-policy
TLDR;
/*
must be inIncludedPaths
orExcludedPaths
to enable range indexes.- The path must end with
?
,[]
, or*
to enable range indexes.?
- Single value[]
- Array. Numbers are also supported to index a specific array element.my-array/1/my-property/?
*
- Anything
Composite Indexes
Property | Description |
---|---|
Path | The full path in a document used for composite indexing |
Order | The sort order for the composite path. Can be ascending or descending |
See here for more details about composite indexes.
Program.cs
Add the following to Program.cs
- Add this to bind the above configuration section to class
StoreOptions
. That will ensure we can DI it into the where ever we need to make the call.
builder.Services.Configure<StoreOptions>(
builder.Configuration.GetSection(nameof(StoreOptions)));
- Register a singleton instance of a
CosmosExtension
builder.Services.AddSingleton<CosmosExtension>();
- Register a singleton instance of
CosmosClient
(MS recommendation) by adding the following lines:
// System.Text.Json with JsonStringEnumConverter
var cosmosClientOptions = new CosmosClientOptions().DefaultOptions();
// Register the client
var connectionString = builder.Configuration["Cosmos:ConnectionString"]!;
var cosmosClient = new CosmosClient(connectionString, cosmosClientOptions);
builder.Services.AddSingleton(cosmosClient);
NOTE: Cosmos Client ConnectionString is defined in KeyVault.
CosmosInitialiser.cs (or other file responsible of Cosmos Initialization)
Whatever file responsible for initializing cosmos database and containers (called from StartupBackgroundService.cs
) has a method ExecuteAsync(CancellationToken stoppingToken)
.
That method can be simplified to this
public async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Creating Cosmos Database And Containers");
await _cosmosExtension.ExecuteAsync(stoppingToken);
}
Create extended class of StoreOptions
Some APIs may have additional logic that is specific to the solutions. You can then create a class extension that inherits from StoreOptions
.
This is particular valid for PIMS API. You would create something like this.
public class ExtendedStoreOptions : StoreOptions
{
/// <summary>
/// Disable the account processing check
/// </summary>
/// <remarks>
/// If set to true all account processing checks will return true
/// Used to disable routing of requests to legacy pims system
/// </remarks>
public bool DisableAccountCheck { get; set; } = false;
}
Your appsettings.json
would look like this then (based on PIMS API as an example)
"ExtendedStoreOptions": {
"DatabaseName": "<name of database>",
"DatabaseThroughput": <provisioned database throughput in RUs>,
"DisableAccountCheck": true, // < --- this is the extra field from the above example
"Containers": [
{
"InstanceName": "<name of container>",
"PartitionKey": "<name of partition key>",
"ContainerThroughput": <provisioned database throughput in RUs>,
"DefaultTimeToLiveInSeconds" : "128.0:0:0.0"
},
//...more containers to be defined
]
}
Your program.cs would then need to bind the config section like this
builder.Services.Configure<ExtendedStoreOptions>(
builder.Configuration.GetSection(nameof(ExtendedStoreOptions)));
Likewise you;ll need to update Store.cs
to reflect using ExtendedStoreOptions
instead.
Cosmos Repository
ICosmosRepository<T>
is a wrapper around Container
which handles exception handling, telemetry, and utility methods.
Also, there is no need to specify the type anymore on each method.
The below code register CosmosClient
, and ICosmosRepository<T>
as singletons:
// Program.cs
var connectionString = builder.Configuration["Cosmos:ConnectionString"]!;
var databaseId = builder.Configuration["StoreOptions:DatabaseName"]!;
builder.AddCosmos(connectionString, databaseId)
.AddRepository<EntityType1>("myEntityContainer1")
.AddRepository<EntityType2>("myEntityContainer2")
TTelemetry
has to extendIBaseTelemetry
.
To use, just inject ICosmosRepository<T>
into your class:
public class MyService(
ICosmosRepository<MyEntity> entityRepository)
{
}
Handled exception status codes
When the following exceptions are thrown, the methods returns null
.
Methods | Status Code |
---|---|
CreateItemAsync |
Conflict |
ReadItemAsync |
NotFound |
ReplaceItemAsync |
NotFound |
PatchItemAsync |
NotFound |
DeleteItemAsync |
NotFound |
Queries
There are a couple of helper methods to enumerate Cosmos
queries from FeedIterator<T>
:
ToListAsync(cancellationToken)
ToAsyncEnumerable(cancellationToken)
FirstOrDefaultAsync(cancellationToken)
Telemetry
- Each method sends a
CosmosDbMetrics
that logs RU usage and other metrics. - On exception, it sends a
UnsuccessfulCosmosRequestEvent
.
It is possible to disable telemetry at:
- Globally: in
AddCosmos
. - Repository level: in
AddRepository
. - In each method.
Keyed Repository
If two or more repositories use the same object type, it is possible to use a keyed repository.
// Program.cs
.AddRepository<Entity>("rightEntity", serviceKey: "right")
.AddRepository<Entity>("leftEntity", serviceKey: "left")
// Service.cs
[FromKeyedServices("right")] ICosmosRepository<Entity> rightRepository,
Cosmos Exception Handler
There is a global exception handler to log CosmosException
methods. It is registered automatically with AddCosmos
.
To register it manually:
builder.Services.AddSingleton<IExceptionHandler, CosmosExceptionHandler>(provider =>
{
var telemetry = provider.GetRequiredService<ExampleServiceTelemetry>();
return new CosmosExceptionHandler(telemetry!);
});
Cosmos Mutex
The CosmosMutex
class is an implementation of a simple distributed mutex. The CosmosMutex
utilizes a Cosmos container as a backing durable store for a give mutex state.
Initialization
An instance of a CosmosMutex
must be initialized before it can be used by an application. This initialization can be performed during startup.
To initialize a CosmosMutex
invoke the InitializeAsync
during the startup initialization of the application.
The InitializeAsync
method requires the following parameters:
- mutexInstance
- The name of the mutex that is being acquired
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger!.LogInformation("Creating Cosmos Database And Containers");
// Supply the mutex instance name to the initialize method
await _mutex.InitializeAsync(MutexName);
_logger!.LogInformation("Health Check Startup Completed");
_healthCheck!.StartupCompleted = true;
}
Acquire
In order to access some distributed data in an exclusive access context a named CosmosMutex
must be acquired by a process.
The AcquireAsync
method requires the following parameters:
- Owner
- The Owner name of the process attempting to acquire the mutex instance
- mutexInstance
- The name of the mutex that is being acquired
- leasExpiry
- The maximum length of time the mutex can be held. An application must allow for enough time to complete its exclusive processing
Note: The mutex is released after the leaseExpiry time has elapsed.
// Attempt to acquire the mutex supplying the machine name as the acquiring owner of the mutex
if (await _mutex.AcquireAsync(Environment.MachineName, MutexName, _mutexLeaseTime))
{
// Perform execution in a mutually exclusive context
await ProcessAsync(cancellationToken);
// Release the mutex
await _mutex.ReleaseAsync(Environment.MachineName, MutexName, cancellationToken);
}
Release
After a process has completed executing its mutually exclusive operation an acquired CosmosMutex
must be released.
The ReleaseAsync
method requires the following parameters:
- owner
- The Owner name of the process attempting to acquire the mutex instance
- mutexInstance
- The name of the mutex that is being acquired
{
// Release the mutex
await _mutex.ReleaseAsync(Environment.MachineName, MutexName, cancellationToken);
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.ApplicationInsights (>= 2.23.0)
- Microsoft.Azure.Cosmos (>= 3.48.0)
- Newtonsoft.Json (>= 13.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated | |
---|---|---|---|
4.10.0 | 993 | 4/23/2025 | |
4.9.0 | 379 | 4/17/2025 | |
4.8.0 | 206 | 4/17/2025 | |
4.7.0 | 355 | 4/15/2025 | |
4.6.0 | 267 | 4/11/2025 | |
4.5.0 | 160 | 4/11/2025 | |
4.4.1 | 291 | 4/9/2025 | |
4.4.0 | 225 | 4/9/2025 | |
4.3.0 | 220 | 4/8/2025 | |
4.2.0 | 175 | 4/7/2025 | |
4.1.0 | 147 | 4/4/2025 | |
4.0.0 | 210 | 4/2/2025 | |
3.8.0 | 750 | 4/1/2025 | |
3.7.0 | 823 | 3/20/2025 | |
3.6.1 | 597 | 3/12/2025 | |
3.6.0 | 232 | 3/11/2025 | |
3.5.0 | 271 | 3/10/2025 | |
3.4.0 | 1,162 | 3/6/2025 | |
3.3.0 | 926 | 2/24/2025 | |
3.2.0 | 226 | 2/20/2025 | |
3.1.0 | 483 | 2/14/2025 | |
3.0.1 | 1,370 | 12/11/2024 | |
3.0.0 | 105 | 12/6/2024 | |
2.3.0 | 2,799 | 10/24/2024 | |
2.2.0 | 126 | 10/24/2024 | |
2.1.0 | 1,314 | 7/30/2024 | |
2.0.1 | 933 | 5/16/2024 | |
2.0.0 | 84 | 5/14/2024 | |
1.1.1 | 560 | 4/22/2024 | |
1.1.0 | 301 | 4/10/2024 | |
1.0.0 | 229 | 4/8/2024 | |
0.0.4 | 220 | 3/29/2024 | |
0.0.3 | 225 | 3/27/2024 | |
0.0.2 | 142 | 3/27/2024 | |
0.0.1 | 149 | 3/26/2024 |