using Microsoft.Extensions.Caching.Distributed; using Mirea.Api.Security.Common.Interfaces; using System; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace Mirea.Api.Endpoint.Common.Services.Security; public class DistributedCacheService(IDistributedCache cache) : ICacheService { public async Task SetAsync(string key, T value, TimeSpan? absoluteExpirationRelativeToNow = null, TimeSpan? slidingExpiration = null, CancellationToken cancellationToken = default) { var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow, SlidingExpiration = slidingExpiration }; var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); if (type.IsPrimitive || type == typeof(string) || type == typeof(DateTime)) { await cache.SetStringAsync(key, value?.ToString() ?? string.Empty, options, cancellationToken); return; } var serializedValue = value as byte[] ?? JsonSerializer.SerializeToUtf8Bytes(value); await cache.SetAsync(key, serializedValue, options, cancellationToken); } public async Task GetAsync(string key, CancellationToken cancellationToken = default) { var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); if (type.IsPrimitive || type == typeof(string) || type == typeof(DateTime)) { var primitiveValue = await cache.GetStringAsync(key, cancellationToken); if (string.IsNullOrEmpty(primitiveValue)) return default; if (type == typeof(string)) return (T?)(object?)primitiveValue; var tryParseMethod = type.GetMethod("TryParse", [typeof(string), type.MakeByRefType()]) ?? throw new NotSupportedException($"Type {type.Name} does not support TryParse."); var parameters = new[] { primitiveValue, Activator.CreateInstance(type) }; var success = (bool)tryParseMethod.Invoke(null, parameters)!; if (success) return (T)parameters[1]!; return default; } var cachedValue = await cache.GetAsync(key, cancellationToken); return cachedValue == null ? default : JsonSerializer.Deserialize(cachedValue); } public Task RemoveAsync(string key, CancellationToken cancellationToken = default) => cache.RemoveAsync(key, cancellationToken); }