|
| 1 | +# GitHub Copilot Instructions for Azure Cosmos DB .NET SDK v3 |
| 2 | + |
| 3 | +This repository contains the Azure Cosmos DB .NET SDK version 3, a comprehensive client library for interacting with Azure Cosmos DB for NoSQL. These instructions help GitHub Copilot provide better suggestions when working with this codebase. |
| 4 | + |
| 5 | +## Repository Structure |
| 6 | + |
| 7 | +- **`Microsoft.Azure.Cosmos/src/`** - Core SDK source code |
| 8 | +- **`Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/`** - Unit tests (no external dependencies) |
| 9 | +- **`Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/`** - Integration tests (require Cosmos DB Emulator) |
| 10 | +- **`Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/`** - Performance benchmark tests |
| 11 | +- **`Microsoft.Azure.Cosmos.Samples/`** - Sample applications and tools |
| 12 | +- **`Microsoft.Azure.Cosmos.Encryption/`** - Encryption functionality |
| 13 | +- **`Microsoft.Azure.Cosmos.Encryption.Custom/`** - Custom encryption providers |
| 14 | + |
| 15 | +## Core Architecture Patterns |
| 16 | + |
| 17 | +### Client Hierarchy |
| 18 | +```csharp |
| 19 | +CosmosClient -> Database -> Container -> Items/Scripts |
| 20 | +``` |
| 21 | + |
| 22 | +### Key Classes and Their Purposes |
| 23 | +- **`CosmosClient`**: Top-level client for account operations, thread-safe singleton |
| 24 | +- **`Database`**: Manages containers and users within a database |
| 25 | +- **`Container`**: Handles item operations, queries, and scripts |
| 26 | +- **`ItemResponse<T>`**: Wraps responses with metadata (status code, headers, diagnostics) |
| 27 | +- **`FeedResponse<T>`**: Handles paginated query results |
| 28 | +- **`TransactionalBatch`**: Groups operations for atomic execution |
| 29 | + |
| 30 | +### Resource Management Patterns |
| 31 | +```csharp |
| 32 | +// CosmosClient should be singleton and disposed at application exit |
| 33 | +using var cosmosClient = new CosmosClient(connectionString); |
| 34 | + |
| 35 | +// Use ConfigureAwait(false) for library code |
| 36 | +var response = await container.ReadItemAsync<T>(id, partitionKey).ConfigureAwait(false); |
| 37 | + |
| 38 | +// Always handle PartitionKey correctly |
| 39 | +var partitionKey = new PartitionKey(partitionKeyValue); |
| 40 | +``` |
| 41 | + |
| 42 | +## Coding Conventions |
| 43 | + |
| 44 | +### Async/Await Patterns |
| 45 | +- Always use `ConfigureAwait(false)` in SDK code |
| 46 | +- Methods should be suffixed with `Async` |
| 47 | +- Return `Task<T>` or `ValueTask<T>` for async operations |
| 48 | +- Use `CancellationToken` parameters for cancellable operations |
| 49 | + |
| 50 | +### Error Handling |
| 51 | +```csharp |
| 52 | +try |
| 53 | +{ |
| 54 | + var response = await container.ReadItemAsync<T>(id, partitionKey); |
| 55 | + return response.Resource; |
| 56 | +} |
| 57 | +catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound) |
| 58 | +{ |
| 59 | + // Handle not found specifically |
| 60 | + return null; |
| 61 | +} |
| 62 | +catch (CosmosException ex) |
| 63 | +{ |
| 64 | + // Handle other Cosmos-specific errors |
| 65 | + // Check ex.StatusCode, ex.SubStatusCode, ex.ActivityId |
| 66 | + throw; |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +### Diagnostics and Observability |
| 71 | +- Use `CosmosDiagnostics` for performance insights |
| 72 | +- Leverage `ActivityId` for correlation across requests |
| 73 | +- Include telemetry data in exceptions and responses |
| 74 | +- Use structured logging with categories like `Microsoft.Azure.Cosmos` |
| 75 | + |
| 76 | +### Performance Best Practices |
| 77 | +```csharp |
| 78 | +// Prefer stream APIs for large payloads |
| 79 | +using var responseStream = await container.ReadItemStreamAsync(id, partitionKey); |
| 80 | + |
| 81 | +// Use bulk operations for multiple items |
| 82 | +await container.CreateItemAsync(item, requestOptions: new() { EnableContentResponseOnWrite = false }); |
| 83 | + |
| 84 | +// Set request options appropriately |
| 85 | +var queryOptions = new QueryRequestOptions |
| 86 | +{ |
| 87 | + PartitionKey = partitionKey, |
| 88 | + MaxItemCount = 100, |
| 89 | + MaxConcurrency = -1 |
| 90 | +}; |
| 91 | +``` |
| 92 | + |
| 93 | +## Testing Patterns |
| 94 | + |
| 95 | +### Unit Tests (`Microsoft.Azure.Cosmos.Tests`) |
| 96 | +- Mock external dependencies using `Mock<T>` from Moq |
| 97 | +- Test classes inherit from appropriate base test classes |
| 98 | +- Use `[TestMethod]` and `[TestClass]` attributes |
| 99 | +- No external service dependencies |
| 100 | +- Focus on business logic, validation, and edge cases |
| 101 | + |
| 102 | +```csharp |
| 103 | +[TestClass] |
| 104 | +public class MyFeatureTests |
| 105 | +{ |
| 106 | + [TestMethod] |
| 107 | + public async Task MyMethod_WithValidInput_ReturnsExpectedResult() |
| 108 | + { |
| 109 | + // Arrange |
| 110 | + var mockClient = new Mock<IDocumentClient>(); |
| 111 | + // ... |
| 112 | + |
| 113 | + // Act |
| 114 | + var result = await myService.MyMethodAsync(); |
| 115 | + |
| 116 | + // Assert |
| 117 | + Assert.AreEqual(expected, result); |
| 118 | + } |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +### Emulator Tests (`Microsoft.Azure.Cosmos.EmulatorTests`) |
| 123 | +- Require Azure Cosmos DB Emulator running |
| 124 | +- Test end-to-end scenarios |
| 125 | +- Use real service interactions |
| 126 | +- Clean up resources after tests |
| 127 | + |
| 128 | +```csharp |
| 129 | +[TestClass] |
| 130 | +public class MyIntegrationTests : BaseCosmosClientHelper |
| 131 | +{ |
| 132 | + [TestInitialize] |
| 133 | + public async Task TestInitialize() |
| 134 | + { |
| 135 | + await base.TestInit(); |
| 136 | + } |
| 137 | + |
| 138 | + [TestCleanup] |
| 139 | + public async Task TestCleanup() |
| 140 | + { |
| 141 | + await base.TestCleanup(); |
| 142 | + } |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +## Common SDK Patterns |
| 147 | + |
| 148 | +### CRUD Operations |
| 149 | +```csharp |
| 150 | +// Create |
| 151 | +var createResponse = await container.CreateItemAsync(item, new PartitionKey(item.pk)); |
| 152 | + |
| 153 | +// Read |
| 154 | +var readResponse = await container.ReadItemAsync<MyItem>(id, new PartitionKey(pk)); |
| 155 | + |
| 156 | +// Update/Replace |
| 157 | +var replaceResponse = await container.ReplaceItemAsync(updatedItem, id, new PartitionKey(pk)); |
| 158 | + |
| 159 | +// Delete |
| 160 | +var deleteResponse = await container.DeleteItemAsync<MyItem>(id, new PartitionKey(pk)); |
| 161 | +``` |
| 162 | + |
| 163 | +### Querying |
| 164 | +```csharp |
| 165 | +// SQL query with parameters |
| 166 | +var query = new QueryDefinition("SELECT * FROM c WHERE c.category = @category") |
| 167 | + .WithParameter("@category", categoryValue); |
| 168 | + |
| 169 | +await foreach (var item in container.GetItemQueryIterator<MyItem>(query)) |
| 170 | +{ |
| 171 | + // Process items |
| 172 | +} |
| 173 | + |
| 174 | +// LINQ queries |
| 175 | +var linqQuery = container.GetItemLinqQueryable<MyItem>() |
| 176 | + .Where(x => x.Category == categoryValue); |
| 177 | +``` |
| 178 | + |
| 179 | +### Change Feed Processing |
| 180 | +```csharp |
| 181 | +var processor = container |
| 182 | + .GetChangeFeedProcessorBuilder<MyItem>("myProcessor", HandleChangesAsync) |
| 183 | + .WithInstanceName("myInstance") |
| 184 | + .WithLeaseContainer(leaseContainer) |
| 185 | + .Build(); |
| 186 | + |
| 187 | +await processor.StartAsync(); |
| 188 | +``` |
| 189 | + |
| 190 | +### Batch Operations |
| 191 | +```csharp |
| 192 | +var batch = container.CreateTransactionalBatch(new PartitionKey(pk)); |
| 193 | +batch.CreateItem(item1); |
| 194 | +batch.ReplaceItem(item2.Id, item2); |
| 195 | +batch.DeleteItem(item3.Id); |
| 196 | + |
| 197 | +var batchResponse = await batch.ExecuteAsync(); |
| 198 | +``` |
| 199 | + |
| 200 | +## Security Considerations |
| 201 | + |
| 202 | +### Authentication |
| 203 | +```csharp |
| 204 | +// Connection string (for development) |
| 205 | +var client = new CosmosClient(connectionString); |
| 206 | + |
| 207 | +// Account key |
| 208 | +var client = new CosmosClient(endpoint, accountKey); |
| 209 | + |
| 210 | +// Azure AD with DefaultAzureCredential |
| 211 | +var client = new CosmosClient(endpoint, new DefaultAzureCredential()); |
| 212 | + |
| 213 | +// Custom token credential |
| 214 | +var client = new CosmosClient(endpoint, tokenCredential); |
| 215 | +``` |
| 216 | + |
| 217 | +### Resource Tokens |
| 218 | +```csharp |
| 219 | +// For fine-grained access control |
| 220 | +var client = new CosmosClient(endpoint, resourceToken); |
| 221 | +``` |
| 222 | + |
| 223 | +## Configuration Patterns |
| 224 | + |
| 225 | +### CosmosClientOptions |
| 226 | +```csharp |
| 227 | +var options = new CosmosClientOptions |
| 228 | +{ |
| 229 | + ApplicationRegion = Regions.EastUS2, |
| 230 | + ConnectionMode = ConnectionMode.Direct, |
| 231 | + MaxRetryAttemptsOnRateLimitedRequests = 9, |
| 232 | + MaxRetryWaitTimeOnRateLimitedRequests = TimeSpan.FromSeconds(30), |
| 233 | + RequestTimeout = TimeSpan.FromSeconds(60), |
| 234 | + MaxRequestsPerTcpConnection = 10, |
| 235 | + MaxTcpConnectionsPerEndpoint = 16, |
| 236 | + EnableContentResponseOnWrite = false, |
| 237 | + ConsistencyLevel = ConsistencyLevel.Session |
| 238 | +}; |
| 239 | +``` |
| 240 | + |
| 241 | +## Documentation Standards |
| 242 | + |
| 243 | +### XML Documentation |
| 244 | +- Use `<summary>`, `<param>`, `<returns>`, `<exception>` tags |
| 245 | +- Include `<example>` sections with CDATA for code samples |
| 246 | +- Reference related types using `<see cref="TypeName"/>` |
| 247 | +- Document thread safety, performance implications, and best practices |
| 248 | + |
| 249 | +### Code Comments |
| 250 | +- Explain complex business logic and algorithms |
| 251 | +- Document performance considerations and trade-offs |
| 252 | +- Include references to Azure Cosmos DB documentation |
| 253 | +- Use TODO comments sparingly and with tracking items |
| 254 | + |
| 255 | +## Dependencies and Compatibility |
| 256 | + |
| 257 | +### Target Frameworks |
| 258 | +- .NET Standard 2.0 for maximum compatibility |
| 259 | +- .NET 6.0+ for performance tests and samples |
| 260 | + |
| 261 | +### Key Dependencies |
| 262 | +- `Microsoft.Azure.Cosmos.Direct` - Direct transport protocol |
| 263 | +- `Microsoft.HybridRow` - HybridRow serialization for batch operations |
| 264 | +- `Azure.Core` - Azure SDK common functionality |
| 265 | +- `System.Text.Json` - JSON serialization (preferred over Newtonsoft.Json) |
| 266 | + |
| 267 | +### Compatibility Considerations |
| 268 | +- Maintain backward compatibility for public APIs |
| 269 | +- Use appropriate nullable reference type annotations |
| 270 | +- Follow semantic versioning for breaking changes |
| 271 | +- Support long-term service (LTS) versions of .NET |
| 272 | + |
| 273 | +## Performance Guidelines |
| 274 | + |
| 275 | +### Memory Management |
| 276 | +- Prefer streaming APIs for large payloads |
| 277 | +- Dispose of resources properly using `using` statements |
| 278 | +- Avoid creating unnecessary allocations in hot paths |
| 279 | +- Use object pooling for frequently allocated objects |
| 280 | + |
| 281 | +### Network Optimization |
| 282 | +- Use bulk operations when possible |
| 283 | +- Implement proper retry policies |
| 284 | +- Configure connection pooling appropriately |
| 285 | +- Monitor and optimize partition key distribution |
| 286 | + |
| 287 | +### Monitoring and Telemetry |
| 288 | +- Use `CosmosDiagnostics` to track request charges and latency |
| 289 | +- Implement proper logging for debugging and monitoring |
| 290 | +- Use Application Insights or similar for production monitoring |
| 291 | +- Track key metrics like RU consumption and throttling |
| 292 | + |
| 293 | +## Common Anti-Patterns to Avoid |
| 294 | + |
| 295 | +1. **Creating multiple CosmosClient instances** - Use singleton pattern |
| 296 | +2. **Not using ConfigureAwait(false)** - Can cause deadlocks in certain scenarios |
| 297 | +3. **Ignoring partition key design** - Leads to hot partitions and poor performance |
| 298 | +4. **Not handling CosmosException properly** - Missing important error context |
| 299 | +5. **Using synchronous APIs** - Blocks threads unnecessarily |
| 300 | +6. **Not disposing resources** - Can lead to connection pool exhaustion |
| 301 | +7. **Hardcoding configuration values** - Use configuration patterns instead |
| 302 | + |
| 303 | +## Migration Guidance |
| 304 | + |
| 305 | +### From SDK v2 to v3 |
| 306 | +- Update namespace from `Microsoft.Azure.Documents` to `Microsoft.Azure.Cosmos` |
| 307 | +- Replace `DocumentClient` with `CosmosClient` |
| 308 | +- Update async patterns to use new response types |
| 309 | +- Migrate connection policies to `CosmosClientOptions` |
| 310 | + |
| 311 | +### Best Practices for Upgrades |
| 312 | +- Test thoroughly with both unit and integration tests |
| 313 | +- Monitor performance metrics after migration |
| 314 | +- Update documentation and samples |
| 315 | +- Provide migration guides for breaking changes |
| 316 | + |
| 317 | +This guidance helps ensure consistent, high-quality code that follows Azure Cosmos DB .NET SDK best practices and conventions. |
0 commit comments