diff --git a/Core.BluePrint.Packages.sln b/Core.BluePrint.Packages.sln
index 7a136ec..0c6eb67 100644
--- a/Core.BluePrint.Packages.sln
+++ b/Core.BluePrint.Packages.sln
@@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Blueprint.KeyVault", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Blueprint.Mongo", "Core.Blueprint.Mongo\Core.Blueprint.Mongo.csproj", "{27A8E3E1-D613-4D5B-8105-485699409F1E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Blueprint.Redis", "Core.Blueprint.Redis\Core.Blueprint.Redis.csproj", "{11F2AA11-FB98-4A33-AEE4-CD49588D2FE1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Blueprint.Caching", "Core.Blueprint.Redis\Core.Blueprint.Caching.csproj", "{11F2AA11-FB98-4A33-AEE4-CD49588D2FE1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Blueprint.Storage", "Core.Blueprint.Storage\Core.Blueprint.Storage.csproj", "{636E4520-79F9-46C8-990D-08F2D24A151C}"
EndProject
diff --git a/Core.Blueprint.Redis/Configuration/RegisterBlueprint.cs b/Core.Blueprint.Redis/Configuration/RegisterBlueprint.cs
index 3aeb596..7ebdcb0 100644
--- a/Core.Blueprint.Redis/Configuration/RegisterBlueprint.cs
+++ b/Core.Blueprint.Redis/Configuration/RegisterBlueprint.cs
@@ -1,4 +1,6 @@
-using Microsoft.Extensions.Configuration;
+using Core.Blueprint.Caching;
+using Core.Blueprint.Caching.Contracts;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -17,23 +19,32 @@ namespace Core.Blueprint.Redis.Configuration
/// The updated service collection.
public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration)
{
- // Retrieve the Redis connection string from the configuration.
- // Get Redis configuration section
- var redisConnectionString = configuration.GetSection("ConnectionStrings:Redis").Value;
- if (string.IsNullOrEmpty(redisConnectionString))
+ // TODO for the following variable we'll need to add in the appsettings.json the following config: "UseRedisCache": true,
+ bool useRedis = configuration.GetValue("UseRedisCache");
+ //TODO decide wheter to use appsettings or the following ENV variable
+ useRedis = Environment.GetEnvironmentVariable("CORE_BLUEPRINT_PACKAGES_USE_REDIS")?.ToLower() == "true";
+
+ if (useRedis)
{
- throw new InvalidOperationException("Redis connection is not configured.");
+ var redisConnectionString = configuration.GetSection("ConnectionStrings:Redis").Value;
+ if (string.IsNullOrEmpty(redisConnectionString))
+ {
+ throw new InvalidOperationException("Redis connection is not configured.");
+ }
+
+ services.AddSingleton(provider =>
+ new RedisCacheProvider(redisConnectionString, provider.GetRequiredService>()));
+ }
+ else
+ {
+ services.AddMemoryCache();
+ services.AddSingleton();
}
- // Register RedisCacheProvider
- services.AddSingleton(provider =>
- new RedisCacheProvider(redisConnectionString, provider.GetRequiredService>()));
-
- // Get CacheSettings and register with the ICacheSettings interface
var cacheSettings = configuration.GetSection("CacheSettings").Get();
if (cacheSettings == null)
{
- throw new InvalidOperationException("Redis CacheSettings section is not configured.");
+ throw new InvalidOperationException("CacheSettings section is not configured.");
}
services.AddSingleton(cacheSettings);
diff --git a/Core.Blueprint.Redis/Contracts/IRedisCacheProvider.cs b/Core.Blueprint.Redis/Contracts/ICacheProvider.cs
similarity index 96%
rename from Core.Blueprint.Redis/Contracts/IRedisCacheProvider.cs
rename to Core.Blueprint.Redis/Contracts/ICacheProvider.cs
index f9a7b5e..cf0a323 100644
--- a/Core.Blueprint.Redis/Contracts/IRedisCacheProvider.cs
+++ b/Core.Blueprint.Redis/Contracts/ICacheProvider.cs
@@ -1,9 +1,9 @@
-namespace Core.Blueprint.Redis
+namespace Core.Blueprint.Caching.Contracts
{
///
/// Interface for managing Redis cache operations.
///
- public interface IRedisCacheProvider
+ public interface ICacheProvider
{
///
/// Retrieves a cache item by its key.
diff --git a/Core.Blueprint.Redis/Core.Blueprint.Redis.csproj b/Core.Blueprint.Redis/Core.Blueprint.Caching.csproj
similarity index 90%
rename from Core.Blueprint.Redis/Core.Blueprint.Redis.csproj
rename to Core.Blueprint.Redis/Core.Blueprint.Caching.csproj
index e1322ba..8d17004 100644
--- a/Core.Blueprint.Redis/Core.Blueprint.Redis.csproj
+++ b/Core.Blueprint.Redis/Core.Blueprint.Caching.csproj
@@ -8,6 +8,7 @@
+
diff --git a/Core.Blueprint.Redis/MemoryCacheProvider.cs b/Core.Blueprint.Redis/MemoryCacheProvider.cs
new file mode 100644
index 0000000..91beb2a
--- /dev/null
+++ b/Core.Blueprint.Redis/MemoryCacheProvider.cs
@@ -0,0 +1,86 @@
+using Core.Blueprint.Caching.Contracts;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Caching.Memory;
+using System.Text.Json;
+
+namespace Core.Blueprint.Caching
+{
+ public sealed class MemoryCacheProvider : ICacheProvider
+ {
+ private readonly IMemoryCache _cache;
+ private readonly ILogger _logger;
+ public MemoryCacheProvider(IMemoryCache cache, ILogger logger)
+ {
+ _cache = cache;
+ _logger = logger;
+ }
+
+ public ValueTask GetAsync(string key)
+ {
+ if (_cache.TryGetValue(key, out var value))
+ {
+ if (value is TEntity typedValue)
+ {
+ return ValueTask.FromResult(typedValue);
+ }
+
+ try
+ {
+ var json = value?.ToString();
+ var deserialized = JsonSerializer.Deserialize(json);
+ return ValueTask.FromResult(deserialized);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Error deserializing cache value for key {Key}", key);
+ }
+ }
+
+ return ValueTask.FromResult(default(TEntity));
+ }
+
+ public ValueTask SetAsync(string key, TEntity value, TimeSpan? expiry = null)
+ {
+ var options = new MemoryCacheEntryOptions();
+ if (expiry.HasValue)
+ {
+ options.SetAbsoluteExpiration(expiry.Value);
+ }
+
+ _cache.Set(key, value, options);
+ return ValueTask.CompletedTask;
+ }
+
+ public ValueTask RemoveAsync(string key)
+ {
+ _cache.Remove(key);
+ return ValueTask.CompletedTask;
+ }
+
+ public ValueTask ExistsAsync(string key)
+ {
+ return ValueTask.FromResult(_cache.TryGetValue(key, out _));
+ }
+
+ public ValueTask RefreshAsync(string key, TimeSpan? expiry = null)
+ {
+ // MemoryCache does not support sliding expiration refresh like Redis,
+ // so we must re-set the value manually if required.
+
+ if (_cache.TryGetValue(key, out var value))
+ {
+ _cache.Remove(key);
+
+ var options = new MemoryCacheEntryOptions();
+ if (expiry.HasValue)
+ {
+ options.SetAbsoluteExpiration(expiry.Value);
+ }
+
+ _cache.Set(key, value, options);
+ }
+
+ return ValueTask.CompletedTask;
+ }
+ }
+}
diff --git a/Core.Blueprint.Redis/RedisCacheProvider.cs b/Core.Blueprint.Redis/RedisCacheProvider.cs
index 525e310..7715f44 100644
--- a/Core.Blueprint.Redis/RedisCacheProvider.cs
+++ b/Core.Blueprint.Redis/RedisCacheProvider.cs
@@ -1,14 +1,15 @@
using Azure.Identity;
+using Core.Blueprint.Caching.Contracts;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using System.Text.Json;
-namespace Core.Blueprint.Redis
+namespace Core.Blueprint.Caching
{
///
/// Redis cache provider for managing cache operations.
///
- public sealed class RedisCacheProvider : IRedisCacheProvider
+ public sealed class RedisCacheProvider : ICacheProvider
{
private IDatabase _cacheDatabase = null!;
private readonly ILogger _logger;