Benday.CosmosDb
6.0.10
dotnet add package Benday.CosmosDb --version 6.0.10
NuGet\Install-Package Benday.CosmosDb -Version 6.0.10
<PackageReference Include="Benday.CosmosDb" Version="6.0.10" />
<PackageVersion Include="Benday.CosmosDb" Version="6.0.10" />
<PackageReference Include="Benday.CosmosDb" />
paket add Benday.CosmosDb --version 6.0.10
#r "nuget: Benday.CosmosDb, 6.0.10"
#:package Benday.CosmosDb@6.0.10
#addin nuget:?package=Benday.CosmosDb&version=6.0.10
#tool nuget:?package=Benday.CosmosDb&version=6.0.10
Benday.CosmosDb
A collection of classes for implementing the domain model and repository patterns with Azure Cosmos DB. These classes are built using the Azure Cosmos DB libraries for .NET and aim to simplify using hierarchical partition keys and to make sure that query operations are created to use those partition keys correctly.
Written by Benjamin Day
Pluralsight Author | Microsoft MVP | Scrum.org Professional Scrum Trainer
https://www.benday.com
https://www.honestcheetah.com
info@benday.com
YouTube: https://www.youtube.com/@_benday
Key Features
- Interfaces and base classes for implementing the repository pattern with Cosmos DB
- Interfaces and base classes for implementing the domain model pattern with Cosmos DB
- Service layer abstractions (
ITenantItemService,IParentedItemService) - Support for parent-child entity relationships with
ParentedItemBaseandIParentedItem - Blob attachment support via
IBlobOwner-- connect Cosmos DB documents to files in Azure Blob Storage using Benday.BlobStorage - Help you to write LINQ queries against Cosmos DB without having to worry whether you're using the right partition keys
- Support for configuring repositories for use in ASP.NET Core projects
- Support for hierarchical partition keys
- Bulk operations with throttling and retry logic (
SaveAllAsync,DeleteAllByTenantIdAsync) - Paged query results with continuation tokens (
GetPagedAsync) - Shared interface contracts via
Benday.Common.Interfaces(IAsyncTenantRepository,IBlobOwner,IParentedItem) - Logging of query performance and request units with consolidated diagnostics helpers
- Detect and warn when you have cross-partition queries
- Structured diagnostics hook (
OnQueryDiagnostics) fires aCosmosQueryDiagnosticsevent for every point operation, feed response page, and query total — same payload shape regardless of whether the source is a LINQ query, raw Cosmos SQL (GetResultsAsync(QueryDefinition, ...)), or a scalar SDK operator (ExecuteScalarAsyncwrappingCountAsync,MaxAsync, etc.) - Pluggable
ICosmosQueryLogSinkfor app-wide diagnostics routing, with a built-inFileCosmosQueryLogSinkthat writes NDJSON - Opt-in capture of Cosmos DB index utilization metrics per entity type, surfaced through the same diagnostics pipeline
- Helper classes and methods for registering types and handling connection configuration
- Ultra-simple configuration for Azure Cosmos DB Linux emulator
- Optimistic concurrency control using ETags
Quick Start
For Azure Cosmos DB Emulator (Development)
{
"CosmosConfiguration": {
"UseEmulator": true
}
}
That's it! See EMULATOR-SETUP.md for complete emulator configuration guide.
For Production
Option 1: Using appsettings.json
{
"CosmosConfiguration": {
"DatabaseName": "ProductionDb",
"ContainerName": "ProductionContainer",
"CreateStructures": false,
"PartitionKey": "/tenantId,/entityType",
"HierarchicalPartitionKey": true,
"Endpoint": "https://your-cosmos.documents.azure.com:443/",
"UseDefaultAzureCredential": true
}
}
Option 2: Using CosmosConfigBuilder
var config = new CosmosConfigBuilder()
.WithEndpoint("https://your-cosmos.documents.azure.com:443/")
.UseDefaultAzureCredential()
.WithDatabase("ProductionDb")
.WithContainer("ProductionContainer")
.Build();
Quick Example
// Configure in Program.cs / Startup.cs
var cosmosConfig = builder.Configuration.GetCosmosConfig();
var cosmosBuilder = new CosmosRegistrationHelper(builder.Services, cosmosConfig);
// Register simple tenant item
cosmosBuilder.RegisterRepositoryAndService<Note>();
// Register parented item with parent-child relationships
cosmosBuilder.RegisterParentedRepositoryAndService<Comment>();
// Use in your services
public class CommentService
{
private readonly IParentedItemService<Comment> _commentService;
public CommentService(IParentedItemService<Comment> commentService)
{
_commentService = commentService;
}
public async Task<IEnumerable<Comment>> GetCommentsForNote(string tenantId, string noteId)
{
// Query comments by parent ID with entity type filtering
return await _commentService.GetAllByParentIdAsync(tenantId, noteId, "Note");
}
}
Custom Configuration Per Repository
You can register repositories with custom configuration values that override the defaults. This is useful when you need to store certain entity types in separate containers:
// Register LookupValue entities in a separate "LookupValues" container
cosmosBuilder.RegisterRepository<LookupValue, ILookupValueRepository, CosmosDbLookupValueRepository>(
containerName: "LookupValues",
withCreateStructures: true
);
Available configuration overrides:
connectionString- Use a different Cosmos DB endpointdatabaseName- Store in a different databasecontainerName- Store in a different containerpartitionKey- Use a different partition key pathuseHierarchicalPartitionKey- Override hierarchical partition key settinguseDefaultAzureCredential- Override authentication methodwithCreateStructures- Override auto-creation of database/container
Any parameter left as null will use the default value from the CosmosRegistrationHelper instance.
Blob Attachments with IBlobOwner and BlobBridge
Cosmos DB entities that inherit from TenantItemBase automatically implement IBlobOwner from Benday.Common.Interfaces. This means every entity can have file attachments stored in Azure Blob Storage via Benday.BlobStorage -- without adding any blob-specific code to the entity itself.
How It Works
TenantItemBase provides a default GetBlobPrefix() that organizes blobs by tenant and entity ID:
// TenantItemBase implements IBlobOwner with a default prefix
public abstract class TenantItemBase : CosmosIdentityBase, ITenantItem, IBlobOwner
{
public virtual string GetBlobPrefix()
{
return $"{TenantId}/{Id}/";
}
}
This means a Note entity with TenantId = "acme" and Id = "note-123" stores its blobs under the path acme/note-123/ in your blob container. You can override GetBlobPrefix() in your entity class for a different convention.
Setup
Add the Benday.BlobStorage and Benday.AzureStorage packages to your project:
dotnet add package Benday.AzureStorage --version 1.0.0-alpha
dotnet add package Benday.BlobStorage --version 1.0.0-alpha
Register Azure Storage services alongside your Cosmos DB services in Program.cs:
using Benday.CosmosDb.Utilities;
var cosmosConfig = builder.Configuration.GetCosmosConfig();
var cosmosBuilder = new CosmosRegistrationHelper(builder.Services, cosmosConfig);
// Register Cosmos DB repositories
cosmosBuilder.RegisterRepositoryAndService<Note>();
// Register Azure Storage services and a blob container
builder.Services.AddBendayAzureStorage(builder.Configuration);
builder.Services.AddBlobRepository("attachments");
Attaching Files to Cosmos DB Entities
Use BlobBridge<T> to manage file attachments for any entity that inherits from TenantItemBase:
using Benday.BlobStorage;
public class NoteAttachmentService
{
private readonly ITenantItemService<Note> _noteService;
private readonly BlobBridge<Note> _blobBridge;
public NoteAttachmentService(
ITenantItemService<Note> noteService,
IBlobRepository blobRepository)
{
_noteService = noteService;
_blobBridge = new BlobBridge<Note>(blobRepository);
}
// Upload a file attachment to a note
public async Task AttachFileAsync(string tenantId, string noteId, string filename, Stream content)
{
var note = await _noteService.GetByIdAsync(tenantId, noteId);
// Stores the blob at "{TenantId}/{Id}/{filename}"
// e.g., "acme/note-123/report.pdf"
await _blobBridge.AttachAsync(note, filename, content);
}
// List all attachments for a note
public async IAsyncEnumerable<string> ListAttachmentsAsync(Note note)
{
await foreach (var blob in _blobBridge.ListAttachmentsAsync(note))
{
yield return blob.Name;
}
}
// Download an attachment
public async Task<byte[]> DownloadAsync(Note note, string filename)
{
return await _blobBridge.DownloadAttachmentBytesAsync(note, filename);
}
// Get a time-limited SAS URL for downloading
public Uri GetDownloadUrl(Note note, string filename)
{
return _blobBridge.GetAttachmentSasUri(
note, filename,
expiry: TimeSpan.FromMinutes(15),
downloadFilename: filename);
}
// Delete all attachments when deleting a note
public async Task DeleteNoteWithAttachmentsAsync(string tenantId, string noteId)
{
var note = await _noteService.GetByIdAsync(tenantId, noteId);
// Delete blobs first, then the Cosmos DB document
await _blobBridge.DeleteAttachmentsAsync(note);
await _noteService.DeleteAsync(note);
}
}
Custom Blob Prefix
Override GetBlobPrefix() when you need a different blob path convention:
public class Invoice : TenantItemBase
{
public string InvoiceNumber { get; set; } = string.Empty;
protected override string GetEntityTypeName() => nameof(Invoice);
// Custom prefix: "acme/invoices/INV-2026-001/"
public override string GetBlobPrefix()
{
return $"{TenantId}/invoices/{InvoiceNumber}/";
}
}
Parent-Child Entities with Attachments
Parented entities also implement IBlobOwner since ParentedItemBase extends TenantItemBase. This lets you attach files to child entities with blob paths that naturally include the tenant context:
public class CommentAttachmentService
{
private readonly IParentedItemService<Comment> _commentService;
private readonly BlobBridge<Comment> _blobBridge;
public CommentAttachmentService(
IParentedItemService<Comment> commentService,
IBlobRepository blobRepository)
{
_commentService = commentService;
_blobBridge = new BlobBridge<Comment>(blobRepository);
}
public async Task AttachScreenshotAsync(Comment comment, Stream screenshot)
{
// Blob stored at "{TenantId}/{CommentId}/screenshot.png"
await _blobBridge.AttachAsync(comment, "screenshot.png", screenshot);
}
}
Bulk Operations
v6 adds throttled bulk operations with configurable concurrency and retry logic for handling Cosmos DB rate limiting (HTTP 429):
// Save many items with automatic throttling
await repository.SaveAllAsync(items);
// Customize concurrency and retries
await repository.SaveAllAsync(items, maxConcurrency: 10, maxRetries: 5);
// Delete all items for a tenant
await repository.DeleteAllByTenantIdAsync("acme");
Paged Queries
Retrieve large result sets efficiently with continuation tokens:
string? token = null;
do
{
var page = await repository.GetPagedAsync("acme", pageSize: 50, continuationToken: token);
foreach (var item in page.Items)
{
// Process each item
}
token = page.ContinuationToken;
} while (token != null);
Query Diagnostics
The library emits a CosmosQueryDiagnostics event for every point operation, every page of feed-iterator results, and the rolled-up total of each query. Events carry the SQL text, parameters, partition key, RU charge, duration, result count, and a cross-partition flag. There are two channels for receiving them — both fire for every event and they don't interfere with each other:
ICosmosQueryLogSink— an app-wide singleton that receives every event from every repository. Use this for structured log files, observability pipelines, or test capture.OnQueryDiagnostics(CosmosQueryDiagnostics)— a virtual hook onCosmosRepository<T>that you can override per-repository when one repo needs special handling.
File Log Sink
FileCosmosQueryLogSink ships with the library and writes one NDJSON record per event to a file via a background queue:
var helper = new CosmosRegistrationHelper(builder.Services, cosmosConfig);
builder.Services.Configure<CosmosFileLogSinkOptions>(options =>
{
options.FilePath = "logs/cosmos-queries.ndjson";
options.QueueCapacity = 100;
});
helper.WithQueryLogSink<FileCosmosQueryLogSink>();
To plug in your own sink, implement ICosmosQueryLogSink and pass it to helper.WithQueryLogSink<TSink>() (or helper.WithQueryLogSink(instance) for a pre-built instance).
Per-Entity Diagnostics Options
Some pieces of telemetry — like Cosmos DB's index utilization metrics — add measurable RU and latency overhead to every query, so they're off by default and configured per entity type:
// Capture index metrics only for one repository's entity type
helper.ConfigureDiagnostics<Note>(o => o.CaptureIndexMetrics = true);
// Or turn it on globally and selectively disable for hot-path entities
helper.ConfigureDiagnosticsDefault(o => o.CaptureIndexMetrics = true);
helper.ConfigureDiagnostics<LookupValue>(o => o.CaptureIndexMetrics = false);
When enabled, the repository sets PopulateIndexMetrics on every QueryRequestOptions it builds and copies the SDK-formatted metrics string into the IndexMetrics field of the diagnostics event — both per-page and on the rolled-up QueryTotal. The included FileCosmosQueryLogSink serializes this field as indexMetrics in the NDJSON output. Microsoft recommends only enabling index metrics while debugging slow queries, not in production. A common pattern is to gate it on the environment:
if (builder.Environment.IsDevelopment())
{
helper.ConfigureDiagnosticsDefault(o => o.CaptureIndexMetrics = true);
}
The included sample application uses exactly this pattern — see Benday.CosmosDb.SampleApp.WebUi/Program.cs.
Sample Application
A complete working sample application is included in this repository demonstrating all major features:
- Person Entity - Demonstrates
TenantItemBasewith custom repository and service layer implementations. Shows complex domain models with nested Address objects. - Note Entity - Simple
TenantItemBaseimplementation using default repository and service registrations. Serves as parent entity for Comments. - Comment Entity - Demonstrates
ParentedItemBasepattern showing parent-child relationships withParentIdandParentEntityTypefor type-safe queries. - LookupValue Entity - Demonstrates custom repository configuration to store entities in a separate Cosmos DB container using the
RegisterRepositoryoverload with configuration options.
To run the sample application:
- Start the Azure Cosmos DB Emulator (see EMULATOR-SETUP.md)
- Run
Benday.CosmosDb.SampleApp.WebUi - Explore the different entity patterns and their implementations
Upgrading from v5
See MIGRATION-v6.md for the complete migration guide. You can also use the migration guide as a prompt for AI coding agents (Claude Code, GitHub Copilot, etc.) to automate the code changes. Key changes:
OwnerIdrenamed toTenantId,DiscriminatorValuerenamed toEntityTypeIOwnedItem/OwnedItemBaserenamed toITenantItem/TenantItemBase- Default partition key path changed from
/pk,/discriminatorto/tenantId,/entityType - JSON serialization defaults to camelCase
- Use
cosmosmigrator migrateto migrate existing container data
Resources
Full Documentation
Sample Application - Working examples of all patterns
NuGet Package
Source Code
Repository API Documentation
Domain Model API Documentation
Feedback & Contributions
Got ideas for Cosmos DB functionality that you'd like to see? Found a bug? Let us know by submitting an issue. Want to contribute? Submit a pull request.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Azure.Identity (>= 1.21.0)
- Benday.Common (>= 9.12.0)
- Benday.Common.Interfaces (>= 1.0.1)
- Microsoft.Azure.Cosmos (>= 3.59.0)
- Microsoft.Extensions.Configuration (>= 10.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Options (>= 10.0.7)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Benday.CosmosDb:
| Package | Downloads |
|---|---|
|
Benday.Identity.CosmosDb
ASP.NET Core Identity implementation using Azure Cosmos DB as the backing store. Provides user store, role store, claims, lockout, two-factor authentication, and external login support. Built on top of the Benday.CosmosDb repository pattern library. |
|
|
Benday.Identity.CosmosDb.UI
ASP.NET Core Identity UI for Azure Cosmos DB. Provides pre-built Login/Logout/AccessDenied Razor Pages, a RedirectToLogin Blazor component, and AddCosmosIdentityWithUI() convenience method that combines core identity registration with cookie authentication. Built on top of Benday.Identity.CosmosDb. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.0.10 | 136 | 5/10/2026 |
| 6.0.9-alpha | 121 | 4/27/2026 |
| 6.0.8-alpha | 122 | 4/20/2026 |
| 6.0.7-alpha | 106 | 4/20/2026 |
| 6.0.3-alpha | 115 | 4/14/2026 |
| 6.0.2-alpha | 150 | 4/6/2026 |
| 6.0.0-alpha | 138 | 3/25/2026 |
| 5.3.0 | 166 | 3/12/2026 |
| 5.2.0 | 416 | 1/9/2026 |
| 5.1.0 | 319 | 12/16/2025 |
| 5.0.0 | 354 | 11/12/2025 |
| 4.10.0 | 252 | 11/6/2025 |
| 4.9.0 | 196 | 9/27/2025 |
| 4.8.0 | 390 | 8/8/2025 |
| 4.7.1 | 311 | 8/7/2025 |
| 4.6.1 | 268 | 6/14/2025 |
| 4.5.0 | 235 | 4/25/2025 |
| 4.4.0 | 231 | 3/22/2025 |
| 4.3.0 | 176 | 3/21/2025 |
| 4.2.2 | 184 | 3/21/2025 |
v6.0.10 - Added FileCosmosQueryLogSink, an ICosmosQueryLogSink implementation that appends each query diagnostics event as a single line of NDJSON to a file via a background queue (configurable file path and queue capacity through CosmosFileLogSinkOptions). Added per-entity diagnostics options via the new CosmosDiagnosticsRegistry singleton and CosmosRegistrationHelper.ConfigureDiagnostics<TEntity>() / ConfigureDiagnosticsDefault() fluent helpers; the first opt-in flag is CaptureIndexMetrics, which sets PopulateIndexMetrics on every QueryRequestOptions the repository builds and copies FeedResponse.IndexMetrics into the new CosmosQueryDiagnostics.IndexMetrics field on per-page and query-total events. Off by default — Microsoft recommends only enabling index metrics while debugging slow queries because of measurable RU/latency overhead. Source-level breaking change: CosmosRepository<T>, CosmosTenantItemRepository<T>, and CosmosDbParentedItemRepository<T> constructors gained an optional trailing CosmosDiagnosticsRegistry? diagnosticsRegistry = null parameter; derived classes that pass base(...) explicitly must forward it (mechanical one-line change). Also: changed some method signatures in CosmosRepository to use generics for flexibility to support situations where the return type of the repository doesn't match the required return type of a repository method;
v6.0.8-alpha - Fix: ExecuteScalarAsync no longer throws when the queryable has no LINQ operators applied (bare GetQueryContextAsync(...).Queryable). The query executes normally and diagnostics fire, with QueryText set to null if extraction fails. Fix: GetResultsAsync(IQueryable<T>, ...) defensively handles the same edge case. Not a breaking change — no public API surface changed; consumers who worked around the bug by chaining a redundant .Where(...) can remove the workaround;
v6.0.8-alpha - Added ICosmosQueryLogSink for app-wide diagnostics routing alongside the existing OnQueryDiagnostics template-method hook. Default NoOpCosmosQueryLogSink is registered via TryAddSingleton so existing consumers get identical runtime behavior. Custom sinks register via CosmosRegistrationHelper.WithQueryLogSink<TSink>() (or the instance overload). Source-level breaking change: CosmosRepository<T>, CosmosTenantItemRepository<T>, and CosmosDbParentedItemRepository<T> constructors gained an optional trailing ICosmosQueryLogSink? sink = null parameter; derived classes that pass base(...) explicitly must forward it (mechanical one-line change). Sink exceptions are caught, logged as ILogger warnings, and suppressed — a broken sink cannot break queries. OnQueryDiagnostics and all existing ILogger output are unchanged;
v6.1 - BREAKING (template methods only): Removed OnLogPointOperationDiagnostics and OnLogFeedResponseDiagnostics virtual hooks. Introduced CosmosQueryDiagnostics structured payload and the single OnQueryDiagnostics(CosmosQueryDiagnostics) hook that fires for point operations, feed response pages, and query totals — distinguished by CosmosQueryEventKind. LogPointOperationDiagnostics now takes a TimeSpan duration; LogFeedResponseDiagnostics and LogQueryTotalDiagnostics take duration, result count, query text, parameters, partition key, and cross-partition flag. Added ExecuteScalarAsync<TResult> helper so Cosmos SDK scalar LINQ operators (CountAsync, MaxAsync, etc.) flow through the library's diagnostics pipeline. Added GetResultsAsync(QueryDefinition, ...) overload for raw Cosmos SQL that emits the same diagnostics as the LINQ overload. ILogger output unchanged. Migrate overrides of the old hooks to OnQueryDiagnostics by switching on diagnostics.EventKind;
v6.0 - BREAKING: Renamed OwnerId to TenantId, DiscriminatorValue to EntityType, IOwnedItem to ITenantItem, OwnedItemBase to TenantItemBase, and all related types. Default partition key path changed from /pk,/discriminator to /tenantId,/entityType. JSON serialization defaults to camelCase. Added IBlobOwner support on TenantItemBase for blob attachments via Benday.BlobStorage. Added bulk SaveAllAsync and DeleteAllByTenantIdAsync with throttling and retry. Added paged queries with GetPagedAsync. Added shared interface contracts from Benday.Common.Interfaces. See MIGRATION-v6.md for upgrade guide;
v5.3 - Added some deprecation attributes to warn devs about some methods that ignore partition keys;
v5.2 - Added bulk delete support to repository;
v5.1 - Added per-repository custom container configuration support;
v5.0 - Adding IParentedItem interface and IParentedItemRepository interface plus CosmosDbParentedItemRepository to support items that have a parent-child relationship in CosmosDb;
v4.10 - Fixing bugs where etag and timestamp not getting updated on Save;
v4.9 - Added simplified config options for local emulator; Added configuration builder extension method to simplify configuration of cosmos db in web projects; Added better paging support to repository;
v4.8 - Refactored batch save to make the saving of each batch be a protected virtual method; Added batch size property;
v4.7 - Adding BeforeSaveBatch and AfterSaveBatch template methods;
v4.6 - Added configure option to use DefaultAzureCredential for authentication using managed service ids in azure; Fixed bug where cosmos client was improperly registered in DI when using managed ids;
v4.5 - Added option to configure 'allow bulk execution' for the CosmosClient; Default value for 'allow bulk execution' is now true;
v4.4 - Changed configuration reader to use default values rather than throwing exceptions when optional values are missing;
v4.3 - Fixed bug where UseHierarchicalPartitionKey was sometimes not being set;
v4.2.2 - Allowed cosmos db options UseHierarchicalPartitionKey to be set-able;
v4.2.1 - Minor bug fix release;
v4.2 - Fixed partition key bug on SaveAsync when in flat-partition key mode;
v4.1 - Added option to CosmosConfig.ConnectionString to enable GatewayMode via connection string;
v4.0 - Added support for non-hierarchical partition keys and made it the default; Added support for the beta version of the linux emulator container; Added configuration options for gateway mode and database throughput; Breaking change: renamed OwnedItemService interface and classes;
v3.0 - Changed framework target to be netstandard2.1; Added helper classes and methods to simplify type registrations;
v2.1 - Added optimistic concurrency checks using _etag to the repository SaveAsync method.
v2.0 - Changed implementation to use System.Text.Json for serialization instead of Newtonsoft.Json. Added configuration utilities to make it easier to configure CosmosDb in web projects. Added service layer base classes.
v1.0 - Adding initial version of the CosmosDb Domain Model & Repository utilities