Documentation Index Fetch the complete documentation index at: https://mintlify.com/IntentArchitect/Intent.Modules.NET/llms.txt
Use this file to discover all available pages before exploring further.
The Intent.CosmosDB module provides complete Azure Cosmos DB integration, generating repositories, documents, and configuration for NoSQL document-based persistence.
Overview
This module generates:
Cosmos DB document classes
Repository implementations
Unit of Work pattern
Container configuration
Multi-tenancy support
Optimistic concurrency control
Cosmos DB client setup
Installation
Key Features
Document-based storage - JSON document persistence
Partitioning support - Horizontal scaling via partition keys
Global distribution - Multi-region replication
Automatic indexing - Query optimization
Change feed - Real-time event processing
Multi-tenancy - Tenant isolation
Configuration
Connection Settings
{
"CosmosDb" : {
"ConnectionString" : "AccountEndpoint=https://your-account.documents.azure.com:443/;AccountKey=your-key==" ,
"DatabaseName" : "MyApplication" ,
"Containers" : {
"Customers" : {
"ContainerName" : "Customers" ,
"PartitionKey" : "/tenantId" ,
"Throughput" : 400
},
"Orders" : {
"ContainerName" : "Orders" ,
"PartitionKey" : "/customerId" ,
"Throughput" : 400
}
}
}
}
Managed Identity (Recommended)
{
"CosmosDb" : {
"AccountEndpoint" : "https://your-account.documents.azure.com:443/" ,
"DatabaseName" : "MyApplication" ,
"UseManagedIdentity" : true
}
}
Module Settings
Use Optimistic Concurrency
Ensures updates are applied only when document ETags match, for improved concurrency management. Prevents lost updates when multiple clients modify the same document. Default: true
Enables a convention to convert enums to/from strings. Benefits:
More readable JSON
Better compatibility with other systems
Easier debugging
Default: false
Specify which authentication methods to use:
Key-based - Connection string with account key
Managed Identity - Azure Managed Identity (recommended for production)
Default: key-based
Document Generation
Domain Entity to Document
public class CustomerDocument : ICosmosDBDocument < Customer , CustomerDocument >
{
[ JsonProperty ( "id" )]
public string Id { get ; set ; }
[ JsonProperty ( "tenantId" )]
public string TenantId { get ; set ; }
[ JsonProperty ( "name" )]
public string Name { get ; set ; }
[ JsonProperty ( "email" )]
public string Email { get ; set ; }
[ JsonProperty ( "isVIP" )]
public bool IsVIP { get ; set ; }
[ JsonProperty ( "createdDate" )]
public DateTime CreatedDate { get ; set ; }
[ JsonProperty ( "_etag" )]
public string ETag { get ; set ; }
public Customer ToEntity ()
{
return new Customer
{
Id = Guid . Parse ( Id ),
Name = Name ,
Email = Email ,
IsVIP = IsVIP ,
CreatedDate = CreatedDate
};
}
public static CustomerDocument FromEntity ( Customer entity )
{
return new CustomerDocument
{
Id = entity . Id . ToString (),
Name = entity . Name ,
Email = entity . Email ,
IsVIP = entity . IsVIP ,
CreatedDate = entity . CreatedDate
};
}
}
Complex Documents
public class OrderDocument : ICosmosDBDocument < Order , OrderDocument >
{
[ JsonProperty ( "id" )]
public string Id { get ; set ; }
[ JsonProperty ( "customerId" )]
public string CustomerId { get ; set ; }
[ JsonProperty ( "orderNumber" )]
public string OrderNumber { get ; set ; }
[ JsonProperty ( "items" )]
public List < OrderItemDocument > Items { get ; set ; }
[ JsonProperty ( "shippingAddress" )]
public AddressDocument ShippingAddress { get ; set ; }
[ JsonProperty ( "status" )]
public string Status { get ; set ; }
[ JsonProperty ( "total" )]
public decimal Total { get ; set ; }
[ JsonProperty ( "orderDate" )]
public DateTime OrderDate { get ; set ; }
[ JsonProperty ( "_etag" )]
public string ETag { get ; set ; }
public Order ToEntity ()
{
var order = new Order
{
Id = Guid . Parse ( Id ),
CustomerId = Guid . Parse ( CustomerId ),
OrderNumber = OrderNumber ,
Status = Enum . Parse < OrderStatus >( Status ),
Total = Total ,
OrderDate = OrderDate
};
foreach ( var itemDoc in Items )
{
order . Items . Add ( itemDoc . ToEntity ());
}
order . ShippingAddress = ShippingAddress . ToEntity ();
return order ;
}
}
public class OrderItemDocument
{
[ JsonProperty ( "productId" )]
public string ProductId { get ; set ; }
[ JsonProperty ( "productName" )]
public string ProductName { get ; set ; }
[ JsonProperty ( "quantity" )]
public int Quantity { get ; set ; }
[ JsonProperty ( "price" )]
public decimal Price { get ; set ; }
public OrderItem ToEntity ()
{
return new OrderItem
{
ProductId = Guid . Parse ( ProductId ),
ProductName = ProductName ,
Quantity = Quantity ,
Price = Price
};
}
}
Repository Implementation
Base Repository
public abstract class CosmosDBRepositoryBase < TDomain , TDocument , TDocumentInterface >
where TDocument : TDocumentInterface
where TDocumentInterface : ICosmosDBDocument < TDomain , TDocument >
{
protected readonly Container _container ;
protected readonly ICosmosDBUnitOfWork _unitOfWork ;
protected CosmosDBRepositoryBase (
Container container ,
ICosmosDBUnitOfWork unitOfWork )
{
_container = container ;
_unitOfWork = unitOfWork ;
}
public ICosmosDBUnitOfWork UnitOfWork => _unitOfWork ;
public virtual void Add ( TDomain entity )
{
var document = TDocumentInterface . FromEntity ( entity );
_unitOfWork . TrackForCreate ( document , _container );
}
public virtual void Update ( TDomain entity )
{
var document = TDocumentInterface . FromEntity ( entity );
_unitOfWork . TrackForUpdate ( document , _container );
}
public virtual void Remove ( TDomain entity )
{
var document = TDocumentInterface . FromEntity ( entity );
_unitOfWork . TrackForDelete ( document , _container );
}
public virtual async Task < TDomain ?> FindByIdAsync (
string id ,
string partitionKey ,
CancellationToken cancellationToken = default )
{
try
{
var response = await _container . ReadItemAsync < TDocument >(
id ,
new PartitionKey ( partitionKey ),
cancellationToken : cancellationToken );
return response . Resource . ToEntity ();
}
catch ( CosmosException ex ) when ( ex . StatusCode == HttpStatusCode . NotFound )
{
return default ;
}
}
public virtual async Task < List < TDomain >> FindAllAsync (
CancellationToken cancellationToken = default )
{
var query = _container . GetItemQueryIterator < TDocument >();
var results = new List < TDomain >();
while ( query . HasMoreResults )
{
var response = await query . ReadNextAsync ( cancellationToken );
results . AddRange ( response . Select ( doc => doc . ToEntity ()));
}
return results ;
}
public virtual async Task < List < TDomain >> QueryAsync (
QueryDefinition queryDefinition ,
CancellationToken cancellationToken = default )
{
var query = _container . GetItemQueryIterator < TDocument >( queryDefinition );
var results = new List < TDomain >();
while ( query . HasMoreResults )
{
var response = await query . ReadNextAsync ( cancellationToken );
results . AddRange ( response . Select ( doc => doc . ToEntity ()));
}
return results ;
}
}
Entity Repository
public interface ICustomerRepository : ICosmosDBRepository < Customer >
{
Task < Customer ?> FindByIdAsync ( Guid id , CancellationToken cancellationToken = default );
Task < Customer ?> FindByEmailAsync ( string email , CancellationToken cancellationToken = default );
Task < List < Customer >> FindVIPCustomersAsync ( CancellationToken cancellationToken = default );
}
public class CustomerRepository : CosmosDBRepositoryBase < Customer , CustomerDocument , ICustomerDocument >, ICustomerRepository
{
public CustomerRepository (
Container container ,
ICosmosDBUnitOfWork unitOfWork )
: base ( container , unitOfWork )
{
}
public async Task < Customer ?> FindByIdAsync (
Guid id ,
CancellationToken cancellationToken = default )
{
return await FindByIdAsync (
id . ToString (),
id . ToString (), // Assuming partition key is the id
cancellationToken );
}
public async Task < Customer ?> FindByEmailAsync (
string email ,
CancellationToken cancellationToken = default )
{
var queryDefinition = new QueryDefinition (
"SELECT * FROM c WHERE c.email = @email" )
. WithParameter ( "@email" , email );
var results = await QueryAsync ( queryDefinition , cancellationToken );
return results . FirstOrDefault ();
}
public async Task < List < Customer >> FindVIPCustomersAsync (
CancellationToken cancellationToken = default )
{
var queryDefinition = new QueryDefinition (
"SELECT * FROM c WHERE c.isVIP = @isVIP" )
. WithParameter ( "@isVIP" , true );
return await QueryAsync ( queryDefinition , cancellationToken );
}
}
Usage Examples
Basic CRUD
public class CustomerService
{
private readonly ICustomerRepository _repository ;
public async Task < Customer > CreateCustomerAsync (
string name ,
string email )
{
var customer = new Customer ( name , email );
_repository . Add ( customer );
await _repository . UnitOfWork . SaveChangesAsync ();
return customer ;
}
public async Task < Customer ?> GetCustomerAsync ( Guid id )
{
return await _repository . FindByIdAsync ( id );
}
public async Task UpdateCustomerAsync ( Guid id , string name )
{
var customer = await _repository . FindByIdAsync ( id );
if ( customer != null )
{
customer . UpdateName ( name );
_repository . Update ( customer );
await _repository . UnitOfWork . SaveChangesAsync ();
}
}
public async Task DeleteCustomerAsync ( Guid id )
{
var customer = await _repository . FindByIdAsync ( id );
if ( customer != null )
{
_repository . Remove ( customer );
await _repository . UnitOfWork . SaveChangesAsync ();
}
}
}
Advanced Queries
// Query with parameters
var queryDef = new QueryDefinition (
"SELECT * FROM c WHERE c.createdDate >= @startDate AND c.createdDate <= @endDate" )
. WithParameter ( "@startDate" , startDate )
. WithParameter ( "@endDate" , endDate );
var customers = await _repository . QueryAsync ( queryDef );
// Query with pagination
var queryOptions = new QueryRequestOptions
{
MaxItemCount = 20 // Page size
};
var query = _container . GetItemQueryIterator < CustomerDocument >(
queryDef ,
requestOptions : queryOptions );
var page = await query . ReadNextAsync ();
var continuationToken = page . ContinuationToken ; // For next page
Cross-Partition Queries
var queryDefinition = new QueryDefinition (
"SELECT * FROM c WHERE c.isVIP = @isVIP" )
. WithParameter ( "@isVIP" , true );
var queryOptions = new QueryRequestOptions
{
MaxItemCount = 100 ,
MaxConcurrency = - 1 // Unlimited parallelism
};
var query = _container . GetItemQueryIterator < CustomerDocument >(
queryDefinition ,
requestOptions : queryOptions );
var allResults = new List < Customer >();
while ( query . HasMoreResults )
{
var response = await query . ReadNextAsync ();
allResults . AddRange ( response . Select ( doc => doc . ToEntity ()));
}
Partitioning
Partition Key Design
// Good partition keys:
// - TenantId (for multi-tenant apps)
// - UserId (for user-specific data)
// - Date (for time-series data)
// - CustomerId (for customer data)
public class OrderDocument
{
[ JsonProperty ( "id" )]
public string Id { get ; set ; }
[ JsonProperty ( "customerId" )] // Partition key
public string CustomerId { get ; set ; }
// Other properties...
}
// Container configuration
var containerProperties = new ContainerProperties
{
Id = "Orders" ,
PartitionKeyPath = "/customerId"
};
Multi-Tenancy
public class TenantDocument
{
[ JsonProperty ( "id" )]
public string Id { get ; set ; }
[ JsonProperty ( "tenantId" )] // Partition key
public string TenantId { get ; set ; }
[ JsonProperty ( "data" )]
public string Data { get ; set ; }
}
// Query within tenant
var queryDef = new QueryDefinition (
"SELECT * FROM c WHERE c.tenantId = @tenantId" )
. WithParameter ( "@tenantId" , currentTenantId );
var queryOptions = new QueryRequestOptions
{
PartitionKey = new PartitionKey ( currentTenantId )
};
Optimistic Concurrency
public async Task UpdateWithConcurrencyAsync ( Customer customer )
{
var document = CustomerDocument . FromEntity ( customer );
var requestOptions = new ItemRequestOptions
{
IfMatchEtag = document . ETag // Only update if ETag matches
};
try
{
await _container . ReplaceItemAsync (
document ,
document . Id ,
new PartitionKey ( document . TenantId ),
requestOptions );
}
catch ( CosmosException ex ) when ( ex . StatusCode == HttpStatusCode . PreconditionFailed )
{
throw new ConcurrencyException (
"The document was modified by another process" );
}
}
Indexing Configure indexes for frequently queried properties to improve performance.
Partition Strategy Choose partition keys that distribute load evenly across physical partitions.
Query Optimization Use SELECT with specific fields instead of SELECT * to reduce RU consumption.
Caching Cache frequently accessed documents to reduce Cosmos DB calls.
Request Units (RU)
var response = await _container . ReadItemAsync < CustomerDocument >(
id ,
new PartitionKey ( partitionKey ));
var requestCharge = response . RequestCharge ;
_logger . LogInformation ( "Request consumed {RequestCharge} RUs" , requestCharge );
Change Feed
var changeFeedProcessor = _container
. GetChangeFeedProcessorBuilder < CustomerDocument >(
"customerProcessor" ,
HandleChangesAsync )
. WithInstanceName ( "consoleHost" )
. WithLeaseContainer ( _leaseContainer )
. Build ();
await changeFeedProcessor . StartAsync ();
async Task HandleChangesAsync (
IReadOnlyCollection < CustomerDocument > changes ,
CancellationToken cancellationToken )
{
foreach ( var document in changes )
{
_logger . LogInformation (
"Customer changed: {CustomerId}" ,
document . Id );
// Process change
await ProcessCustomerChangeAsync ( document , cancellationToken );
}
}
Best Practices
Design for scale - Choose partition keys that distribute data evenly
Minimize cross-partition queries - They consume more RUs
Use point reads - Most efficient way to read documents
Implement retry logic - Handle rate limiting (429 status)
Monitor RU consumption - Optimize queries based on RU usage
Use bulk operations - For high-volume data operations
Additional Resources