### ASP.NET Core Minimal API with DocumentDB and MongoDB Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt This C# code demonstrates setting up an ASP.NET Core Minimal API that integrates with DocumentDB, using MongoDB as the backend. It includes configuring services, starting a MongoDB container with Testcontainers, registering repositories, seeding data, and defining API endpoints for CRUD operations on WeatherForecast entities. The example also handles application shutdown to dispose of the container. ```csharp using Dilcore.DocumentDb.Abstractions; using Dilcore.DocumentDb.MongoDb.Extensions; using Dilcore.DocumentDb.MongoDb.Repositories; using Dilcore.DocumentDb.MongoDb.Repositories.Abstractions; using Testcontainers.MongoDb; var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Start MongoDB container (for development/testing) var mongoDbContainer = new MongoDbBuilder("mongo:latest").Build(); await mongoDbContainer.StartAsync(); var connectionString = mongoDbContainer.GetConnectionString(); // Configure DocumentDB builder.Services.AddMongoDb( configure => configure.UseConnectionString(connectionString), dbContainer => { dbContainer.AddDatabase("SampleDB", db => { db.AddGenericRepository( registerOptions => registerOptions.WithBulkRepository(), collectionOptions => collectionOptions .WithCollectionName("weatherForecasts") .WithDatabaseName("SampleDB")); }); }); var app = builder.Build(); // Cleanup on shutdown app.Lifetime.ApplicationStopping.Register(async () => await mongoDbContainer.DisposeAsync()); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // Seed data using (var scope = app.Services.CreateScope()) { var bulkRepo = scope.ServiceProvider .GetRequiredService>(); var forecasts = Enumerable.Range(1, 5) .Select(i => new WeatherForecast( DateOnly.FromDateTime(DateTime.Now.AddDays(i)), Random.Shared.Next(-20, 55), new[] { "Freezing", "Cool", "Warm", "Hot" }[Random.Shared.Next(4)])) .ToArray(); await bulkRepo.BulkStoreAsync(forecasts); } // GET all forecasts app.MapGet("/weather-forecasts", async ( IGenericRepository repository) => { var result = await repository.GetListAsync(); return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Errors); }); // GET forecast by ID app.MapGet("/weather-forecasts/{id:guid}", async ( Guid id, IGenericRepository repository) => { var result = await repository.GetAsync(id); return result.IsSuccess && result.Value != null ? Results.Ok(result.Value) : Results.NotFound(); }); // POST new forecast app.MapPost("/weather-forecasts", async ( WeatherForecast forecast, IGenericRepository repository) => { var result = await repository.StoreAsync(forecast); return result.IsSuccess ? Results.Created($"/weather-forecasts/{result.Value.Id}", result.Value) : Results.BadRequest(result.Errors); }); // PUT update forecast app.MapPut("/weather-forecasts/{id:guid}", async ( Guid id, WeatherForecast forecast, IGenericRepository repository) => { if (id != forecast.Id) return Results.BadRequest("ID mismatch"); var result = await repository.StoreAsync(forecast); return result.IsSuccess ? Results.Ok(result.Value) : Results.Conflict(result.Errors); // ETag mismatch = conflict }); // DELETE forecast app.MapDelete("/weather-forecasts/{id:guid}", async ( Guid id, long etag, IGenericRepository repository) => { var result = await repository.DeleteAsync(id, etag); return result.IsSuccess && result.Value ? Results.NoContent() : Results.NotFound(); }); app.Run(); // Entity definition record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) : IDocumentEntity { public Guid Id { get; set; } public long ETag { get; set; } public bool IsDeleted { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } ``` -------------------------------- ### TenantDatabasePrefixProvider Implementation (C#) Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md An example implementation of IDocumentDatabasePrefixProvider that prefixes database names with a tenant identifier. It relies on an ITenantContext to retrieve the current tenant ID. ```csharp public class TenantDatabasePrefixProvider : IDocumentDatabasePrefixProvider { private readonly ITenantContext _tenantContext; public TenantDatabasePrefixProvider(ITenantContext tenantContext) { _tenantContext = tenantContext; } public Task> ResolveAsync(CancellationToken cancellationToken = default) { var tenantId = _tenantContext.GetCurrentTenantId(); return Task.FromResult(Result.Ok($"tenant_{tenantId}")); } } ``` -------------------------------- ### Basic MongoDB Setup and API Endpoints in C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Demonstrates how to configure MongoDB using Testcontainers for a web API. It sets up the service with a connection string, adds a database with a generic repository for WeatherForecast entities, and defines API endpoints for retrieving and storing weather forecasts. ```csharp var builder = WebApplication.CreateBuilder(args); // Configure MongoDB with Testcontainers var mongoDbContainer = new MongoDbBuilder().Build(); await mongoDbContainer.StartAsync(); var connectionString = mongoDbContainer.GetConnectionString(); builder.Services.AddMongoDb(configure => configure.UseConnectionString(connectionString), dbContainer => { dbContainer.AddDatabase("SampleDB", db => { db.AddGenericRepository( registerRepositoryAction: register => register.WithBulkRepository(), options => { options.WithCollectionName("weatherForecasts") .WithDatabaseName("SampleDB"); }); }); }); var app = builder.Build(); // API Endpoints app.MapGet("/weather-forecasts", async (IGenericRepository repository) => { var result = await repository.GetListAsync(); return result.IsSuccess ? Results.Ok(result.ValueOrDefault) : Results.BadRequest(result.Errors); }); app.MapPost("/weather-forecasts", async (IGenericRepository repository, WeatherForecast forecast) => { var result = await repository.StoreAsync(forecast); return result.IsSuccess ? Results.Ok(result.ValueOrDefault) : Results.BadRequest(result.Errors); }); ``` -------------------------------- ### Integration Test Base Setup - C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Provides a base class for integration tests, setting up and tearing down a MongoDB instance using Testcontainers. This ensures isolated and reproducible test environments. Depends on Testcontainers.MongoDB and NUnit. ```csharp public abstract class BaseIntegrationTests { protected static readonly MongoDbContainer MongoDbContainer = new MongoDbBuilder().Build(); [OneTimeSetUp] public async Task OneTimeSetUp() { await MongoDbContainer.StartAsync(); } [OneTimeTearDown] public async Task OneTimeTearDown() { await MongoDbContainer.DisposeAsync(); } } ``` -------------------------------- ### Configure MongoDB Services with Dependency Injection (C#) Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Demonstrates how to configure MongoDB services using the `AddMongoDb` extension method for `Microsoft.Extensions.DependencyInjection`. Supports basic single-database setup and advanced configurations with multiple databases, custom prefix resolvers, and various repository types. ```csharp using Dilcore.DocumentDb.MongoDb.Extensions; using Dilcore.DocumentDb.MongoDb.Repositories; var builder = WebApplication.CreateBuilder(args); // Basic configuration with single database builder.Services.AddMongoDb( configure => configure.UseConnectionString("mongodb://localhost:27017"), dbContainer => { dbContainer.AddDatabase("SampleDB", db => { db.AddGenericRepository(options => { options.WithCollectionName("users") .WithDatabaseName("SampleDB"); }); }); }); // Advanced configuration with multiple databases and all repository types builder.Services.AddMongoDb( configure => configure .UseConnectionString("mongodb://localhost:27017") .UseMaxConnectionPoolSize(100), dbContainer => { // Database 1: User Management dbContainer.AddDatabase("UserDB", db => { db.AddGenericRepository( registerOptions => registerOptions .WithBulkRepository() .WithProjectionRepository(), collectionOptions => collectionOptions .WithCollectionName("users") .WithDatabaseName("UserDB") .WithSoftDelete() .WithIndexes( new CreateIndexModel( Builders.IndexKeys.Ascending(x => x.Email)), new CreateIndexModel( Builders.IndexKeys.Descending(x => x.CreatedAt)) )); }); // Database 2: Product Catalog with custom prefixes dbContainer.AddDatabase("ProductDB", db => { db.AddCustomDatabasePrefixResolver(); db.AddCustomCollectionPrefixResolver(); db.AddGenericRepository( registerOptions => registerOptions.WithBulkRepository(), collectionOptions => collectionOptions .WithCollectionName("products") .WithDatabaseName("ProductDB") .WithCollectionItemsTimeToLive( TimeSpan.FromDays(30), x => x.CreatedAt)); }); }); ``` -------------------------------- ### Register DocumentDB with Custom Prefix Resolvers (C#) Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Demonstrates how to register custom database and collection prefix resolvers within the DocumentDB configuration. This example shows adding a TenantDatabasePrefixProvider and a FeatureFlagCollectionPrefixProvider, ultimately affecting the MongoDB path to 'tenant_abc_AppDB.v2_users'. ```csharp builder.Services.AddMongoDb( configure => configure.UseConnectionString(connectionString), dbContainer => { dbContainer.AddDatabase("AppDB", db => { db.AddCustomDatabasePrefixResolver(); db.AddCustomCollectionPrefixResolver(); db.AddGenericRepository(options => options.WithCollectionName("users").WithDatabaseName("AppDB")); // Final MongoDB path: "tenant_abc_AppDB.v2_users" }); }); ``` -------------------------------- ### FeatureFlagCollectionPrefixProvider Implementation (C#) Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md An example implementation of IDocumentCollectionPrefixProvider that prefixes collection names based on a feature flag. It uses an IFeatureFlagService to determine whether to use a 'v1' or 'v2' prefix. ```csharp public class FeatureFlagCollectionPrefixProvider : IDocumentCollectionPrefixProvider { private readonly IFeatureFlagService _featureFlagService; public FeatureFlagCollectionPrefixProvider(IFeatureFlagService featureFlagService) { _featureFlagService = featureFlagService; } public Task> ResolveAsync(CancellationToken cancellationToken = default) { var useNewSchema = _featureFlagService.IsEnabled("UseNewUserSchema"); var prefix = useNewSchema ? "v2" : "v1"; return Task.FromResult(Result.Ok(prefix)); } } ``` -------------------------------- ### C# MongoDB Registration with Custom Database Prefix Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Illustrates how to register MongoDB services in C# using the Dilcore library, incorporating a custom database prefix provider. This example shows adding a tenant-specific prefix provider and configuring a user collection within a specific database. ```csharp // Registration builder.Services.AddMongoDb( configure => configure.UseConnectionString(connectionString), dbContainer => { dbContainer.AddDatabase("UserDB", db => { db.AddCustomDatabasePrefixResolver(); db.AddGenericRepository(options => options.WithCollectionName("users").WithDatabaseName("UserDB")); }); }); ``` -------------------------------- ### GET /weather-forecasts Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Retrieves a list of all weather forecasts. ```APIDOC ## GET /weather-forecasts ### Description Retrieves a list of all weather forecasts stored in the database. ### Method GET ### Endpoint /weather-forecasts ### Parameters #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **Array of WeatherForecast objects**: A list of weather forecast records. #### Response Example ```json [ { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "date": "2023-10-27", "temperatureC": 25, "summary": "Warm", "eTag": 1678886400, "isDeleted": false, "createdAt": "2023-10-26T10:00:00Z", "updatedAt": "2023-10-26T10:00:00Z" } ] ``` ``` -------------------------------- ### GET /weather-forecasts/{id:guid} Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Retrieves a specific weather forecast by its unique ID. ```APIDOC ## GET /weather-forecasts/{id:guid} ### Description Retrieves a specific weather forecast by its unique identifier. ### Method GET ### Endpoint /weather-forecasts/{id:guid} ### Parameters #### Path Parameters - **id** (guid) - Required - The unique identifier of the weather forecast. #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **WeatherForecast object**: The requested weather forecast record. #### Error Response (404) - **Not Found**: If no weather forecast with the specified ID is found. #### Response Example ```json { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "date": "2023-10-27", "temperatureC": 25, "summary": "Warm", "eTag": 1678886400, "isDeleted": false, "createdAt": "2023-10-26T10:00:00Z", "updatedAt": "2023-10-26T10:00:00Z" } ``` ``` -------------------------------- ### PUT /weather-forecasts/{id:guid} Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Updates an existing weather forecast. ```APIDOC ## PUT /weather-forecasts/{id:guid} ### Description Updates an existing weather forecast record identified by its ID. ### Method PUT ### Endpoint /weather-forecasts/{id:guid} ### Parameters #### Path Parameters - **id** (guid) - Required - The unique identifier of the weather forecast to update. #### Query Parameters None #### Request Body - **forecast** (WeatherForecast) - Required - The updated weather forecast object. - **id** (guid) - Required - The ID of the forecast to update (must match the ID in the path). - **date** (DateOnly) - Required - The date of the forecast. - **temperatureC** (int) - Required - The temperature in Celsius. - **summary** (string) - Optional - A summary of the weather conditions. ### Request Example ```json { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "date": "2023-10-27", "temperatureC": 26, "summary": "Sunny and Warm" } ``` ### Response #### Success Response (200 OK) - **WeatherForecast object**: The updated weather forecast record. #### Error Response (400 Bad Request) - **Error message**: If the ID in the path does not match the ID in the request body. #### Error Response (409 Conflict) - **Errors**: If there is an ETag mismatch, indicating the record has been modified since it was last retrieved. #### Response Example ```json { "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "date": "2023-10-27", "temperatureC": 26, "summary": "Sunny and Warm", "eTag": 1678886402, "isDeleted": false, "createdAt": "2023-10-26T10:00:00Z", "updatedAt": "2023-10-26T10:10:00Z" } ``` ``` -------------------------------- ### Get User Summaries with Projection - C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Demonstrates how to retrieve a list of user summaries using projection operations. It filters out deleted users and selects specific properties for the summary. Requires IGenericProjectionRepository and Builders from MongoDB.Driver. ```csharp public class ReportingService { private readonly IGenericProjectionRepository _projectionRepository; public ReportingService(IGenericProjectionRepository projectionRepository) { _projectionRepository = projectionRepository; } public async Task>> GetUserSummariesAsync() { return await _projectionRepository.GetListAsync( filter: Builders.Filter.Eq(x => x.IsDeleted, false), projection: x => new UserSummary { Id = x.Id, Name = x.Name, Email = x.Email, LastLoginDate = x.UpdatedAt }); } } public class UserSummary { public Guid Id { get; set; } public string Name { get; set; } public string Email { get; set; } public DateTime LastLoginDate { get; set; } } ``` -------------------------------- ### DELETE /weather-forecasts/{id:guid} Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Deletes a weather forecast by its ID. ```APIDOC ## DELETE /weather-forecasts/{id:guid} ### Description Deletes a weather forecast record from the database using its unique identifier. ### Method DELETE ### Endpoint /weather-forecasts/{id:guid} ### Parameters #### Path Parameters - **id** (guid) - Required - The unique identifier of the weather forecast to delete. #### Query Parameters - **etag** (long) - Required - The ETag of the forecast to ensure optimistic concurrency. #### Request Body None ### Response #### Success Response (204 No Content) - **No Content**: Indicates the weather forecast was successfully deleted. #### Error Response (404 Not Found) - **Not Found**: If no weather forecast with the specified ID is found, or if the ETag does not match. #### Response Example (No response body for 204 No Content) ``` -------------------------------- ### Define Document Entity Interface and Implementations (C#) Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Defines the base `IDocumentEntity` interface for all document entities, including standard fields for identity, concurrency, soft delete, and audit timestamps. Provides example implementations for both class-based and record-based entities. ```csharp public interface IDocumentEntity { Guid Id { get; set; } long ETag { get; set; } bool IsDeleted { get; set; } DateTime CreatedAt { get; set; } DateTime UpdatedAt { get; set; } } // Example entity implementation public class User : IDocumentEntity { public Guid Id { get; set; } public long ETag { get; set; } public bool IsDeleted { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } // Custom properties public string Name { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public int Age { get; set; } } // Record-based entity (alternative syntax) public record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) : IDocumentEntity { public Guid Id { get; set; } public long ETag { get; set; } public bool IsDeleted { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } ``` -------------------------------- ### Service Configuration with AddMongoDb - C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Demonstrates how to configure the MongoDB services using dependency injection. This includes setting the connection string, defining databases, and registering repositories with specific options. Requires Microsoft.Extensions.DependencyInjection. ```csharp services.AddMongoDb(configure => configure.UseConnectionString(connectionString), builder => { builder.AddDatabase("MyDatabase", db => { db.AddGenericRepository(options => options.WithCollectionName("myEntities") .WithDatabaseName("MyDatabase")); }); }); ``` -------------------------------- ### Configure DocumentDB with Multiple Databases (C#) Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Demonstrates how to configure DocumentDB services in C#, setting up multiple databases with generic repositories for different entities. It shows how to specify collection names and database names, and how to enable bulk and projection repositories. ```csharp services.AddMongoDb(configure => configure.UseConnectionString(connectionString), builder => { // Database 1: User Management builder.AddDatabase("UserDB", db => { db.AddGenericRepository(options => options.WithCollectionName("users") .WithDatabaseName("UserDB")); db.AddGenericRepository(repositoryOptions => repositoryOptions.WithBulkRepository(), collectionOptions => collectionOptions.WithCollectionName("roles") .WithDatabaseName("UserDB")); }); // Database 2: Product Catalog builder.AddDatabase("ProductDB", db => { db.AddCustomDatabasePrefixResolver(); db.AddGenericRepository(repositoryOptions => repositoryOptions.WithBulkRepository() .WithProjectionRepository(), collectionOptions => collectionOptions.WithCollectionName("products") .WithDatabaseName("ProductDB")); }); }); ``` -------------------------------- ### Repository Configuration Options - C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Shows how to configure repository-level options. This enables specific features like bulk operations and projection capabilities for the repository. Uses extension methods on repository options. ```csharp repositoryOptions.WithBulkRepository() // Enable bulk operations .WithProjectionRepository(); // Enable projection operations ``` -------------------------------- ### Advanced MongoDB Configuration with Custom Prefixes in C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Illustrates advanced MongoDB configuration in C#, including setting up custom database and collection prefix resolvers for multi-tenancy and feature flags. It registers a generic repository with bulk and projection capabilities, defines collection and database names, enables soft delete, and configures indexes. ```csharp services.AddMongoDb(configure => configure.UseConnectionString(connectionString), builder => { builder.AddDatabase("TestDB1", db => { // Custom database prefix for multi-tenancy db.AddCustomDatabasePrefixResolver(); // Custom collection prefix for feature flags db.AddCustomCollectionPrefixResolver(); // Register repository with all capabilities db.AddGenericRepository( repositoryOptions => repositoryOptions .WithBulkRepository() .WithProjectionRepository(), collectionOptions => collectionOptions .WithCollectionName("testEntities") .WithDatabaseName("TestDB1") .WithSoftDelete() .WithIndexes( Builders.IndexKeys.Ascending(x => x.Name), Builders.IndexKeys.Descending(x => x.CreatedAt) )); }); }); ``` -------------------------------- ### C# Environment-Based Database Prefix Provider Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Provides a C# implementation of IDocumentDatabasePrefixProvider to prefix database names based on the application's environment (e.g., development, staging, production). This aids in environment separation. It relies on IHostEnvironment to determine the current environment. ```csharp using Dilcore.DocumentDb.Abstractions; using FluentResults; // Environment-based database prefix public class EnvironmentDatabasePrefixProvider : IDocumentDatabasePrefixProvider { private readonly IHostEnvironment _environment; public EnvironmentDatabasePrefixProvider(IHostEnvironment environment) { _environment = environment; } public Task> ResolveAsync(CancellationToken cancellationToken = default) { // Results in: "dev_UserDB", "staging_UserDB", "prod_UserDB" var prefix = _environment.EnvironmentName.ToLowerInvariant(); return Task.FromResult(Result.Ok(prefix)); } } ``` -------------------------------- ### Register Repository Options for an Entity with C# Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt This C# snippet shows how to configure which repository types are registered for a given entity. It demonstrates enabling bulk and projection repositories alongside the default generic repository. The configuration is applied during the `AddGenericRepository` call, and the registered repositories can then be injected into services. ```csharp using Dilcore.DocumentDb.MongoDb.Repositories; db.AddGenericRepository( registerOptions => registerOptions .WithBulkRepository() // Enables IGenericBulkRepository .WithProjectionRepository(), // Enables IGenericProjectionRepository collectionOptions => collectionOptions .WithCollectionName("products") .WithDatabaseName("ProductDB")); // Now you can inject all three repository types: public class ProductService { private readonly IGenericRepository _repository; private readonly IGenericBulkRepository _bulkRepository; private readonly IGenericProjectionRepository _projectionRepository; public ProductService( IGenericRepository repository, IGenericBulkRepository bulkRepository, IGenericProjectionRepository projectionRepository) { _repository = repository; _bulkRepository = bulkRepository; _projectionRepository = projectionRepository; } } ``` -------------------------------- ### Collection Configuration Options - C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Illustrates how to configure collection-specific options for MongoDB. This includes setting custom names, targeting specific databases, enabling soft delete, and defining indexes. Uses extension methods on options builder. ```csharp options.WithCollectionName("customName") // Custom collection name .WithDatabaseName("customDb") // Target database .WithSoftDelete() // Enable soft delete .WithIndexes( Builders.IndexKeys.Ascending(x => x.Field1), Builders.IndexKeys.Descending(x => x.Field2) ); ``` -------------------------------- ### POST /weather-forecasts Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Creates a new weather forecast. ```APIDOC ## POST /weather-forecasts ### Description Creates a new weather forecast record in the database. ### Method POST ### Endpoint /weather-forecasts ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **forecast** (WeatherForecast) - Required - The weather forecast object to create. - **date** (DateOnly) - Required - The date of the forecast. - **temperatureC** (int) - Required - The temperature in Celsius. - **summary** (string) - Optional - A summary of the weather conditions. ### Request Example ```json { "date": "2023-10-28", "temperatureC": 22, "summary": "Sunny" } ``` ### Response #### Success Response (201 Created) - **WeatherForecast object**: The newly created weather forecast record, including its generated ID and ETag. #### Error Response (400 Bad Request) - **Errors**: If the request body is invalid or missing required fields. #### Response Example ```json { "id": "b2c3d4e5-f6a7-8901-2345-67890abcdef0", "date": "2023-10-28", "temperatureC": 22, "summary": "Sunny", "eTag": 1678886401, "isDeleted": false, "createdAt": "2023-10-26T10:05:00Z", "updatedAt": "2023-10-26T10:05:00Z" } ``` ``` -------------------------------- ### Configure MongoDB Collection Options with C# Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt This snippet demonstrates how to fluently configure MongoDB collection settings using C#. It covers setting database and collection names, enabling soft delete, creating empty collections, configuring TTL for document expiration, and defining indexes for query optimization. Dependencies include Dilcore.DocumentDb.Abstractions and MongoDB.Driver. ```csharp using Dilcore.DocumentDb.Abstractions; using MongoDB.Driver; // Full collection configuration example db.AddGenericRepository(options => { options // Required: Set database and collection names .WithDatabaseName("OrderDB") .WithCollectionName("orders") // Enable soft delete (sets IsDeleted=true instead of removing) .WithSoftDelete() // Create collection even if empty .WithEmptyCollection() // Configure TTL for automatic document expiration .WithCollectionItemsTimeToLive( TimeSpan.FromDays(365), x => x.CreatedAt) // Define indexes for query optimization .WithIndexes( new CreateIndexModel( Builders.IndexKeys.Ascending(x => x.CustomerId)), new CreateIndexModel( Builders.IndexKeys.Combine( Builders.IndexKeys.Ascending(x => x.Status), Builders.IndexKeys.Descending(x => x.CreatedAt))), new CreateIndexModel( Builders.IndexKeys.Text(x => x.Description)) ); }); ``` -------------------------------- ### C# Tenant-Based Database Prefix Provider Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Implements IDocumentDatabasePrefixProvider in C# to dynamically set database names based on the current tenant. This is useful for multi-tenant applications to isolate data. It depends on ITenantContext for retrieving tenant information. ```csharp using Dilcore.DocumentDb.Abstractions; using FluentResults; // Multi-tenant database prefix provider public class TenantDatabasePrefixProvider : IDocumentDatabasePrefixProvider { private readonly ITenantContext _tenantContext; public TenantDatabasePrefixProvider(ITenantContext tenantContext) { _tenantContext = tenantContext; } public Task> ResolveAsync(CancellationToken cancellationToken = default) { var tenantId = _tenantContext.GetCurrentTenantId(); // Results in: "tenant_abc_UserDB" for tenant "abc" return Task.FromResult(Result.Ok($"tenant_{tenantId}")); } } ``` -------------------------------- ### Bulk Operations with IGenericBulkRepository in C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Demonstrates the use of `IGenericBulkRepository` for efficient bulk operations on `User` entities within a `DataMigrationService`. It includes methods for bulk storing an array of users and bulk deleting users based on specified criteria. ```csharp public class DataMigrationService { private readonly IGenericBulkRepository _bulkRepository; public DataMigrationService(IGenericBulkRepository bulkRepository) { _bulkRepository = bulkRepository; } public async Task>> MigrateUsersAsync(User[] users) { return await _bulkRepository.BulkStoreAsync(users); } public async Task CleanupInactiveUsersAsync() { return await _bulkRepository.BulkDeleteAsync(x => x.IsDeleted && x.UpdatedAt < DateTime.UtcNow.AddYears(-1)); } } ``` -------------------------------- ### Basic CRUD Operations with IGenericRepository in C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Shows how to use `IGenericRepository` for basic CRUD operations on `User` entities within a `UserService`. It covers creating, retrieving by ID, retrieving a list of active users, and deleting users, demonstrating the use of the `Result` type for operation outcomes. ```csharp public class UserService { private readonly IGenericRepository _userRepository; public UserService(IGenericRepository userRepository) { _userRepository = userRepository; } public async Task> CreateUserAsync(User user) { return await _userRepository.StoreAsync(user); } public async Task> GetUserByIdAsync(Guid userId) { return await _userRepository.GetAsync(userId); } public async Task>> GetActiveUsersAsync() { return await _userRepository.GetListAsync(x => !x.IsDeleted); } public async Task> DeleteUserAsync(Guid userId, long eTag) { return await _userRepository.DeleteAsync(userId, eTag); } } ``` -------------------------------- ### Implement A/B Test Collection Prefix Provider (C#) Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Generates a collection prefix based on the user's A/B test group. It relies on IUserContext to retrieve the test group, which can be 'control' or 'treatment', influencing the collection name. ```csharp // A/B testing collection prefix public class ABTestCollectionPrefixProvider : IDocumentCollectionPrefixProvider { private readonly IUserContext _userContext; public ABTestCollectionPrefixProvider(IUserContext userContext) { _userContext = userContext; } public Task> ResolveAsync(CancellationToken cancellationToken = default) { var testGroup = _userContext.GetABTestGroup(); // "control" or "treatment" return Task.FromResult(Result.Ok(testGroup)); } } ``` -------------------------------- ### IDocumentDatabasePrefixProvider Interface (C#) Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Defines the interface for custom database prefix providers in DocumentDB. Implementations control the naming of MongoDB databases, supporting multi-tenancy, environment separation, and regional deployments. ```csharp public interface IDocumentDatabasePrefixProvider : IDocumentPrefixProvider { Task> ResolveAsync(CancellationToken cancellationToken = default); } ``` -------------------------------- ### Package Dependencies - XML Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Lists the necessary NuGet package versions required for the Dilcore DocumentDB library. These include MongoDB.Driver for MongoDB interaction, FluentResults for result handling, and Microsoft.Extensions.DependencyInjection for DI. This configuration should be placed in Directory.Packages.props. ```xml ``` -------------------------------- ### Service Usage of GenericRepository - C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Shows a service class that utilizes the configured IGenericRepository to perform operations like storing entities. It demonstrates dependency injection of the repository and calling its methods asynchronously. Requires FluentResults for the Result type. ```csharp public class MyService { private readonly IGenericRepository _repository; public MyService(IGenericRepository repository) { _repository = repository; } public async Task> CreateAsync(MyEntity entity) { return await _repository.StoreAsync(entity); } } ``` -------------------------------- ### C# Generic Projection Repository for Data Transformations Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Demonstrates the use of IGenericProjectionRepository in C# for optimized data retrieval. It allows fetching specific fields of entities, reducing payload size and improving performance. Dependencies include MongoDB.Driver and FluentResults. ```csharp using Dilcore.DocumentDb.MongoDb.Repositories.Abstractions; using FluentResults; using MongoDB.Driver; // Projection DTOs public class UserSummary { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; } public class UserStats { public Guid Id { get; set; } public DateTime LastActive { get; set; } public bool IsActive { get; set; } } public class ReportingService { private readonly IGenericProjectionRepository _projectionRepository; public ReportingService(IGenericProjectionRepository projectionRepository) { _projectionRepository = projectionRepository; } // Get single projected entity public async Task> GetUserSummaryAsync(Guid userId) { var filter = Builders.Filter.Eq(x => x.Id, userId); return await _projectionRepository.GetAsync( filter, user => new UserSummary { Id = user.Id, Name = user.Name, Email = user.Email }); } // Get list with projection and filter public async Task>> GetActiveUserSummariesAsync() { var filter = Builders.Filter.Eq(x => x.IsDeleted, false); return await _projectionRepository.GetListAsync( filter, user => new UserSummary { Id = user.Id, Name = user.Name, Email = user.Email }); } // Get all with projection (no filter) public async Task>> GetAllUserStatsAsync() { return await _projectionRepository.GetListAsync( user => new UserStats { Id = user.Id, LastActive = user.UpdatedAt, IsActive = !user.IsDeleted }); } // Complex projection for dashboard public async Task>> GetDashboardDataAsync() { var filter = Builders.Filter.And( Builders.Filter.Eq(x => x.IsDeleted, false), Builders.Filter.Gte(x => x.Age, 18)); return await _projectionRepository.GetListAsync( filter, user => new DashboardUserDto { UserId = user.Id, DisplayName = user.Name, MemberSince = user.CreatedAt, DaysSinceLastActivity = (DateTime.UtcNow - user.UpdatedAt).Days }); } } public class DashboardUserDto { public Guid UserId { get; set; } public string DisplayName { get; set; } = string.Empty; public DateTime MemberSince { get; set; } public int DaysSinceLastActivity { get; set; } } ``` -------------------------------- ### Perform Bulk Operations with IGenericBulkRepository in C# Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Demonstrates how to use the IGenericBulkRepository for various bulk operations including inserting, updating, and deleting entities in MongoDB. It utilizes FluentResults for handling operation outcomes and showcases optimistic concurrency for updates. ```csharp using Dilcore.DocumentDb.MongoDb.Repositories.Abstractions; using FluentResults; public class DataMigrationService { private readonly IGenericBulkRepository _bulkRepository; public DataMigrationService(IGenericBulkRepository bulkRepository) { _bulkRepository = bulkRepository; } // Bulk insert new entities public async Task>> ImportUsersAsync(User[] users) { // All entities with ETag = 0 will be inserted var result = await _bulkRepository.BulkStoreAsync(users); if (result.IsSuccess) { Console.WriteLine($"Imported {result.Value.Count} users"); // Each entity now has Id, ETag, CreatedAt, UpdatedAt populated foreach (var user in result.Value) { Console.WriteLine($"User {user.Name}: ID={user.Id}, ETag={user.ETag}"); } } return result; } // Bulk store with IEnumerable (for streaming/lazy sources) public async Task>> ImportUsersFromStreamAsync( IEnumerable usersStream) { return await _bulkRepository.BulkStoreRangeAsync(usersStream); } // Bulk update existing entities public async Task>> UpdateMultipleUsersAsync(User[] users) { // Entities with ETag > 0 will be updated using optimistic concurrency return await _bulkRepository.BulkStoreAsync(users); } // Bulk delete with expression public async Task DeleteOldInactiveUsersAsync() { var oneYearAgo = DateTime.UtcNow.AddYears(-1); var result = await _bulkRepository.BulkDeleteAsync( x => x.IsDeleted && x.UpdatedAt < oneYearAgo); if (result.IsSuccess) { Console.WriteLine("Cleanup completed successfully"); } else { Console.WriteLine($"Cleanup failed: {result.Errors.First().Message}"); } return result; } // Example: Seed database with test data public async Task SeedDatabaseAsync() { var users = Enumerable.Range(1, 1000) .Select(i => new User { Name = $"User {i}", Email = $"user{i}@example.com", Age = 20 + (i % 50) }) .ToArray(); var result = await _bulkRepository.BulkStoreAsync(users); Console.WriteLine($"Seeded {result.ValueOrDefault?.Count ?? 0} users"); } } ``` -------------------------------- ### IDocumentCollectionPrefixProvider Interface (C#) Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Defines the interface for custom collection prefix providers in DocumentDB. Implementations dynamically control the naming of MongoDB collections, useful for feature flags, A/B testing, and data migrations. ```csharp public interface IDocumentCollectionPrefixProvider : IDocumentPrefixProvider { Task> ResolveAsync(CancellationToken cancellationToken = default); } ``` -------------------------------- ### Bulk Repository Interface for MongoDB in C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md This C# interface, `IGenericBulkRepository`, provides optimized methods for performing bulk operations on MongoDB documents. It includes `BulkStoreAsync` for inserting multiple documents and `BulkDeleteAsync` for removing multiple documents based on an expression. ```csharp public interface IGenericBulkRepository where TDocument : IDocumentEntity { Task>> BulkStoreAsync(TDocument[] entities, CancellationToken cancellationToken = default); Task BulkDeleteAsync(Expression> expression, CancellationToken cancellationToken = default); } ``` -------------------------------- ### Projection Repository Interface for MongoDB in C# Source: https://github.com/aytymchuk/dilcore-library-documentdb/blob/main/README.md Defines the `IGenericProjectionRepository` interface in C# for efficient data retrieval and transformation from MongoDB. It allows fetching specific projections of documents using filter definitions and projection expressions. ```csharp public interface IGenericProjectionRepository where TDocument : IDocumentEntity { Task> GetAsync(FilterDefinition filter, Expression> projection, CancellationToken cancellationToken = default); Task>> GetListAsync(FilterDefinition filter, Expression> projection, CancellationToken cancellationToken = default); } ``` -------------------------------- ### C# Integration Test Base Class with Testcontainers for MongoDB Source: https://context7.com/aytymchuk/dilcore-library-documentdb/llms.txt Provides a base class for integration tests using Testcontainers to spin up an isolated MongoDB instance. It configures dependency injection for MongoDB repositories and includes setup/teardown methods for the container. This class is designed to be extended by specific test fixtures. ```csharp using Dilcore.DocumentDb.MongoDb.Extensions; using Dilcore.DocumentDb.MongoDb.Repositories; using Dilcore.DocumentDb.MongoDb.Repositories.Abstractions; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using Testcontainers.MongoDb; public abstract class BaseIntegrationTests { protected static readonly MongoDbContainer MongoDbContainer = new MongoDbBuilder("mongo:latest").Build(); protected IServiceProvider ServiceProvider { get; private set; } = null!; [OneTimeSetUp] public async Task OneTimeSetUp() { await MongoDbContainer.StartAsync(); } [OneTimeTearDown] public async Task OneTimeTearDown() { await MongoDbContainer.DisposeAsync(); } [SetUp] public void SetUp() { var services = new ServiceCollection(); var connectionString = MongoDbContainer.GetConnectionString(); services.AddMongoDb( configure => configure.UseConnectionString(connectionString), dbContainer => { dbContainer.AddDatabase("TestDB", db => { db.AddGenericRepository( options => options .WithBulkRepository() .WithProjectionRepository(), collectionOptions => collectionOptions .WithCollectionName($"test_{Guid.NewGuid():N}") .WithDatabaseName("TestDB") .WithSoftDelete()); }); }); ServiceProvider = services.BuildServiceProvider(); } protected IGenericRepository GetRepository() => ServiceProvider.GetRequiredService>(); protected IGenericBulkRepository GetBulkRepository() => ServiceProvider.GetRequiredService>(); protected IGenericProjectionRepository GetProjectionRepository() => ServiceProvider.GetRequiredService>(); } public class TestEntity : IDocumentEntity { public Guid Id { get; set; } public long ETag { get; set; } public bool IsDeleted { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } public string Name { get; set; } = string.Empty; public int Value { get; set; } } // Example test class [TestFixture] public class GenericRepositoryTests : BaseIntegrationTests { [Test] public async Task StoreAsync_NewEntity_CreatesWithIdAndETag() { var repository = GetRepository(); var entity = new TestEntity { Name = "Test", Value = 42 }; var result = await repository.StoreAsync(entity); Assert.That(result.IsSuccess, Is.True); Assert.That(result.Value.Id, Is.Not.EqualTo(Guid.Empty)); Assert.That(result.Value.ETag, Is.Not.EqualTo(0)); Assert.That(result.Value.CreatedAt, Is.Not.EqualTo(default(DateTime))); } [Test] public async Task GetAsync_ExistingEntity_ReturnsEntity() { var repository = GetRepository(); var entity = new TestEntity { Name = "Test", Value = 42 }; var stored = (await repository.StoreAsync(entity)).Value; var result = await repository.GetAsync(stored.Id); Assert.That(result.IsSuccess, Is.True); Assert.That(result.Value.Name, Is.EqualTo("Test")); } [Test] public async Task DeleteAsync_WithSoftDelete_SetsIsDeletedFlag() { var repository = GetRepository(); var entity = new TestEntity { Name = "Test", Value = 42 }; var stored = (await repository.StoreAsync(entity)).Value; var deleteResult = await repository.DeleteAsync(stored.Id, stored.ETag); Assert.That(deleteResult.IsSuccess, Is.True); // Entity should not appear in normal queries var getResult = await repository.GetAsync(stored.Id); Assert.That(getResult.Value, Is.Null); } } ```