Merge branch 'development' of https://gitea.white-enciso.pro/AgileWebs/Core.BluePrint.Packages into development
This commit is contained in:
		| @@ -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.Caching", "Core.Blueprint.Redis\Core.Blueprint.Caching.csproj", "{11F2AA11-FB98-4A33-AEE4-CD49588D2FE1}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Blueprint.Redis", "Core.Blueprint.Redis\Core.Blueprint.Redis.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 | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| namespace Core.Blueprint.Caching.Adapters | ||||
| namespace Core.Blueprint.Redis | ||||
| { | ||||
|     public interface ICacheSettings | ||||
|     { | ||||
|   | ||||
| @@ -1,10 +1,8 @@ | ||||
| using Core.Blueprint.Caching.Adapters; | ||||
| using Core.Blueprint.Caching.Contracts; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| namespace Core.Blueprint.Caching.Configuration | ||||
| namespace Core.Blueprint.Redis.Configuration | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Provides extension methods for registering Redis-related services in the DI container. | ||||
| @@ -19,30 +17,23 @@ namespace Core.Blueprint.Caching.Configuration | ||||
|         /// <returns>The updated service collection.</returns> | ||||
|         public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration) | ||||
|         { | ||||
|             // TODO for the following variable we'll need to add in the appsettings.json the following config: "UseRedisCache": true, | ||||
|             bool useRedis = configuration.GetValue<bool>("UseRedisCache"); | ||||
|  | ||||
|             if (useRedis) | ||||
|             // Retrieve the Redis connection string from the configuration. | ||||
|             // Get Redis configuration section | ||||
|             var redisConnectionString = configuration.GetSection("ConnectionStrings:Redis").Value; | ||||
|             if (string.IsNullOrEmpty(redisConnectionString)) | ||||
|             { | ||||
|                 var redisConnectionString = configuration.GetSection("ConnectionStrings:Redis").Value; | ||||
|                 if (string.IsNullOrEmpty(redisConnectionString)) | ||||
|                 { | ||||
|                     throw new InvalidOperationException("Redis connection is not configured."); | ||||
|                 } | ||||
|  | ||||
|                 services.AddSingleton<ICacheProvider>(provider => | ||||
|                     new RedisCacheProvider(redisConnectionString, provider.GetRequiredService<ILogger<RedisCacheProvider>>())); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 services.AddMemoryCache(); | ||||
|                 services.AddSingleton<ICacheProvider, MemoryCacheProvider>(); | ||||
|                 throw new InvalidOperationException("Redis connection is not configured."); | ||||
|             } | ||||
|  | ||||
|             // Register RedisCacheProvider | ||||
|             services.AddSingleton<IRedisCacheProvider>(provider => | ||||
|                 new RedisCacheProvider(redisConnectionString, provider.GetRequiredService<ILogger<RedisCacheProvider>>())); | ||||
|  | ||||
|             // Get CacheSettings and register with the ICacheSettings interface | ||||
|             var cacheSettings = configuration.GetSection("CacheSettings").Get<CacheSettings>(); | ||||
|             if (cacheSettings == null) | ||||
|             { | ||||
|                 throw new InvalidOperationException("CacheSettings section is not configured."); | ||||
|                 throw new InvalidOperationException("Redis CacheSettings section is not configured."); | ||||
|             } | ||||
|             services.AddSingleton<ICacheSettings>(cacheSettings); | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| namespace Core.Blueprint.Caching.Contracts | ||||
| namespace Core.Blueprint.Redis | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Interface for managing Redis cache operations. | ||||
|     /// </summary> | ||||
|     public interface ICacheProvider | ||||
|     public interface IRedisCacheProvider | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Retrieves a cache item by its key. | ||||
| @@ -9,7 +9,6 @@ | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Microsoft.Azure.StackExchangeRedis" Version="3.2.1" /> | ||||
|     <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.5" /> | ||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.5" /> | ||||
|     <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.5" /> | ||||
|     <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" /> | ||||
| @@ -1,7 +1,11 @@ | ||||
| using System.Text; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Text.RegularExpressions; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Core.Blueprint.Caching.Helpers | ||||
| namespace Core.Blueprint.Redis.Helpers | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Helper class for generating consistent and normalized cache keys. | ||||
|   | ||||
| @@ -1,86 +0,0 @@ | ||||
| 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<MemoryCacheProvider> _logger; | ||||
|         public MemoryCacheProvider(IMemoryCache cache, ILogger<MemoryCacheProvider> logger) | ||||
|         { | ||||
|             _cache = cache; | ||||
|             _logger = logger; | ||||
|         } | ||||
|  | ||||
|         public ValueTask<TEntity> GetAsync<TEntity>(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<TEntity>(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<TEntity>(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<bool> 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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +1,14 @@ | ||||
| using Azure.Identity; | ||||
| using Core.Blueprint.Caching.Contracts; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using StackExchange.Redis; | ||||
| using System.Text.Json; | ||||
|  | ||||
| namespace Core.Blueprint.Caching | ||||
| namespace Core.Blueprint.Redis | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Redis cache provider for managing cache operations. | ||||
|     /// </summary> | ||||
|     public sealed class RedisCacheProvider : ICacheProvider | ||||
|     public sealed class RedisCacheProvider : IRedisCacheProvider | ||||
|     { | ||||
|         private IDatabase _cacheDatabase = null!; | ||||
|         private readonly ILogger<RedisCacheProvider> _logger; | ||||
| @@ -35,29 +34,14 @@ namespace Core.Blueprint.Caching | ||||
|         /// <param name="connectionString">The Redis connection string.</param> | ||||
|         /// <returns>An <see cref="IDatabase"/> instance representing the Redis cache database.</returns> | ||||
|         /// <exception cref="Exception">Thrown when the connection to Redis fails.</exce | ||||
|         public async Task<IDatabase> InitializeRedisAsync(string connectionString) | ||||
|         async Task<IDatabase> InitializeRedisAsync(string connectionString) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty; | ||||
|  | ||||
|                 ConfigurationOptions configurationOptions; | ||||
|  | ||||
|                 if (environment.Equals("Local", StringComparison.OrdinalIgnoreCase)) | ||||
|                 { | ||||
|                     // Use simple local Redis config | ||||
|                     configurationOptions = ConfigurationOptions.Parse(connectionString); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // Use Azure Redis config | ||||
|                     configurationOptions = await ConfigurationOptions | ||||
|                         .Parse(connectionString) | ||||
|                         .ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential()); | ||||
|                 } | ||||
|                 var configurationOptions = await ConfigurationOptions.Parse($"{connectionString}") | ||||
|                     .ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential()); | ||||
|  | ||||
|                 configurationOptions.AbortOnConnectFail = false; | ||||
|  | ||||
|                 var connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configurationOptions); | ||||
|  | ||||
|                 _logger.LogInformation("Successfully connected to Redis."); | ||||
|   | ||||
| @@ -18,12 +18,17 @@ namespace Core.Blueprint.SQLServer.Configuration | ||||
|         /// <returns>An updated <see cref="IServiceCollection"/> with SQL Server services registered.</returns> | ||||
|         public static IServiceCollection AddSQLServer(this IServiceCollection services, IConfiguration configuration) | ||||
|         { | ||||
|             var chainedCredentials = new ChainedTokenCredential( | ||||
|             var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty; | ||||
|  | ||||
|             if (environment != "Local") | ||||
|             { | ||||
|                 var chainedCredentials = new ChainedTokenCredential( | ||||
|                     new ManagedIdentityCredential(), | ||||
|                     new SharedTokenCacheCredential(), | ||||
|                     new VisualStudioCredential(), | ||||
|                     new VisualStudioCodeCredential() | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             services.AddScoped(typeof(IEntityRepository<,>), typeof(EntityRepository<,>)); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user