IMEX.CORE: .NET 8/9/10 core library with unified Fluent API. Cache: L1/L2 Hybrid (199ns L1 hit, 40M ops/sec), CacheConfigurationBuilder (strategy, preset, ConfigureL1/ConfigureHybrid/ConfigureMonitoring, WithRateLimiting). SqlSugar: SqlSugarOptionsBuilder (NOLOCK, slow query, callbacks). AddImexCore: UseCache, UseSqlSugar(configure), UseRateLimiting(configure), UseMonitoring(configure), UseImexCore(app, configure). ISmartCache registered by default. Production-ready.
$ dotnet add package IMEX.COREIMEX.Core library for API systems – High-performance Hybrid Cache, SqlSugar ORM, unified Fluent API (AddImexCore, CacheConfigurationBuilder, SqlSugarOptionsBuilder). Configure Cache/SqlSugar/Monitoring/RateLimit via builders; Fluent API evaluation: complete for Cache, SqlSugar, and Middleware.
IMEX.Core is a core library for APIs: high-performance Hybrid Cache, SqlSugar ORM, and unified Fluent API to configure Cache, SqlSugar, Monitoring, RateLimit, and Middleware from Program.cs.
docs/FLUENT-API-EVALUATION.mddocs/FLUENT-API-EVALUATION.mdFusionStyleOptimizations.CreateKeyThreeParts / CreateKeyTwoParts (string.Create) for EnhancedMemoryCache, CachePerformanceOptimizer, ResilientRedisClusterProvider — single allocation per keyThreadLocalMetricsBuffer.GetDecisionMetrics() returns HitRatio, ErrorRate, P50Ms, P95Ms, P99Ms for TTL, warming, skip L2, circuit. Call RecordError() on operation failure to update error rateCacheGetOptionsPool.Rent() / Return(options) when profiling shows options allocation as bottleneck. ValueTask path: use GetIfCachedAsync for L1-only readEnableL1Compression = false (default) — L1 stores object reference, no compression → very fast Get/Set for large objects (100KB+), minimal allocation. Set EnableL1Compression = true when saving RAM (adaptive compression by memory pressure)CacheGetOptions.SkipDistributedLocker = true — skip distributed lock for that call to reduce latency/contention (like FusionCache SetSkipDistributedLocker)# Package Manager
Install-Package IMEX.CORE -Version 2.0.5
# .NET CLI
dotnet add package IMEX.CORE --version 2.0.5
# Paket
paket add IMEX.CORE --version 2.0.5
🆕 Latest (Fluent API & Package):
{
"MainDB": "DB_Main",
"MultiDBEnabled": true,
"DBConnections": [
{
"ConnId": "DB_Main",
"DBType": 1,
"Enable": true,
"HitRate": 50,
"ConnectionStr": "Data Source=localhost;Initial Catalog=MedcomHR;Integrated Security=True;",
"ProviderName": "System.Data.SqlClient",
"Slaves": [
{
"HitRate": 0,
"Connection": "Data Source=slave-server;Initial Catalog=MedcomHR;Integrated Security=True;"
}
]
}
]
}
{
"Cache": {
"Hybrid": {
"L2TtlMultiplier": 3.0,
"L1PromotionTtlMinutes": 30,
"EnableFactoryTimeouts": true,
"SoftTimeoutMs": 500,
"HardTimeoutMs": 20000,
"FailSafeTtlMultiplier": 5.0,
"EnableRedisPubSubSync": true,
"EnableSignalRSync": true,
"HealthCheckIntervalSeconds": 30,
"DefaultLockTimeoutSeconds": 30
},
"EnhancedMemoryCache": {
"BackgroundRefreshRatio": 0.7,
"BackgroundRefreshIntervalSeconds": 45,
"CleanupSampleSize": 1500,
"CleanupSamplingRate": 0.08,
"AdaptiveTtl": {
"HighHitRatioThreshold": 0.85,
"LowHitRatioThreshold": 0.6,
"HighPerformanceMultiplier": 2.0,
"MaxTtlMultiplier": 4.0,
"MinTtlMinutes": 5
}
},
"Medical": {
"PatientDataCacheMinutes": 90,
"MedicalRecordsCacheMinutes": 180,
"VitalSignsCacheMinutes": 15,
"AllergiesCacheMinutes": 360,
"MedicationsCacheMinutes": 120
},
"Warming": {
"EnableWarmingOnStartup": true,
"MaxConcurrentWarmingTasks": 4,
"WarmingTaskTimeoutSeconds": 30,
"TotalWarmingTimeoutMinutes": 5,
"BatchSize": 50,
"RetryCount": 3
},
"Tracing": {
"EnableTracing": true,
"SamplingRate": 0.1,
"ServiceName": "EMR-Cache",
"EnableMetrics": true,
"EnableDetailedAttributes": false
},
"Eviction": {
"PolicyType": "Adaptive",
"MemoryPressureThreshold": 80,
"MaxEntriesPerEviction": 1000
},
"LargeScale": {
"ExpectedConcurrentUsers": 10000,
"EnableCacheWarming": true,
"EnableTracing": true,
"TracingSamplingRate": 0.1
},
"BatchOperations": {
"MaxBatchSize": 500,
"MaxConcurrentBatches": 10,
"BatchTimeoutSeconds": 30,
"EnablePipelining": true
},
"RedisCluster": {
"EnableCluster": false,
"EnableSentinel": false,
"InstanceName": "EMR-Cache",
"VirtualNodesPerPhysical": 150,
"ClusterEndpoints": [],
"SentinelEndpoints": [],
"SentinelServiceName": "mymaster"
},
"MultiTenant": {
"Enabled": false,
"AllowEmptyTenant": true,
"TrackKeysPerTenant": true,
"TenantHeaderName": "X-Tenant-Id"
},
"Decorators": {
"EnableTracingDecorator": true,
"EnableTenantDecorator": false
}
},
"Redis": {
"Enable": true,
"ConnectionString": "localhost:6379",
"Database": 0,
"KeyPrefix": "emr:"
}
}
{
"Serilog": {
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
}
},
{
"Name": "Elasticsearch",
"Args": {
"nodeUris": "http://localhost:9200",
"indexFormat": "medcom-hr-logs-{0:yyyy.MM.dd}"
}
}
]
}
}
Namespaces: AddImexCore, UseImexCore, CacheMode, ImexCoreOptions nằm trong IMEX.CORE.Extensions; CachePreset là CacheConfigurationBuilder.CachePreset trong IMEX.CORE.Caching.Configuration.
using IMEX.CORE.Extensions;
using IMEX.CORE.Caching.Configuration;
// Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
// ✅ Option 1: Minimal setup (Memory Cache + SqlSugar)
builder.Services.AddImexCore();
// ✅ Option 2: Full configuration
builder.Services.AddImexCore(options =>
{
options.UseCache(CacheMode.Hybrid, "localhost:6379");
options.UseCachePreset(CacheConfigurationBuilder.CachePreset.HighPerformance);
options.UseSqlSugar();
options.UseMonitoring();
options.UseCacheWarming();
});
// ✅ Option 3: From appsettings.json
builder.Services.AddImexCore(builder.Configuration);
// ✅ Option 4: Detailed Rate Limiting & Monitoring (Fluent)
builder.Services.AddImexCore(options =>
{
options.UseCache(CacheMode.Hybrid, "localhost:6379");
options.UseSqlSugar();
options.UseRateLimiting(config =>
{
config.TokensPerSecond = 200;
config.MaxConcurrentOperations = 80;
config.QueueLimit = 150;
});
options.UseMonitoring(config =>
{
config.RefreshIntervalSeconds = 15;
config.MinHitRatio = 0.80;
config.LatencyWarningMs = 1.5;
});
});
var app = builder.Build();
app.UseImexCore(); // Default: App.IsRun = true
// Or configure middleware (e.g. disable setting application state)
app.UseImexCore(opts => opts.SetApplicationRunningState = false);
app.Run();
{
"ImexCore": {
"CacheMode": "Hybrid",
"RedisConnection": "localhost:6379",
"EnableMonitoring": true,
"EnableCacheWarming": true,
"UseSqlSugar": true
}
}
When using AddImexCore, you can configure in detail via these overloads:
| Method | Description | Example |
|---|---|---|
UseRateLimiting(configure) | Enable rate limiting and configure (tokens/s, concurrent, queue) | options.UseRateLimiting(c => { c.TokensPerSecond = 200; }) |
UseMonitoring(configure) | Enable monitoring and configure dashboard (refresh, thresholds) | options.UseMonitoring(c => { c.RefreshIntervalSeconds = 15; }) |
UseSqlSugar(configure) | Enable SqlSugar and Fluent config (NOLOCK, slow query, …) | See SqlSugarOptionsBuilder |
ConfigureCache(configure) | Detailed CacheConfigurationBuilder configuration | options.ConfigureCache(b => b.ConfigureL1(...)) |
Middleware: app.UseImexCore(configure) – configure middleware (e.g. SetApplicationRunningState = false to avoid setting App.IsRun = true).
Cache (direct AddCache()): use .ConfigureMonitoring(configure) to configure the health dashboard (RefreshIntervalSeconds, MinHitRatio, LatencyWarningMs, …).
| Strategy | Description | Use Case |
|---|---|---|
UseMemoryCache() | L1 in-memory only | Single server, development |
UseHybridCache(redis) | L1 Memory + L2 Redis | Multi-server, production |
UseRedisCache(redis) | Redis only | Stateless containers |
UseAutoStrategy() | Auto-detect | Auto-scaling environments |
| Preset | MaxEntries | MaxMemory | BackgroundRefresh | Use Case |
|---|---|---|---|---|
HighPerformance | 5000 | 1GB | 90% | High-traffic APIs |
MemoryOptimized | 1000 | 256MB | 70% | Limited RAM |
HighReliability | 3000 | 512MB | 80% | Critical apps |
HybridProduction | 2000 | 512MB | 85% | Multi-server |
using IMEX.CORE.Caching.Configuration;
// 🎯 Option 1: Fluent Builder (Recommended)
services.AddCache()
// Choose strategy
.UseHybridCache("localhost:6379", instanceName: "MyApp")
// Choose preset
.WithPreset(CachePreset.HighPerformance)
// Optional features
.WithMonitoring() // Health dashboard
.WithMetrics() // Prometheus metrics
.WithRateLimiting(config => // Rate limiting
{
config.TokensPerSecond = 100;
config.MaxConcurrentOperations = 50;
})
.WithMemoryPressureManagement() // Auto-eviction when RAM is low
// Configure Monitoring/Dashboard (refresh interval, thresholds)
.ConfigureMonitoring(config =>
{
config.RefreshIntervalSeconds = 20;
config.MaxHistoryCount = 240;
config.MinHitRatio = 0.75;
config.LatencyWarningMs = 2.0;
})
// Custom L1 configuration
.ConfigureL1(config =>
{
config.FailSafe.MaxEntries = 10000;
config.FailSafe.MaxTotalBytes = 2L * 1024 * 1024 * 1024; // 2GB
config.BackgroundRefreshRatio = 0.85;
config.AdaptiveTtl.HighHitRatioThreshold = 0.9;
config.AdaptiveTtl.HighPerformanceMultiplier = 2.5;
})
// Custom Hybrid configuration
.ConfigureHybrid(config =>
{
config.EnableL2Cache = true;
config.L2TtlMultiplier = 3.0;
config.EnableBackgroundRefresh = true;
config.SoftTimeout = TimeSpan.FromSeconds(3);
config.HardTimeout = TimeSpan.FromSeconds(20);
})
.Build();
// 🚀 High Performance (Memory or Hybrid)
services.AddHighPerformanceCache(); // Memory only
services.AddHighPerformanceCache("localhost:6379"); // Hybrid với Redis
// 💾 Memory Optimized (tiết kiệm RAM)
services.AddMemoryOptimizedCache();
// 🏭 Production Hybrid (full features)
services.AddProductionHybridCache(
redisConnectionString: "localhost:6379",
enableRateLimiting: true,
enableMemoryPressure: true
);
{
"Cache": {
"EnhancedMemoryCache": {
"BackgroundRefreshRatio": 0.85,
"BackgroundRefreshIntervalSeconds": 30,
"CleanupSampleSize": 2000,
"CleanupSamplingRate": 0.15,
"FailSafe": {
"MaxEntries": 5000,
"MaxTotalBytes": 536870912,
"DefaultTtlMinutes": 45,
"AlwaysCompressSnapshot": true
},
"AdaptiveTtl": {
"HighHitRatioThreshold": 0.85,
"LowHitRatioThreshold": 0.5,
"HighPerformanceMultiplier": 1.8,
"MaxTtlMultiplier": 2.5,
"MinTtlMinutes": 2
},
"SingleFlight": {
"HighConcurrencyThreshold": 256,
"WaitForExistingHighMs": 1500,
"FactoryHardTimeoutMs": 8000
}
},
"Hybrid": {
"EnableL2Cache": true,
"L2TtlMultiplier": 2.5,
"L1PromotionTtlMinutes": 25,
"EnableFactoryTimeouts": true,
"SoftTimeoutMs": 3000,
"HardTimeoutMs": 20000,
"FailSafeTtlMultiplier": 1.2
}
},
"Redis": {
"Enable": true,
"ConnectionString": "localhost:6379",
"InstanceName": "MyApp",
"DefaultExpiration": "00:45:00",
"EnableCircuitBreaker": true,
"CbErrorRateThreshold": 0.08,
"CbBreakSeconds": 20,
"RetryCount": 3
}
}
// Program.cs
builder.Services.AddSqlSugarSetup();
// Or via AddImexCore
builder.Services.AddImexCore(options =>
{
options.UseSqlSugar();
});
When you need to customize SqlSugar (AutoCloseConnection, WithNoLock, SlowQuery, callbacks…), use SqlSugarOptionsBuilder in one of two ways:
Option 1: Call AddSqlSugarSetup directly with a lambda
// Program.cs
using IMEX.CORE.DBAccess;
using IMEX.CORE.DBAccess.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSqlSugarSetup(options => options
.UseAutoCloseConnection(true)
.UseWithNoLock(true) // SQL Server: WITH (NOLOCK)
.UseSlowQueryDetection(thresholdMs: 3000, samplingRate: 1)
.UseDiffLog(true)
.ConfigureMoreSettings(settings =>
{
settings.IsAutoRemoveDataCache = true;
settings.SqlServerCodeFirstNvarchar = true;
})
.OnSlowQueryDetected((sql, parameters, duration) =>
{
Console.WriteLine($"Slow query: {duration}ms - {sql}");
})
.OnError(ex =>
{
// Handle SqlSugar errors
}));
var app = builder.Build();
app.Run();
Option 2: Via AddImexCore with overload UseSqlSugar(Action<SqlSugarOptionsBuilder>)
// Program.cs
builder.Services.AddImexCore(options =>
{
options.UseCache(CacheMode.Memory);
options.UseSqlSugar(sqlSugar => sqlSugar
.UseAutoCloseConnection(true)
.UseWithNoLock(true)
.UseSlowQueryDetection(3000)
.OnSlowQueryDetected((sql, parameters, duration) =>
{
// Custom handling
}));
});
Common builder methods:
| Method | Description |
|---|---|
UseAutoCloseConnection(bool) | Close connection after each query |
UseWithNoLock(bool) | SQL Server: use WITH (NOLOCK) |
UseSlowQueryDetection(thresholdMs, samplingRate) | Enable slow query detection |
UseDiffLog(bool) | Enable Diff Log for audit |
ConfigureMoreSettings(Action<ConnMoreSettings>) | Configure MoreSettings in detail |
OnSlowQueryDetected(Action<sql, parameters, duration>) | Callback when slow query is detected |
OnError(Action<SqlSugarException>) | Callback on SQL error |
{
"MainDB": "DB_Main",
"DBConnections": [
{
"ConnId": "DB_Main",
"DBType": 1,
"Enable": true,
"HitRate": 50,
"ConnectionStr": "Server=localhost;Database=MyDB;User Id=sa;Password=xxx;",
"Slaves": [
{
"HitRate": 30,
"ConnectionStr": "Server=slave1;Database=MyDB;User Id=sa;Password=xxx;"
},
{
"HitRate": 20,
"ConnectionStr": "Server=slave2;Database=MyDB;User Id=sa;Password=xxx;"
}
]
},
{
"ConnId": "DB_Log",
"DBType": 1,
"Enable": true,
"HitRate": 0,
"ConnectionStr": "Server=localhost;Database=MyDB_Log;User Id=sa;Password=xxx;"
}
]
}
| DBType | Database | Description |
|---|---|---|
| 0 | MySql | MySQL/MariaDB |
| 1 | SqlServer | Microsoft SQL Server |
| 2 | Sqlite | SQLite |
| 3 | Oracle | Oracle Database |
| 4 | PostgreSQL | PostgreSQL |
| 5 | Dm | DM Database |
| 6 | Kdbndp | Kingbase |
(SqlSugar SQL support)
{
"AppSettings": {
"SqlAOP": {
"EnableSlowQueryDetection": true,
"SlowQueryThresholdMs": 3000,
"SlowQuerySamplingRate": 100,
"EnableDiffLog": true
},
"LogToDb": true
}
}
public class UserService
{
private readonly ISqlSugarClient _db;
private readonly ISmartCache _cache;
public UserService(ISqlSugarClient db, ISmartCache cache)
{
_db = db;
_cache = cache;
}
// Query với cache
public async Task<List<User>> GetActiveUsersAsync()
{
var key = _cache.CreateKey("users", "active");
return await _cache.GetAsync(key, async () =>
{
return await _db.Queryable<User>()
.Where(u => u.IsActive)
.ToListAsync();
}, ttlMinutes: 30);
}
// Transaction
public async Task<bool> CreateUserAsync(User user)
{
try
{
_db.Ado.BeginTran();
await _db.Insertable(user).ExecuteCommandAsync();
await _db.Insertable(new UserProfile { UserId = user.Id })
.ExecuteCommandAsync();
_db.Ado.CommitTran();
// Invalidate cache
await _cache.RemoveByPrefixAsync("users");
return true;
}
catch
{
_db.Ado.RollbackTran();
throw;
}
}
// Multi-database
public async Task<List<AuditLog>> GetLogsAsync()
{
// Switch to Log database
return await _db.GetConnection("DB_Log")
.Queryable<AuditLog>()
.OrderByDescending(l => l.CreatedAt)
.Take(100)
.ToListAsync();
}
}
{
"DBConnections": [
{
"ConnId": "DB_Main",
"DBType": 1,
"Enable": true,
"HitRate": 50,
"ConnectionStr": "Server=master;Database=MyDB;...",
"Slaves": [
{
"HitRate": 30,
"ConnectionStr": "Server=slave1;Database=MyDB;..."
},
{
"HitRate": 20,
"ConnectionStr": "Server=slave2;Database=MyDB;..."
}
]
}
]
}
Note: Higher HitRate means that slave is used more often. HitRate = 0 means not used.
{
"DBConnections": [
{
"ConnId": "DB_Main",
"DBType": 1,
"Enable": true,
"ConnectionStr": "BASE64_ENCRYPTED_STRING.SIGNATURE"
}
]
}
The library automatically detects and decrypts connection strings in the base64.signature format.
// Option 1: All features from appsettings.json
services.AddLargeScaleCacheFeatures();
// Option 2: Custom configuration
services.AddLargeScaleCacheFeatures(new LargeScaleCacheOptions
{
ExpectedConcurrentUsers = 20000,
EnableCacheWarming = true,
EnableTracing = true,
TracingSamplingRate = 0.05,
ServiceName = "EMR-Production"
});
// Thêm tính năng riêng lẻ
services.AddCacheWarming();
services.AddCacheTracing();
services.AddAdaptiveEviction();
services.AddBatchOperationsConfig();
// From appsettings.json
services.AddRedisClusterSupport();
// Or custom configuration
services.AddRedisClusterSupport(options =>
{
options.EnableCluster = true;
options.ClusterEndpoints = new List<string>
{
"redis-node1:6379",
"redis-node2:6379",
"redis-node3:6379"
};
options.VirtualNodesPerPhysical = 150;
});
// Add tenant context provider
services.AddDefaultTenantContextProvider();
// Thêm cache decorators với tenant isolation
services.AddCacheDecorators(
enableTracing: true,
enableTenantIsolation: true
);
using IMEX.Core.Caching.Interfaces;
public class MyService
{
private readonly ISmartCache _cache;
public MyService(ISmartCache cache)
{
_cache = cache;
}
// Get với factory pattern
public async Task<Employee> GetEmployeeAsync(int id)
{
var key = _cache.CreateKey("employees", id.ToString());
return await _cache.GetAsync<Employee>(key, async () =>
{
return await _dbContext.Employees.FindAsync(id);
}, ttlMinutes: 30);
}
// Batch operations
public async Task<Dictionary<string, Employee>> GetEmployeesAsync(IEnumerable<int> ids)
{
var keys = ids.Select(id => _cache.CreateKey("employees", id.ToString()));
return await _cache.GetManyAsync<Employee>(keys);
}
// Remove by prefix
public async Task InvalidateEmployeeCacheAsync()
{
await _cache.RemoveByPrefixAsync("employees");
}
}
public class EmployeeCacheWarmer
{
private readonly CacheWarmingService _warmingService;
public EmployeeCacheWarmer(CacheWarmingService warmingService)
{
_warmingService = warmingService;
}
public void RegisterWarmingTasks()
{
// Register critical keys
_warmingService.RegisterCriticalKey("employees:all", async () =>
{
return await _dbContext.Employees.ToListAsync();
}, priority: 1, ttlMinutes: 60);
_warmingService.RegisterCriticalKey("departments:all", async () =>
{
return await _dbContext.Departments.ToListAsync();
}, priority: 2, ttlMinutes: 120);
}
}
using IMEX.CORE.Caching.Monitoring;
// Get metrics
var metrics = cache.GetCacheMetrics();
// Export Prometheus format
var prometheusData = CacheOpenTelemetryExporter.ExportPrometheusSnapshot(metrics);
// Metrics bao gồm:
// - cache_hit_ratio
// - cache_latency_ms
// - cache_memory_usage_bytes
// - cache_entries_count
// - cache_eviction_count
using IMEX.CORE.DBAccess;
public class EmployeeRepository
{
private readonly DbContextBase _dbContext;
private readonly ISmartCache _cache;
public async Task<List<Employee>> GetActiveEmployeesAsync(int departmentId)
{
var key = _cache.CreateKey("employees", $"dept:{departmentId}:active");
return await _cache.GetAsync(key, async () =>
{
return await _dbContext.Queryable<Employee>()
.Where(e => e.DepartmentId == departmentId && e.IsActive)
.ToListAsync();
}, ttlMinutes: 30);
}
}
┌───────────────────────────────────────────────────────────┐
│ IMEX.Core │
├───────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Caching │ │ Database │ │ Security │ │
│ │ System │ │ Access │ │ Layer │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├───────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Logging │ │ Utilities │ │ Models │ │
│ │ System │ │ & Helpers │ │ & DTOs │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├───────────────────────────────────────────────────────────┤
│ .NET 8.0/9.0/10.0 Runtime │
└───────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ Enterprise Cache System (Large-Scale) │
├─────────────────────────────────────────────────────────────────────────────┤
│ DECORATORS LAYER │
│ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ │
│ │ TracingDecorator │ │ TenantDecorator │ │ EventDrivenDeco. │ │
│ │ • OpenTelemetry │ │ • Multi-tenant │ │ • Cache Events │ │
│ │ • Prometheus │ │ • Key isolation │ │ • Notifications │ │
│ └───────────────────┘ └───────────────────┘ └───────────────────┘ │
├─────────────────────────────────────────────────────────────────────────────┤
│ HYBRID CACHE LAYER │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ EnhancedHybridMemoryCache │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ L1 Memory │ │ L2 Redis │ │ Lock │ │ Circuit │ │ │
│ │ │ Cache │→ │ Cache │ │ Manager │ │ Breaker │ │ │
│ │ │ (Enhanced) │ │ (MsgPack) │ │ (Single- │ │ (Enhanced) │ │ │
│ │ └─────────────┘ └─────────────┘ │ Flight) │ └─────────────┘ │ │
│ │ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────────┤
│ L1 CACHE FEATURES │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Fail-Safe │ │ Background │ │ Adaptive │ │ Prefix/Tag │ │
│ │ Cache │ │ Refresh │ │ TTL │ │ Manager │ │
│ │ • Stale │ │ • SWR │ │ • Hit-based │ │ • Trie DS │ │
│ │ fallback │ │ • Scheduled │ │ • Frequency │ │ • Pattern │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────────────┤
│ L2 CACHE FEATURES │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ MessagePack │ │ Redis Cluster │ │ Consistent Hash │ │
│ │ Provider │ │ Provider │ │ Ring │ │
│ │ • LZ4 compress │ │ • Cluster mode │ │ • Virtual nodes │ │
│ │ • Pipeline │ │ • Sentinel │ │ • Auto balance │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────────────────────┤
│ MANAGEMENT SERVICES │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Warming │ │ Eviction │ │ Memory │ │ Health │ │
│ │ Service │ │ Policy │ │ Pressure │ │ Monitor │ │
│ │ • Startup │ │ • LRU/LFU │ │ • Auto GC │ │ • Real-time │ │
│ │ • Priority │ │ • Adaptive │ │ • Auto GC │ │ • Metrics │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
CacheConfiguration (Root)
├── HybridCacheConfiguration
│ └── L2 TTL, Factory Timeouts, Sync settings
├── EnhancedMemoryCacheConfiguration
│ └── AdaptiveTtlConfiguration
├── MedicalCacheConfiguration
│ └── Domain-specific TTLs
├── WarmingConfiguration
├── TracingConfiguration
├── EvictionConfiguration
├── LargeScaleConfiguration
├── BatchOperationsConfiguration
├── RedisClusterConfiguration
├── MultiTenantConfiguration
└── DecoratorsConfiguration
ISmartCachepublic interface ISmartCache : IDisposable, IAsyncDisposable
{
// Key management
string CreateKey(string tableName, string key);
// Sync operations
T? Get<T>(string key);
T? GetFast<T>(string key); // Ultra-fast, skip complex features
void Set<T>(string key, T value, int ttlMinutes);
void SetFast<T>(string key, T value, int ttlMinutes);
void SetSmart<T>(string key, T value, int ttlMinutes);
// Async operations
Task<T?> GetAsync<T>(string key, Func<Task<T>> factory, int ttlMinutes);
Task<T?> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, int ttlMinutes);
Task SetAsync<T>(string key, T value, int ttlMinutes);
// Batch operations
Task<Dictionary<string, T?>> GetManyAsync<T>(IEnumerable<string> keys);
Task SetManyAsync<T>(Dictionary<string, T> entries, int ttlMinutes);
Task RemoveManyAsync(IEnumerable<string> keys);
Task<Dictionary<string, T>> GetOrCreateManyAsync<T>(
IEnumerable<string> keys,
Func<IEnumerable<string>, Task<Dictionary<string, T>>> factory,
int ttlMinutes);
// Removal operations
Task RemoveAsync(string key);
Task RemoveByPrefixAsync(string prefix);
// Metrics
CacheDashboardMetrics GetCacheMetrics();
}
ICacheWarmerpublic interface ICacheWarmer
{
Task WarmCacheAsync(CancellationToken cancellationToken);
Task WarmCriticalKeysAsync(IEnumerable<CacheWarmingEntry> entries);
void RegisterCriticalKey<T>(string key, Func<Task<T>> factory, int priority, int ttlMinutes);
}
IEvictionPolicypublic interface IEvictionPolicy
{
string PolicyName { get; }
IEnumerable<string> SelectKeysForEviction(
IEnumerable<CacheEntryInfo> entries,
int maxEntriesToEvict);
}
// Available policies:
// - LruEvictionPolicy
// - LfuEvictionPolicy
// - SizeBasedEvictionPolicy
// - TtlEvictionPolicy
// - RandomEvictionPolicy
// - AdaptiveEvictionPolicy
// - CompositeEvictionPolicy
IConsistentHashRingpublic interface IConsistentHashRing
{
void AddNode(string nodeId);
void RemoveNode(string nodeId);
string GetNode(string key);
int NodeCount { get; }
int VirtualNodeCount { get; }
}
// CacheSetup extensions
public static class CacheSetup
{
// Auto-detection
void AddSmartCacheSetup(this IServiceCollection services, IConfiguration? config);
// Strategy-based
void AddCacheSetupWithStrategy(this IServiceCollection services, CacheStrategy strategy, IConfiguration? config);
// Large-scale features
void AddLargeScaleCacheFeatures(this IServiceCollection services, LargeScaleCacheOptions? options);
void AddCacheWarming(this IServiceCollection services, Action<CacheWarmingConfig>? configure);
void AddCacheTracing(this IServiceCollection services, Action<CacheTracingConfig>? configure);
void AddRedisClusterSupport(this IServiceCollection services, Action<RedisClusterOptions>? configure);
void AddAdaptiveEviction(this IServiceCollection services, Action<EvictionPolicyConfig>? configure);
void AddBatchOperationsConfig(this IServiceCollection services, Action<BatchOperationsConfig>? configure);
// Multi-tenant
void AddDefaultTenantContextProvider(this IServiceCollection services);
void AddCacheDecorators(this IServiceCollection services, bool? enableTracing, bool? enableTenantIsolation);
}
dotnet test .\tests\IMEX.CORE.Tests\IMEX.CORE.Tests.csproj -c Release
Note:
Skipped if the environment does not meet requirements.To exclude Performance tests from the release pipeline, run with a filter by namespace (depending on how tests are organized):
dotnet test .\tests\IMEX.CORE.Tests\IMEX.CORE.Tests.csproj -c Release --filter FullyQualifiedName!~IMEX.CORE.Tests.Performance
[Test]
public async Task Cache_Should_Store_And_Retrieve_Data()
{
// Arrange
var cache = new EnhancedMemoryCache(memoryCache, config);
var testData = new { Id = 1, Name = "Test" };
// Act
await cache.SetAsync("test:key", testData, 10);
var result = await cache.GetAsync<object>("test:key", () => Task.FromResult(testData));
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result.Id, Is.EqualTo(1));
}
[Test]
public async Task BatchOperations_Should_Handle_Multiple_Keys()
{
// Arrange
var entries = new Dictionary<string, Employee>
{
["emp:1"] = new Employee { Id = 1, Name = "John" },
["emp:2"] = new Employee { Id = 2, Name = "Jane" }
};
// Act
await cache.SetManyAsync(entries, ttlMinutes: 30);
var results = await cache.GetManyAsync<Employee>(entries.Keys);
// Assert
Assert.That(results.Count, Is.EqualTo(2));
}
[Test]
public async Task Cache_Performance_Should_Be_Optimal()
{
// Arrange
var analyzer = new CachePerformanceAnalyzer();
// Act
var results = await analyzer.RunBenchmarkAsync(100_000);
// Assert
Assert.That(results.SetOperations.Improvement, Is.GreaterThan(2.0)); // 2x faster
Assert.That(results.MemoryUsage.MemorySavings, Is.GreaterThan(40.0)); // 40% less memory
}
| Operation | Standard .NET | IMEX.Core | Improvement |
|---|---|---|---|
| Set Operations | 100ns | 25ns | 4x faster |
| Get Operations | 50ns | 15ns | 3.3x faster |
| Memory Usage | 100% | 30-50% | 50-70% less |
| GC Pressure | 100% | 10-20% | 80-90% less |
| Throughput | 800K ops/sec | 3.2M ops/sec | 4x higher |
| Batch Operations | 10K ops/sec | 500K ops/sec | 50x faster |
Dự án cung cấp sample code để bắt đầu nhanh:
| Sample | Mô tả |
|---|---|
| CacheTestApp | Ứng dụng mẫu dùng IMEX Core với cache: AddImexCore, ISmartCache, GetAsync/SetAsync. |
| HealthCheckExample.cs | Ví dụ health check endpoint (IdGenerator, cache, DB) để tích hợp với ASP.NET Core Health Checks hoặc monitoring. |
Chạy sample:
cd samples/CacheTestApp
dotnet run
Benchmark cache (L1, Hybrid, Redis, so sánh FusionCache, v.v.) nằm trong thư mục benchmarks/CacheBenchmarks:
Chạy nhanh (ví dụ):
cd benchmarks/CacheBenchmarks
dotnet run -c Release
| Triệu chứng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| Redis connection failed / timeout | Redis chưa chạy, sai host/port, firewall chặn. | Kiểm tra Redis đang chạy (redis-cli ping), đúng connection string (ví dụ localhost:6379), mở port 6379. |
| Hybrid cache chỉ dùng L1, không ghi L2 | L2 (Redis) lỗi hoặc circuit breaker mở. | Xem log/exception khi kết nối Redis; kiểm tra cấu hình circuit breaker (CbErrorRateThreshold, CbBreakSeconds) trong Redis/Cache.Hybrid. |
| ISmartCache not registered | Dùng strategy Redis-only; ISmartCache chỉ đăng ký cho Memory và Hybrid. | Dùng UseMemoryCache() hoặc UseHybridCache(redis); hoặc tự đăng ký implementation ISmartCache cho Redis nếu cần. |
| Triệu chứng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| Connection string not found / DB không kết nối | MainDB hoặc ConnId không khớp với DBConnections. | Trong appsettings kiểm tra MainDB trùng ConnId của một connection trong DBConnections; connection đó có Enable: true và ConnectionStr đúng. |
| Slow query không log | Chưa bật slow query detection. | Dùng UseSlowQueryDetection(thresholdMs, samplingRate) trên SqlSugarOptionsBuilder hoặc cấu hình AppSettings:SqlAOP:EnableSlowQueryDetection và SlowQueryThresholdMs. |
| Read/Write splitting không dùng slave | HitRate = 0 hoặc chỉ có master. | Thêm Slaves với HitRate > 0 (tổng HitRate thường 100); đảm bảo connection slave hợp lệ. |
| Triệu chứng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| AddImexCore từ appsettings không đúng | Section ImexCore thiếu hoặc sai key. | Đảm bảo có section ImexCore với CacheMode, RedisConnection (nếu Hybrid/Redis), UseSqlSugar, EnableMonitoring, EnableCacheWarming theo appsettings mẫu. |
| UseImexCore() sau khi Build() vẫn lỗi | Middleware chưa được gọi hoặc thứ tự middleware. | Gọi app.UseImexCore() (hoặc UseImexCore(configure)) sau builder.Build(), trước app.Run(). |
| CachePreset / CacheMode không nhận | Thiếu namespace. | Thêm using IMEX.CORE.Extensions; và using IMEX.CORE.Caching.Configuration;; dùng CacheConfigurationBuilder.CachePreset.HighPerformance cho preset. |
We welcome contributions from the community! To contribute:
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is distributed under the MIT license. See LICENSE for details.
⭐ If this library is useful to you, please give us a star! ⭐
Made with ❤️ by truongnv2412