3 min read
Working with Azure Cosmos DB SDK v3 for .NET
Azure Cosmos DB continues to be a popular choice for globally distributed applications. The .NET SDK v3, released last year, brought significant improvements in performance and usability. Let me share some patterns I have been using.
Setting Up the SDK
dotnet add package Microsoft.Azure.Cosmos
Creating the Cosmos Client
The SDK v3 uses a simplified client model:
using Microsoft.Azure.Cosmos;
public class CosmosService
{
private readonly CosmosClient _cosmosClient;
private readonly Container _container;
public CosmosService(string connectionString)
{
var options = new CosmosClientOptions
{
SerializerOptions = new CosmosSerializationOptions
{
PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
},
ConnectionMode = ConnectionMode.Direct
};
_cosmosClient = new CosmosClient(connectionString, options);
_container = _cosmosClient.GetContainer("MyDatabase", "MyContainer");
}
}
CRUD Operations
Here is a complete example of basic operations:
public class Product
{
public string Id { get; set; }
public string Category { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class ProductRepository
{
private readonly Container _container;
public ProductRepository(Container container)
{
_container = container;
}
// Create
public async Task<Product> CreateAsync(Product product)
{
product.Id = Guid.NewGuid().ToString();
var response = await _container.CreateItemAsync(
product,
new PartitionKey(product.Category));
return response.Resource;
}
// Read
public async Task<Product> GetAsync(string id, string category)
{
try
{
var response = await _container.ReadItemAsync<Product>(
id,
new PartitionKey(category));
return response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
}
// Update
public async Task<Product> UpdateAsync(Product product)
{
var response = await _container.UpsertItemAsync(
product,
new PartitionKey(product.Category));
return response.Resource;
}
// Delete
public async Task DeleteAsync(string id, string category)
{
await _container.DeleteItemAsync<Product>(
id,
new PartitionKey(category));
}
}
Querying with LINQ
SDK v3 has excellent LINQ support:
public async Task<List<Product>> GetProductsByCategoryAsync(string category)
{
var query = _container.GetItemLinqQueryable<Product>()
.Where(p => p.Category == category && p.Price > 10)
.OrderBy(p => p.Name)
.ToFeedIterator();
var results = new List<Product>();
while (query.HasMoreResults)
{
var response = await query.ReadNextAsync();
results.AddRange(response);
}
return results;
}
Using SQL Queries
For complex queries, you can use SQL directly:
public async Task<List<Product>> SearchProductsAsync(string searchTerm)
{
var queryDefinition = new QueryDefinition(
"SELECT * FROM c WHERE CONTAINS(c.name, @searchTerm)")
.WithParameter("@searchTerm", searchTerm);
var query = _container.GetItemQueryIterator<Product>(queryDefinition);
var results = new List<Product>();
while (query.HasMoreResults)
{
var response = await query.ReadNextAsync();
results.AddRange(response);
}
return results;
}
Batch Operations
For better performance with multiple operations:
public async Task CreateBatchAsync(List<Product> products, string category)
{
var batch = _container.CreateTransactionalBatch(new PartitionKey(category));
foreach (var product in products)
{
batch.CreateItem(product);
}
var response = await batch.ExecuteAsync();
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Batch operation failed: {response.StatusCode}");
}
}
Request Units Monitoring
Always monitor your RU consumption:
var response = await _container.CreateItemAsync(product, new PartitionKey(product.Category));
Console.WriteLine($"Request charge: {response.RequestCharge} RUs");
Best Practices
- Reuse the CosmosClient - It is thread-safe and expensive to create
- Choose the right partition key - This is crucial for performance and cost
- Use Direct mode - For better performance in production
- Enable Application Insights - For monitoring and diagnostics
Cosmos DB SDK v3 provides a robust foundation for building scalable applications with global distribution capabilities.