ERDM.Core 14.0.0

dotnet add package ERDM.Core --version 14.0.0
                    
NuGet\Install-Package ERDM.Core -Version 14.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ERDM.Core" Version="14.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ERDM.Core" Version="14.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ERDM.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ERDM.Core --version 14.0.0
                    
#r "nuget: ERDM.Core, 14.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ERDM.Core@14.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ERDM.Core&version=14.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ERDM.Core&version=14.0.0
                    
Install as a Cake Tool

ERDMCore - Enterprise MongoDB Shared Kernel

๐Ÿ“‹ Overview

ERDMCore is a production-ready, enterprise-grade shared kernel for building MongoDB-based microservices, specifically designed for credit management and financial systems. It provides a comprehensive foundation following Domain-Driven Design (DDD) principles with robust infrastructure, repository patterns, and best practices for MongoDB.

๐ŸŽฏ Key Features

Core Capabilities

  • โœ… Domain-Driven Design (DDD): Rich domain models with aggregates, entities, and value objects
  • โœ… Repository Pattern: Generic and type-safe repository implementation for MongoDB
  • โœ… Unit of Work: Transaction management with MongoDB sessions
  • โœ… Audit Trail: Automatic tracking of creation, modification, and soft delete
  • โœ… Domain Events: Built-in event sourcing support
  • โœ… Soft Delete: Non-destructive deletion with IsActive flag
  • โœ… Pagination: Standardized pagination support for all queries
  • โœ… Health Checks: Built-in MongoDB health monitoring

MongoDB Optimizations

  • โœ… Connection Pooling: Configurable connection pool settings
  • โœ… Read Preferences: Support for Primary, Secondary, Nearest, and Preferred modes
  • โœ… Write Concerns: Configurable write concerns (Majority, Acknowledged, Custom)
  • โœ… Tag Sets: Support for MongoDB tag-based read preferences
  • โœ… Max Staleness: Configurable replication lag tolerance
  • โœ… Retry Logic: Automatic retry for reads and writes
  • โœ… SSL/TLS Support: Secure connections with certificate validation

Enterprise Features

  • โœ… Correlation IDs: End-to-end request tracking
  • โœ… Structured Logging: Built-in logging with correlation
  • โœ… Exception Handling: Comprehensive exception hierarchy
  • โœ… Validation: Guard clauses and input validation
  • โœ… DTO Support: Data transfer objects with pagination and filtering
  • โœ… Bulk Operations: Efficient batch operations

๐Ÿ“ฆ Installation

Using NuGet Package Manager

Install-Package ERDMCore

Using .NET CLI

dotnet add package ERDMCore

Package Reference

<PackageReference Include="ERDMCore" Version="1.0.0" />

๐Ÿš€ Quick Start

1. Configure MongoDB in appsettings.json

{
  "MongoDB": {
    "ConnectionString": "mongodb://localhost:27017",
    "DatabaseName": "credit_management",
    "CollectionPrefix": "credit",
    "MinPoolSize": 10,
    "MaxPoolSize": 100,
    "ConnectionTimeoutSeconds": 30,
    "SocketTimeoutSeconds": 30,
    "WriteConcern": "majority",
    "JournalEnabled": true,
    "ReadPreferenceMode": "Primary",
    "RetryWrites": true,
    "RetryReads": true
  }
}

2. Register ERDMCore in Program.cs

using ERDMCore.Infrastructure.MongoDB.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Add MongoDB infrastructure
builder.Services.AddMongoDB(builder.Configuration);

// Register your repositories
builder.Services.AddScoped<ICreditApplicationRepository, CreditApplicationRepository>();

var app = builder.Build();

// Map health checks
app.MapHealthChecks("/health");

app.Run();

3. Create Your Entity

using ERDMCore.Core.Entities;

public class CreditApplication : BaseEntity
{
    public string CustomerId { get; private set; }
    public decimal Amount { get; private set; }
    public string Status { get; private set; }
    public int CreditScore { get; private set; }
    
    public CreditApplication(string customerId, decimal amount)
    {
        CustomerId = customerId;
        Amount = amount;
        Status = "Draft";
    }
    
    public void Submit()
    {
        if (Status != "Draft")
            throw new BusinessRuleException("Submit", "Only draft applications can be submitted");
            
        Status = "Submitted";
        AddDomainEvent(new CreditApplicationSubmittedEvent(this));
    }
    
    public void Approve(int creditScore)
    {
        if (Status != "UnderReview")
            throw new BusinessRuleException("Approve", "Application must be under review");
            
        CreditScore = creditScore;
        Status = "Approved";
        AddDomainEvent(new CreditApplicationApprovedEvent(this));
    }
}

4. Create Repository Interface

using ERDMCore.Core.Interfaces;

public interface ICreditApplicationRepository : IRepository<CreditApplication>
{
    Task<IEnumerable<CreditApplication>> GetByCustomerIdAsync(string customerId);
    Task<IEnumerable<CreditApplication>> GetPendingApplicationsAsync();
    Task<decimal> GetTotalApprovedAmountAsync(string customerId);
}

5. Implement Repository

using ERDMCore.Infrastructure.MongoDB.Infrastructure;
using MongoDB.Driver;

public class CreditApplicationRepository : MongoRepository<CreditApplication>, ICreditApplicationRepository
{
    public CreditApplicationRepository(
        IMongoDatabase database,
        IOptions<MongoDbSettings> settings,
        ILogger<CreditApplicationRepository> logger)
        : base(database, settings, logger)
    {
    }
    
    public async Task<IEnumerable<CreditApplication>> GetByCustomerIdAsync(string customerId)
    {
        var filter = Builders<CreditApplication>.Filter.Eq(x => x.CustomerId, customerId);
        return await _collection.Find(filter).ToListAsync();
    }
    
    public async Task<IEnumerable<CreditApplication>> GetPendingApplicationsAsync()
    {
        var filter = Builders<CreditApplication>.Filter.Eq(x => x.Status, "Pending");
        return await _collection.Find(filter).ToListAsync();
    }
    
    public async Task<decimal> GetTotalApprovedAmountAsync(string customerId)
    {
        var filter = Builders<CreditApplication>.Filter.And(
            Builders<CreditApplication>.Filter.Eq(x => x.CustomerId, customerId),
            Builders<CreditApplication>.Filter.Eq(x => x.Status, "Approved")
        );
        
        var sum = await _collection.Aggregate()
            .Match(filter)
            .Group(x => x.CustomerId, g => new { Total = g.Sum(x => x.Amount) })
            .FirstOrDefaultAsync();
            
        return sum?.Total ?? 0;
    }
}

6. Use Repository in Service

public class CreditService
{
    private readonly ICreditApplicationRepository _repository;
    private readonly IUnitOfWork _unitOfWork;
    
    public CreditService(ICreditApplicationRepository repository, IUnitOfWork unitOfWork)
    {
        _repository = repository;
        _unitOfWork = unitOfWork;
    }
    
    public async Task<CreditApplication> SubmitApplicationAsync(SubmitApplicationCommand command)
    {
        await _unitOfWork.BeginTransactionAsync();
        
        try
        {
            var application = new CreditApplication(command.CustomerId, command.Amount);
            application.Submit();
            
            await _repository.AddAsync(application);
            await _unitOfWork.CommitTransactionAsync();
            
            return application;
        }
        catch
        {
            await _unitOfWork.RollbackTransactionAsync();
            throw;
        }
    }
    
    public async Task<PaginatedResult<CreditApplication>> GetApplicationsAsync(int page, int pageSize)
    {
        return await _repository.GetPaginatedAsync(
            page, 
            pageSize, 
            x => x.IsActive,
            x => x.CreatedAt,
            sortDescending: true
        );
    }
}

๐Ÿ—๏ธ Architecture

Project Structure

ERDMCore/
โ”œโ”€โ”€ Core/                           # Domain layer
โ”‚   โ”œโ”€โ”€ Entities/                   # Base entity, value objects
โ”‚   โ”œโ”€โ”€ Interfaces/                 # Repository, Unit of Work contracts
โ”‚   โ”œโ”€โ”€ DTOs/                       # Data transfer objects
โ”‚   โ”œโ”€โ”€ Exceptions/                 # Domain exceptions
โ”‚   โ””โ”€โ”€ PaginatedResult.cs          # Pagination wrapper
โ”‚
โ”œโ”€โ”€ Infrastructure.MongoDB/         # MongoDB infrastructure
โ”‚   โ”œโ”€โ”€ Settings/                   # MongoDB configuration
โ”‚   โ”œโ”€โ”€ Infrastructure/             # Repository implementations
โ”‚   โ””โ”€โ”€ Extensions/                 # Service registration
โ”‚
โ””โ”€โ”€ Middleware/                     # Cross-cutting concerns
    โ””โ”€โ”€ RequestLoggingMiddleware.cs # Request logging

Design Patterns

  • Repository Pattern: Abstraction over data access
  • Unit of Work: Transaction management
  • Domain Events: Event-driven architecture support
  • Value Objects: Immutable domain concepts
  • Aggregate Root: Consistency boundaries
  • Specification Pattern: Query encapsulation

โš™๏ธ Advanced Configuration

Read Preference with Tag Sets

{
  "MongoDB": {
    "ConnectionString": "mongodb://replica-set:27017",
    "ReadPreferenceMode": "SecondaryPreferred",
    "MaxStaleness": "00:00:90",
    "TagSets": [
      {
        "Tags": [
          { "Name": "dc", "Value": "east" },
          { "Name": "usage", "Value": "analytics" }
        ]
      }
    ]
  }
}

Write Concern Configuration

{
  "MongoDB": {
    "WriteConcern": "majority",  // Options: "majority", "1", "2", "3", "0"
    "JournalEnabled": true        // Wait for journal commit
  }
}

Connection Pool Optimization

{
  "MongoDB": {
    "MinPoolSize": 20,           // Minimum connections
    "MaxPoolSize": 200,          // Maximum connections
    "ConnectionTimeoutSeconds": 30,
    "SocketTimeoutSeconds": 60
  }
}

SSL/TLS Configuration

{
  "MongoDB": {
    "UseSsl": true,
    "AllowInsecureTls": false,   // For development only
    "ConnectionString": "mongodb://user:pass@host:27017/?ssl=true"
  }
}

๐Ÿ“Š Features Matrix

Feature Description Status
Basic CRUD Create, Read, Update, Delete operations โœ…
Soft Delete Non-destructive deletion with IsActive โœ…
Pagination Skip/Take with total count โœ…
Filtering LINQ expression support โœ…
Bulk Operations InsertMany, UpdateMany, DeleteMany โœ…
Transactions Multi-document ACID transactions โœ…
Domain Events Event sourcing support โœ…
Audit Trail CreatedBy, ModifiedBy tracking โœ…
Health Checks MongoDB connection monitoring โœ…
Connection Pooling Configurable pool settings โœ…
Read Preferences Primary, Secondary, Nearest, etc. โœ…
Write Concerns Majority, Acknowledged, Custom โœ…
Tag Sets Server selection based on tags โœ…
Max Staleness Replication lag tolerance โœ…
Retry Logic Automatic operation retry โœ…
SSL/TLS Encrypted connections โœ…

๐Ÿ”ง Performance Tuning

Connection Pool Sizing

// For high-throughput applications
settings.MinPoolSize = 50;
settings.MaxPoolSize = 500;

// For low-latency requirements
settings.ConnectionTimeoutSeconds = 10;
settings.SocketTimeoutSeconds = 15;

Read Preference Strategy

  • Primary: Strong consistency (default)
  • Secondary: Read scalability, eventual consistency
  • Nearest: Lowest latency, geographic distribution
  • SecondaryPreferred: Availability with consistency

Write Concern Strategy

  • Majority: Strong durability (default)
  • w=1: Lower latency, risk of rollback
  • w=0: Fastest, no acknowledgment

๐Ÿงช Testing

Unit Testing Example

[Fact]
public async Task AddAsync_ShouldInsertEntity()
{
    // Arrange
    var repository = new CreditApplicationRepository(database, settings, logger);
    var application = new CreditApplication("CUST-123", 5000);
    
    // Act
    var result = await repository.AddAsync(application);
    
    // Assert
    Assert.NotNull(result.Id);
    Assert.NotNull(result.CreatedAt);
    Assert.Equal("CUST-123", result.CustomerId);
}

Integration Testing with Testcontainers

[Fact]
public async Task GetByIdAsync_ShouldReturnEntity()
{
    // Arrange
    var mongoContainer = new MongoDbBuilder()
        .WithImage("mongo:6.0")
        .Build();
        
    await mongoContainer.StartAsync();
    
    var settings = new MongoDbSettings 
    { 
        ConnectionString = mongoContainer.GetConnectionString(),
        DatabaseName = "test_db"
    };
    
    // Act & Assert
    // ... test implementation
}

๐Ÿšฆ Health Checks

// Check health status
GET /health

// Response
{
    "status": "Healthy",
    "checks": [
        {
            "name": "mongodb",
            "status": "Healthy",
            "description": "MongoDB is healthy",
            "duration": "00:00:00.1234567"
        }
    ]
}

๐Ÿ“ Best Practices

1. Entity Design

// โœ… Good - Rich domain model
public class CreditApplication : BaseEntity
{
    private List<Document> _documents = new();
    
    public void Submit() { /* business logic */ }
    public void Approve() { /* business logic */ }
}

// โŒ Bad - Anemic model
public class CreditApplication
{
    public string Status { get; set; }
    // No business logic
}

2. Repository Usage

// โœ… Good - Use unit of work for multiple operations
await _unitOfWork.BeginTransactionAsync();
await _repository.AddAsync(entity1);
await _repository.AddAsync(entity2);
await _unitOfWork.CommitTransactionAsync();

// โŒ Bad - Each operation separate
await _repository.AddAsync(entity1);
await _repository.AddAsync(entity2);

3. Query Optimization

// โœ… Good - Use indexes
var filter = Builders<T>.Filter.Eq(x => x.CustomerId, customerId);
await _collection.Find(filter).ToListAsync();

// โŒ Bad - No index support
await _collection.Find("{}").ToListAsync();

๐Ÿ”’ Security Considerations

  • Always use SSL/TLS in production
  • Store connection strings in secure vault
  • Use principle of least privilege for database users
  • Enable authentication and authorization
  • Implement request validation
  • Sanitize user inputs

๐Ÿ“š API Reference

BaseEntity Properties

Property Type Description
Id string Unique identifier (ObjectId)
CreatedAt DateTime? Creation timestamp
CreatedBy string User who created
UpdatedAt DateTime? Last update timestamp
UpdatedBy string User who last updated
IsActive bool Soft delete flag
Version int Optimistic concurrency version

IRepository Methods

Method Description
GetByIdAsync Retrieve by ID
GetAllAsync Retrieve all records
AddAsync Insert single entity
UpdateAsync Update existing entity
DeleteAsync Soft delete entity
FindAsync Query with LINQ
GetPaginatedAsync Paginated results
ExecuteQueryAsync Raw MongoDB query

๐Ÿ› Troubleshooting

Common Issues and Solutions

Connection Timeout

// Increase timeout values
{
  "ConnectionTimeoutSeconds": 60,
  "SocketTimeoutSeconds": 120
}

Write Concern Timeout

// Reduce write concern or increase timeout
{
  "WriteConcern": "1",  // Instead of "majority"
  "JournalEnabled": false  // For better performance
}

Connection Pool Exhaustion

// Increase pool size
{
  "MinPoolSize": 50,
  "MaxPoolSize": 500
}

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

  • MongoDB .NET Driver team
  • Contributors and maintainers
  • Community feedback and support

๐Ÿ“ž Support


Version: 1.0.0
Release Date: March 2026
Compatible With: .NET 8.0, MongoDB 6.0+
Maintainer: ERDM Team

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on ERDM.Core:

Package Downloads
ERDMCore.Middleware

Package Description

ERDMCore.Infrastructure.MongoDB

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
14.0.0 218 3/31/2026
13.0.0 236 3/28/2026
12.0.0 126 3/27/2026
11.0.0 125 3/27/2026
10.0.0 119 3/27/2026