mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-26 04:32:50 +08:00
177 lines
7.1 KiB
C#
177 lines
7.1 KiB
C#
using Microsoft.Extensions.Caching.Distributed;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace FreeSql.Internal.CommonProvider {
|
|
class CacheProvider : ICache {
|
|
|
|
public IDistributedCache Cache { get; private set; }
|
|
private bool CacheSupportMultiRemove = false;
|
|
private static DateTime dt1970 = new DateTime(1970, 1, 1);
|
|
|
|
public CacheProvider(IDistributedCache cache, ILogger log) {
|
|
if (cache == null) cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions { }));
|
|
Cache = cache;
|
|
var key1 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
|
|
var key2 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
|
|
Cache.Set(key1, new byte[] { 65 });
|
|
Cache.Set(key2, new byte[] { 65 });
|
|
try { Cache.Remove($"{key1}|{key2}"); } catch { } // redis-cluster 不允许执行 multi keys 命令
|
|
CacheSupportMultiRemove = Cache.Get(key1) == null && cache.Get(key2) == null;
|
|
if (CacheSupportMultiRemove == false) {
|
|
log.LogWarning("FreeSql Warning: 低性能, IDistributedCache 没现实批量删除缓存 Cache.Remove(\"key1|key2\").");
|
|
Remove(key1, key2);
|
|
}
|
|
}
|
|
|
|
public Func<object, string> Serialize { get; set; }
|
|
public Func<string, Type, object> Deserialize { get; set; }
|
|
|
|
Func<JsonSerializerSettings> JsonSerializerSettings = () => {
|
|
var st = new JsonSerializerSettings();
|
|
st.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
|
|
st.DateFormatHandling = DateFormatHandling.IsoDateFormat;
|
|
st.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
|
|
return st;
|
|
};
|
|
string SerializeObject(object value) {
|
|
if (Serialize != null) return Serialize(value);
|
|
return JsonConvert.SerializeObject(value, this.JsonSerializerSettings());
|
|
}
|
|
T DeserializeObject<T>(string value) {
|
|
if (Deserialize != null) return (T) Deserialize(value, typeof(T));
|
|
return JsonConvert.DeserializeObject<T>(value, this.JsonSerializerSettings());
|
|
}
|
|
|
|
public void Set<T>(string key, T data, int timeoutSeconds = 0) {
|
|
if (string.IsNullOrEmpty(key)) return;
|
|
Cache.Set(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
|
}
|
|
public T Get<T>(string key) {
|
|
if (string.IsNullOrEmpty(key)) return default(T);
|
|
var value = Cache.Get(key);
|
|
if (value == null) return default(T);
|
|
return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
|
|
}
|
|
public string Get(string key) {
|
|
if (string.IsNullOrEmpty(key)) return null;
|
|
var value = Cache.Get(key);
|
|
if (value == null) return null;
|
|
return Encoding.UTF8.GetString(value);
|
|
}
|
|
|
|
async public Task SetAsync<T>(string key, T data, int timeoutSeconds = 0) {
|
|
if (string.IsNullOrEmpty(key)) return;
|
|
await Cache.SetAsync(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
|
}
|
|
async public Task<T> GetAsync<T>(string key) {
|
|
if (string.IsNullOrEmpty(key)) return default(T);
|
|
var value = await Cache.GetAsync(key);
|
|
if (value == null) return default(T);
|
|
return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
|
|
}
|
|
async public Task<string> GetAsync(string key) {
|
|
if (string.IsNullOrEmpty(key)) return null;
|
|
var value = await Cache.GetAsync(key);
|
|
if (value == null) return null;
|
|
return Encoding.UTF8.GetString(value);
|
|
}
|
|
|
|
public void Remove(params string[] keys) {
|
|
if (keys == null || keys.Length == 0) return;
|
|
var keysDistinct = keys.Distinct();
|
|
if (CacheSupportMultiRemove) Cache.Remove(string.Join("|", keysDistinct));
|
|
else foreach (var key in keysDistinct) Cache.Remove(key);
|
|
}
|
|
|
|
async public Task RemoveAsync(params string[] keys) {
|
|
if (keys == null || keys.Length == 0) return;
|
|
var keysDistinct = keys.Distinct();
|
|
if (CacheSupportMultiRemove) await Cache.RemoveAsync(string.Join("|", keysDistinct));
|
|
else foreach (var key in keysDistinct) await Cache.RemoveAsync(key);
|
|
}
|
|
|
|
public T Shell<T>(string key, int timeoutSeconds, Func<T> getData) {
|
|
if (timeoutSeconds <= 0) return getData();
|
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
|
var cacheValue = Cache.Get(key);
|
|
if (cacheValue != null) {
|
|
try {
|
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
|
return DeserializeObject<T>(txt);
|
|
} catch {
|
|
Cache.Remove(key);
|
|
throw;
|
|
}
|
|
}
|
|
var ret = getData();
|
|
Cache.Set(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
|
return ret;
|
|
}
|
|
|
|
public T Shell<T>(string key, string field, int timeoutSeconds, Func<T> getData) {
|
|
if (timeoutSeconds <= 0) return getData();
|
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
|
var hashkey = $"{key}:{field}";
|
|
var cacheValue = Cache.Get(hashkey);
|
|
if (cacheValue != null) {
|
|
try {
|
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
|
var value = DeserializeObject<(T, long)>(txt);
|
|
if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
|
|
} catch {
|
|
Cache.Remove(hashkey);
|
|
throw;
|
|
}
|
|
}
|
|
var ret = (getData(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
|
|
Cache.Set(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
|
|
return ret.Item1;
|
|
}
|
|
|
|
async public Task<T> ShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync) {
|
|
if (timeoutSeconds <= 0) return await getDataAsync();
|
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
|
var cacheValue = await Cache.GetAsync(key);
|
|
if (cacheValue != null) {
|
|
try {
|
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
|
return DeserializeObject<T>(txt);
|
|
} catch {
|
|
await Cache.RemoveAsync(key);
|
|
throw;
|
|
}
|
|
}
|
|
var ret = await getDataAsync();
|
|
await Cache.SetAsync(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
|
return ret;
|
|
}
|
|
|
|
async public Task<T> ShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync) {
|
|
if (timeoutSeconds <= 0) return await getDataAsync();
|
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
|
var hashkey = $"{key}:{field}";
|
|
var cacheValue = await Cache.GetAsync(hashkey);
|
|
if (cacheValue != null) {
|
|
try {
|
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
|
var value = DeserializeObject<(T, long)>(txt);
|
|
if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
|
|
} catch {
|
|
await Cache.RemoveAsync(hashkey);
|
|
throw;
|
|
}
|
|
}
|
|
var ret = (await getDataAsync(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
|
|
await Cache.SetAsync(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
|
|
return ret.Item1;
|
|
}
|
|
}
|
|
}
|