Files
parr_api/PARR.DAL/Cache/Services/Base/RedisCacheService.cs
2026-03-23 13:58:31 +10:00

194 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.Caching.Distributed;
using StackExchange.Redis;
using System.Text.Json;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace PARR.DAL.Cache.Services.Base
{
internal class RedisCacheService : IRedisCacheService
{
private readonly IDistributedCache cache;
private readonly IDatabase redis;
public RedisCacheService(
IDistributedCache cache,
IConnectionMultiplexer connectionMultiplexer
)
{
this.cache = cache;
this.redis = connectionMultiplexer.GetDatabase();
}
#region Распределенный кэш IDistributedCache
public async Task<T?> GetCachedDataAsync<T>(string key)
{
var jsonData = await cache.GetStringAsync(key);
if (jsonData == null)
return default(T);
return JsonSerializer.Deserialize<T>(jsonData);
}
public T? GetCachedData<T>(string key)
{
var jsonData = cache.GetString(key);
if (jsonData == null)
return default(T);
return JsonSerializer.Deserialize<T>(jsonData);
}
public void SetCachedData<T>(string key, T data, TimeSpan cacheDuration)
{
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = cacheDuration
};
var jsonData = JsonSerializer.Serialize(data);
cache.SetString(key, jsonData, options);
}
public async Task SetCachedDataAsync<T>(string key, T data, TimeSpan cacheDuration)
{
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = cacheDuration
};
var jsonData = JsonSerializer.Serialize(data);
await cache.SetStringAsync(key, jsonData, options);
}
public async Task DeleteCachedDataAsync(string key)
{
await cache.RemoveAsync(key);
}
public void DeleteCachedData(string key)
{
cache.Remove(key);
}
#endregion
#region Нативные операции Redis, Redis Hash
public async Task SetHashFieldAsync<T>(string hashKey, string field, T value, TimeSpan? ttl = null)
{
// меняет одно поле в Hash
var jsonData = JsonSerializer.Serialize(value);
// true - поля не было, создалось новое. false - поле было, обновили значение
var result = await redis.HashSetAsync(hashKey, field, jsonData);
// если указан ttl, обновим для всего Hash
// если не указан и ранее был создан hashKey, оставит его ttl; а если hashKey не было, то создаст его БЕССРОЧНЫМ!!!
if (ttl.HasValue)
await SetHashTtlAsync(hashKey, ttl.Value);
}
public async Task<T?> GetHashFieldAsync<T>(string hashKey, string field)
{
// получить значение поля из Hash
var value = await redis.HashGetAsync(hashKey, field);
if (value.IsNullOrEmpty)
return default;
return JsonSerializer.Deserialize<T>(value);
}
public async Task<Dictionary<string, T>> GetAllHashFieldsAsync<T>(string hashKey)
{
// получить все записи из Hash
var objs = await redis.HashGetAllAsync(hashKey);
if (objs.Length == 0)
return new Dictionary<string, T>();
var result = objs.ToDictionary(
t => t.Name.ToString(),
t => JsonSerializer.Deserialize<T>(t.Value)
);
return result!;
}
public async Task DeleteHashFieldAsync(string hashKey, string field)
{
// удалить запись из Hash
await redis.HashDeleteAsync(hashKey, field);
}
public async Task<bool> HashFieldExistsAsync(string hashKey, string field)
{
// есть ли запись в Hash
return await redis.HashExistsAsync(hashKey, field);
}
public async Task DeleteHashAsync(string hashKey)
{
// удалить весь Hash
await redis.KeyDeleteAsync(hashKey);
}
public async Task<long> GetHashLengthAsync(string hashKey)
{
// кол-во записей в hash
return await redis.HashLengthAsync(hashKey);
}
public async Task SetHashTtlAsync(string hashKey, TimeSpan ttl)
{
// Установить ttl для Hash
await redis.KeyExpireAsync(hashKey, ttl);
}
#endregion
#region Helpers
public string GetKey(string[] keyParts, string[]? keyPartsToHash = null)
{
// разделитель между ИД
var mainSeparator = "_";
// разделитель между словами
var wordSeparator = "-";
if (keyParts.Length == 0)
{
throw new ArgumentNullException("keyParts не может быть пустым");
}
var keyStr = string.Join(mainSeparator, keyParts).Replace(" ", wordSeparator);
if (keyPartsToHash != null && keyPartsToHash.Length > 0)
{
var partsToHashStr = string.Join(mainSeparator, keyPartsToHash).Replace(" ", wordSeparator);
using var sha256 = System.Security.Cryptography.SHA256.Create();
var hashedBytes = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(partsToHashStr));
var base64str = Convert.ToBase64String(hashedBytes).Substring(0, 16);
return (keyStr + mainSeparator + base64str).ToLower();
}
return keyStr.ToLower();
}
#endregion
}
}