6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) + game logic (GameFix/GameDAL/ServerData) + network layer (NetWorkMessage) + data layer (ObjectModel) + utilities (MrWu/Core/Config/CloudAPI/dll) + adapters (zyxAdapter/base) .NET 8.0 C# solution, 16 projects, 958 source files
1200 lines
68 KiB
C#
1200 lines
68 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using MrWu.Debug;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using StackExchange.Redis;
|
||
|
||
namespace Server.DB.Redis {
|
||
public static class RedisCachingHelper {
|
||
|
||
/// <summary>
|
||
/// 默认缓存过期时间,单位:秒
|
||
/// </summary>
|
||
public static int ExpireBySecond { get; set; } = 3600;// 86400;
|
||
|
||
/*
|
||
*
|
||
* 主要用法 GetOrAdd
|
||
* RedisType 参数表示 Redis 存储类型,当前支持,String/Hash/List
|
||
* 泛型类型支持
|
||
* String 全部JSON支持的类型
|
||
* Hash 除简单类型外,所有有无参构造方法的类型, 注意:实现IDictionary的类型只支持IDictionary成员,不支持继承扩展属性/字段;
|
||
* List 数组 以及 实现 IList 接口类型有无参构造的类型;
|
||
*
|
||
* acquire Redis 未命中时获取对象的委托方法, 必须返回一个有效对象,以避免缓存穿透
|
||
* key Redis 标识关键字
|
||
* dbIdx Redis Database Id
|
||
* throwIfKeyTypeWrong 在从Redis获取对象时 Redis Key类型错误或对象成员类型错误时是否抛异常, 无此参数的重载默认为 true。
|
||
* 注意:所有操作redis的网络异常将被屏蔽,所有由类型不匹配和不支持类型将会抛 ArgumentOutOfRangeException 异常
|
||
*
|
||
* 缓存过期时间指定,可以使用有expire参数的重载以固定值指定,也可以使用 acquire 参数类型为 Func<Tuple<T, int>> 的重载以灵活方式指定
|
||
*
|
||
* 其他:使用本扩展方法,将会对象及对象成员的类型保持强类型特性,存储在redis上的数据是经过JSON格式包装,修改数据必须注意格式。
|
||
**/
|
||
|
||
|
||
#region 扩展方法
|
||
|
||
#region GetOrAdd Generic Sync
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, TimeSpan expire) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, expire, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, int dbIdx, int expireBySecond) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, int dbIdx, TimeSpan expire) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, expire, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, expire, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<T> acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = acquire();
|
||
db.AddToRedis(redisType, key, value, expire);
|
||
return value;
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, int>> acquire) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, true);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, int>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, true);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, int>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, int>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = acquire();
|
||
db.AddToRedis(redisType, key, value.Item1, TimeSpan.FromSeconds(value.Item2));
|
||
return value.Item1;
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, TimeSpan>> acquire) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, TimeSpan>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, TimeSpan>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(redisType, key, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Tuple<T, TimeSpan>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = acquire();
|
||
db.AddToRedis(redisType, key, value.Item1, value.Item2);
|
||
return value.Item1;
|
||
}
|
||
#endregion
|
||
|
||
#region GetOrAdd Generic Async
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, TimeSpan expire) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, expire, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, int dbIdx, int expireBySecond) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, int dbIdx, TimeSpan expire) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, expire, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, expire, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static async Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<T>> acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = await acquire.Invoke();
|
||
db.AddToRedis(redisType, key, value, expire);
|
||
return value;
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, int>>> acquire) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, true);
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, int>>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, true);
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, int>>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static async Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, int>>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = await acquire();
|
||
db.AddToRedis(redisType, key, value.Item1, TimeSpan.FromSeconds(value.Item2));
|
||
return value.Item1;
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, TimeSpan>>> acquire) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, TimeSpan>>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, TimeSpan>>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
public static async Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func<Task<Tuple<T, TimeSpan>>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = await acquire();
|
||
db.AddToRedis(redisType, key, value.Item1, value.Item2);
|
||
return value.Item1;
|
||
}
|
||
#endregion
|
||
|
||
#region GetOrAdd RedisHash Sync
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, TimeSpan expire) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, expire, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, int dbIdx, int expireBySecond) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, int dbIdx, TimeSpan expire) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, expire, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, expire, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<T> acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = acquire();
|
||
db.AddToRedis(key, field, keyExists, value, expire);
|
||
return value;
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, int>> acquire) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, true);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, int>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, true);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, int>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, int>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = acquire();
|
||
db.AddToRedis(key, field, keyExists, value.Item1, TimeSpan.FromSeconds(value.Item2));
|
||
return value.Item1;
|
||
}
|
||
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, TimeSpan>> acquire) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, TimeSpan>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, true);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, TimeSpan>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
public static T GetOrAdd<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Tuple<T, TimeSpan>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = acquire();
|
||
db.AddToRedis(key, field, keyExists, value.Item1, value.Item2);
|
||
return value.Item1;
|
||
}
|
||
|
||
public static bool TryGet<T>(this IDatabase db, RedisKey key, RedisValue field, out bool keyExists, out T outValue, bool throwIfKeyTypeWrong) {
|
||
outValue = default(T);
|
||
keyExists = false;
|
||
try {
|
||
var transaction = db.CreateTransaction();
|
||
var task1 = transaction.KeyTimeToLiveAsync(key);
|
||
var task2 = transaction.HashGetAsync(key, field);
|
||
if (transaction.Execute()) {
|
||
var task1Result = task1.Result;
|
||
keyExists = task1Result.HasValue && task1Result.Value > TimeSpan.Zero;
|
||
var redisValue = task2.Result;
|
||
if (!keyExists || redisValue.IsNullOrEmpty) {
|
||
return false;
|
||
}
|
||
return GetObjectFromJsonWrapper(redisValue, out outValue, throwIfKeyTypeWrong, true, throwIfKeyTypeWrong);
|
||
}
|
||
} catch (Exception ex) {
|
||
Console.WriteLine(ex);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public static bool AddToRedis(this IDatabase db, RedisKey key, RedisValue field, bool keyExists, object value, TimeSpan timeSpan) {
|
||
try {
|
||
var transaction = db.CreateTransaction();
|
||
transaction.HashSetAsync(key, field, GetStringOfJsonWrapper(value));
|
||
if (!keyExists) {
|
||
transaction.KeyExpireAsync(key, timeSpan);
|
||
}
|
||
return transaction.Execute();
|
||
} catch (Exception ex) {
|
||
Console.WriteLine(ex);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region GetOrAdd RedisHash Async
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, TimeSpan expire) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, expire, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, int dbIdx, int expireBySecond) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, int dbIdx, TimeSpan expire) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, expire, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, expire, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static async Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<T>> acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = await acquire();
|
||
db.AddToRedis(key, field, keyExists, value, expire);
|
||
return value;
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, int>>> acquire) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, true);
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, int>>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, true);
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, int>>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static async Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, int>>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = await acquire();
|
||
db.AddToRedis(key, field, keyExists, value.Item1, TimeSpan.FromSeconds(value.Item2));
|
||
return value.Item1;
|
||
}
|
||
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, TimeSpan>>> acquire) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, TimeSpan>>> acquire, int dbIdx) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, true);
|
||
}
|
||
public static Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, TimeSpan>>> acquire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.GetOrAddAsync(key, field, acquire, -1, throwIfKeyTypeWrong);
|
||
}
|
||
public static async Task<T> GetOrAddAsync<T>(this DbStyle dbStyle, RedisKey key, RedisValue field, Func<Task<Tuple<T, TimeSpan>>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
if (db.TryGet<T>(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
|
||
return outValue;
|
||
}
|
||
var value = await acquire();
|
||
db.AddToRedis(key, field, keyExists, value.Item1, value.Item2);
|
||
return value.Item1;
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region UpdateOrAdd
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, -1, expire, true);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, expire, true);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAdd(redisType, key, value, -1, expire, throwIfKeyTypeWrong);
|
||
}
|
||
public static T UpdateOrAdd<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
var existRedisKeyType = RedisType.None;
|
||
try {
|
||
//获取原有数据类型
|
||
existRedisKeyType = db.KeyType(key);
|
||
} catch (Exception ex) {
|
||
Debug.Error($"RedisCachingHelper UpdateOrAdd db.KeyType fail, key: {key}, ex: {ex}");
|
||
}
|
||
//检查原有key数据类型
|
||
if (existRedisKeyType != RedisType.None && existRedisKeyType != redisType && throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"redis key 当前存储的数据类型为:{existRedisKeyType}, 新类型为:{redisType}");
|
||
}
|
||
|
||
db.AddToRedis(redisType, key, value, expire);
|
||
return value;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region UpdateOrAdd Async
|
||
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, expire, true);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, expire, true);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
|
||
}
|
||
public static Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, expire, throwIfKeyTypeWrong);
|
||
}
|
||
public static async Task<T> UpdateOrAddAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
var existRedisKeyType = RedisType.None;
|
||
try {
|
||
//获取原有数据类型
|
||
existRedisKeyType = await db.KeyTypeAsync(key);
|
||
} catch (Exception ex) {
|
||
Debug.Error($"RedisCachingHelper UpdateOrAdd db.KeyType fail, key: {key}, ex: {ex}");
|
||
}
|
||
//检查原有key数据类型
|
||
if (existRedisKeyType != RedisType.None && existRedisKeyType != redisType && throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"redis key 当前存储的数据类型为:{existRedisKeyType}, 新类型为:{redisType}");
|
||
}
|
||
|
||
db.AddToRedis(redisType, key, value, expire);
|
||
return value;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Delete
|
||
|
||
public static bool Delete(this DbStyle dbStyle, int dbIdx = -1, params RedisKey[] keys) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
return db.KeyDelete(keys) == keys.Length;
|
||
}
|
||
public static async Task<bool> DeleteAsync(this DbStyle dbStyle, int dbIdx = -1, params RedisKey[] keys) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
var count = await db.KeyDeleteAsync(keys);
|
||
return count == keys.Length;
|
||
}
|
||
|
||
public static IDatabase GetDataBase(this DbStyle dbStyle, int dbIdx) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
return db;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region TryGet
|
||
public static bool TryGet<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue) {
|
||
return dbStyle.TryGet(redisType, key, out outValue, -1, true);
|
||
}
|
||
|
||
public static bool TryGet<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue, int dbIdx) {
|
||
return dbStyle.TryGet(redisType, key, out outValue, dbIdx, true);
|
||
}
|
||
public static bool TryGet<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
|
||
return dbStyle.TryGet(redisType, key, out outValue, -1, throwIfKeyTypeWrong);
|
||
}
|
||
public static bool TryGet<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue, int dbIdx, bool throwIfKeyTypeWrong) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
return db.TryGet(redisType, key, out outValue, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
public static bool TryGet<T>(this IDatabase db, RedisType redisType, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
|
||
EnsureKeyNotEmptyOrNULL(key);
|
||
switch (redisType) {
|
||
case RedisType.String:
|
||
return db.TryGetString(key, out outValue, throwIfKeyTypeWrong);
|
||
case RedisType.Hash:
|
||
return db.TryGetHash(key, out outValue, throwIfKeyTypeWrong);
|
||
case RedisType.List:
|
||
return db.TryGetList(key, out outValue, throwIfKeyTypeWrong);
|
||
case RedisType.Set:
|
||
case RedisType.SortedSet:
|
||
throw new NotSupportedException(); //return db.TryGetSet(key, out outValue, throwIfKeyTypeWrong);
|
||
case RedisType.None:
|
||
//case RedisType.Stream:
|
||
case RedisType.Unknown:
|
||
default:
|
||
throw new NotSupportedException($"key: {key}, redisType: {redisType}");
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region AddToRedis
|
||
public static bool AddToRedis<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
|
||
return dbStyle.AddToRedis(redisType, key, value, TimeSpan.FromSeconds(ExpireBySecond), -1);
|
||
}
|
||
public static bool AddToRedis<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire) {
|
||
return dbStyle.AddToRedis(redisType, key, value, TimeSpan.FromSeconds(expire), -1);
|
||
}
|
||
public static bool AddToRedis<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire, int dbIdx) {
|
||
return dbStyle.AddToRedis(redisType, key, value, TimeSpan.FromSeconds(expire), dbIdx);
|
||
}
|
||
public static bool AddToRedis<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
|
||
return dbStyle.AddToRedis(redisType, key, value, expire, -1);
|
||
}
|
||
public static bool AddToRedis<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, int dbIdx) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
return db.AddToRedis(redisType, key, value, expire);
|
||
}
|
||
|
||
public static bool AddToRedis<T>(this IDatabase db, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
|
||
EnsureKeyNotEmptyOrNULL(key);
|
||
switch (redisType) {
|
||
case RedisType.String:
|
||
return db.AddStringToRedis(key, value, expire);
|
||
case RedisType.Hash:
|
||
return db.AddHashToRedis(key, value, expire);
|
||
case RedisType.List:
|
||
return db.AddListToRedis(key, value as IEnumerable, expire);
|
||
case RedisType.Set:
|
||
case RedisType.SortedSet:
|
||
throw new NotSupportedException(); //return db.AddSetToRedis(key, value, expire);
|
||
case RedisType.None:
|
||
//case RedisType.Stream:
|
||
case RedisType.Unknown:
|
||
default:
|
||
throw new NotSupportedException($"key: {key}, redisType: {redisType}");
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region AddToRedis Async
|
||
public static Task<bool> AddToRedisAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
|
||
return dbStyle.AddToRedisAsync(redisType, key, value, TimeSpan.FromSeconds(ExpireBySecond), -1);
|
||
}
|
||
public static Task<bool> AddToRedisAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire) {
|
||
return dbStyle.AddToRedisAsync(redisType, key, value, TimeSpan.FromSeconds(expire), -1);
|
||
}
|
||
public static Task<bool> AddToRedisAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire, int dbIdx) {
|
||
return dbStyle.AddToRedisAsync(redisType, key, value, TimeSpan.FromSeconds(expire), dbIdx);
|
||
}
|
||
public static Task<bool> AddToRedisAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
|
||
return dbStyle.AddToRedisAsync(redisType, key, value, expire, -1);
|
||
}
|
||
public static Task<bool> AddToRedisAsync<T>(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, int dbIdx) {
|
||
var db = redisManager.GetDataBase(dbStyle, dbIdx);
|
||
return db.AddToRedisAsync(redisType, key, value, expire);
|
||
}
|
||
|
||
public static Task<bool> AddToRedisAsync<T>(this IDatabase db, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
|
||
EnsureKeyNotEmptyOrNULL(key);
|
||
switch (redisType) {
|
||
case RedisType.String:
|
||
return db.AddStringToRedisAsync(key, value, expire);
|
||
case RedisType.Hash:
|
||
return db.AddHashToRedisAsync(key, value, expire);
|
||
case RedisType.List:
|
||
return db.AddListToRedisAsync(key, value as IEnumerable, expire);
|
||
case RedisType.Set:
|
||
case RedisType.SortedSet:
|
||
throw new NotSupportedException(); //return db.AddSetToRedis(key, value, expire);
|
||
case RedisType.None:
|
||
//case RedisType.Stream:
|
||
case RedisType.Unknown:
|
||
default:
|
||
throw new NotSupportedException($"key: {key}, redisType: {redisType}");
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
public static IDatabase GetRedisDataBase(this DbStyle style, int dbIdx = -1) => redisManager.GetDataBase(style, dbIdx);
|
||
#endregion
|
||
|
||
#region 扩展功能实现
|
||
|
||
#region 以 Redis String 类型存储
|
||
static bool TryGetString<T>(this IDatabase db, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
|
||
outValue = default(T);
|
||
if (!db.GetFromRedis(key, throwIfKeyTypeWrong, p => p.StringGet(key), out var redisValue)) {
|
||
return false;
|
||
}
|
||
//检查原始类型与目标类型是否一致
|
||
return !redisValue.IsNullOrEmpty && GetObjectFromJsonWrapper(redisValue, out outValue, throwIfKeyTypeWrong, true, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
static bool AddStringToRedis<T>(this IDatabase db, RedisKey key, T value, TimeSpan expire) {
|
||
var stringValue = GetStringOfJsonWrapper(value);
|
||
return db.ExecuctRedisTransaction(key, expire, false, transaction => transaction.StringSetAsync(key, stringValue));
|
||
}
|
||
|
||
static Task<bool> AddStringToRedisAsync<T>(this IDatabase db, RedisKey key, T value, TimeSpan expire) {
|
||
var stringValue = GetStringOfJsonWrapper(value);
|
||
return db.ExecuctRedisTransactionAsync(key, expire, false, transaction => transaction.StringSetAsync(key, stringValue));
|
||
}
|
||
#endregion
|
||
|
||
#region 以 Redis Hash 类型存储
|
||
public readonly static string hash_type_field_name = "_@_type_@_name_@_";
|
||
static bool TryGetHash<T>(this IDatabase db, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
|
||
outValue = default(T);
|
||
|
||
if (!db.GetFromRedis(key, throwIfKeyTypeWrong, p => p.HashGetAll(key), out var hashEntries)) {
|
||
return false;
|
||
}
|
||
|
||
|
||
if (hashEntries.Length == 0) {
|
||
return false;
|
||
}
|
||
|
||
var targetType = typeof(T);
|
||
var item = hashEntries.SingleOrDefault(p => hash_type_field_name.Equals(p.Name)).Value;
|
||
if (item.IsNullOrEmpty) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"Hash 原始类型描述为空:目标类型:{ targetType.FullName}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
Type originType = null;
|
||
try {
|
||
originType = Type.GetType(item);
|
||
} catch (Exception ex) {
|
||
Debug.Error($"TryGetHash Type.GetType fail, type: {item}, ex: {ex}");
|
||
}
|
||
if (originType == null) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无法获取原始类型:{originType}");
|
||
}
|
||
return false;
|
||
}
|
||
hashEntries = hashEntries.Where(p => !string.Equals(p.Name, hash_type_field_name)).ToArray();
|
||
|
||
//检查原始类型与目标类型是否一致
|
||
if (!originType.Equals(targetType)) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的目标类型:原始类型:{originType.FullName}, 目标类型:{targetType.FullName}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
outValue = Activator.CreateInstance<T>();
|
||
var dictionaryGeneric = targetType.GetInterface(typeOfIDictionaryGeneric.Name);
|
||
if (dictionaryGeneric != null) {
|
||
//目标类型是 IDictionary<,>
|
||
var genericArgs = dictionaryGeneric.GetGenericArguments();
|
||
var method = TryGetIDictionaryGenericMethod.MakeGenericMethod(genericArgs);
|
||
var succ = (bool)method.Invoke(null, new object[] { outValue, hashEntries });
|
||
if (!succ) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"TryGetHash 解释元素类型不未成功!");
|
||
}
|
||
}
|
||
return succ;
|
||
} else if (outValue is IDictionary dictionary) {
|
||
//目标类型是 IDictionary
|
||
return LoadDictionaryMembersFromHashEntries(hashEntries, dictionary, targetType, throwIfKeyTypeWrong);
|
||
} else {
|
||
//目标类型是非 IDictionary 类型
|
||
return LoadObjectMembersFromHashEntries(hashEntries, outValue, targetType, throwIfKeyTypeWrong);
|
||
}
|
||
}
|
||
static readonly Type typeOfRedisCachingHelper = typeof(RedisCachingHelper);
|
||
static Type typeOfObject { get; } = typeof(object);
|
||
static Type typeOfCollectionGeneric { get; } = typeof(Collection<>);
|
||
static Type typeOfIListGeneric { get; } = typeof(IList<>);
|
||
static Type typeOfIList { get; } = typeof(IList);
|
||
static Type typeOfIDictionaryGeneric { get; } = typeof(IDictionary<,>);
|
||
|
||
static bool LoadDictionaryMembersFromHashEntries(HashEntry[] hashEntries, IDictionary dictionary, Type targetType, bool throwIfKeyTypeWrong) {
|
||
foreach (var item in hashEntries) {
|
||
if (!item.Name.IsNullOrEmpty) {
|
||
try {
|
||
if (GetObjectFromJsonWrapper(item.Name, out var dictionaryKeyname) && GetObjectFromJsonWrapper(item.Value, out var dictValue)) {
|
||
dictionary.Add(dictionaryKeyname, dictValue);
|
||
}
|
||
} catch (Exception ex) {
|
||
Debug.Error($"StaticCachingHelper LoadDictionaryMembersFromHashEntries fail, ex: {ex}");
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"解析数据发生异常,目标类型:{targetType.FullName}!", ex);
|
||
}
|
||
return false;
|
||
}
|
||
} else {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的原始成员名称, Name:{item.Name}, Value:{targetType.FullName}");
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool LoadObjectMembersFromHashEntries(HashEntry[] hashEntries, object instance, Type targetType, bool throwIfKeyTypeWrong) {
|
||
var fields = targetType.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(p => !p.IsInitOnly).ToArray();
|
||
var props = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0).ToArray();
|
||
|
||
if (fields.Length == 0 && props.Length == 0) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"类型:{targetType} 没有公开的可读写字段或属性");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
foreach (var item in hashEntries) {
|
||
if (!item.Value.IsNullOrEmpty) {
|
||
Action<object, object> valueSetAction = null;
|
||
Type memberType = null;
|
||
var fieldInfo = fields.SingleOrDefault(p => p.Name == item.Name);
|
||
if (fieldInfo != null) {
|
||
valueSetAction = fieldInfo.SetValue;
|
||
memberType = fieldInfo.FieldType;
|
||
} else {
|
||
var propInfo = props.SingleOrDefault(p => p.Name == item.Name);
|
||
if (propInfo != null) {
|
||
valueSetAction = propInfo.SetValue;
|
||
memberType = propInfo.PropertyType;
|
||
} else {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的原始成员名称, Name:{item.Name}, Value:{item.Value}");
|
||
}
|
||
//缓存的数据对象成员与当前的类型的成员不一致,放弃当前缓存数据
|
||
return false;
|
||
}
|
||
}
|
||
if (GetObjectFromJsonWrapper(item.Value, out var memberValue, out var memberOriginType, throwIfKeyTypeWrong, false) && memberType.IsAssignableFrom(memberOriginType)) {
|
||
valueSetAction.Invoke(instance, memberValue);
|
||
} else {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的原始成员类型与当前成员类型匹配,当前成员类型:{item}, 原始成员类型:{memberOriginType}");
|
||
}
|
||
return false;
|
||
}
|
||
} else {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的原始数据, Name:{item.Name}, Value:{item.Value}");
|
||
}
|
||
//缓存的数据对象成员与当前的类型的成员不一致,放弃当前缓存数据
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static MethodInfo TryGetIDictionaryGenericMethod { get; } = typeOfRedisCachingHelper.GetMethod(nameof(TryGetIDictionaryGeneric), BindingFlags.Static | BindingFlags.NonPublic);
|
||
static bool TryGetIDictionaryGeneric<TKey, TValue>(IDictionary<TKey, TValue> dictionary, HashEntry[] hashEntries) {
|
||
var keyType = typeof(TKey);
|
||
var valueType = typeof(TValue);
|
||
foreach (var hashEntry in hashEntries) {
|
||
if (hashEntry.Name.IsNullOrEmpty || hashEntry.Value.IsNullOrEmpty) {
|
||
return false;
|
||
} else if (GetObjectFromJsonWrapper(hashEntry.Name, out var key, out var originKeyType, false, false) && GetObjectFromJsonWrapper(hashEntry.Value, out var value, out var originValueType, false, false)) {
|
||
if (!(keyType.IsAssignableFrom(originKeyType) || (key == null && (keyType.IsClass || keyType.IsInterface)))) {//反序列化成员数据失败,有可能成员类型已改变
|
||
Debug.Error($"StaticCachingHelper TryGetIDictionaryGeneric fail, hashEntry.Name: {hashEntry.Name}, 类型不正确: 要求元素类型:{keyType}, 原始数据元素类型:{originKeyType}");
|
||
return false;
|
||
}
|
||
if (!(valueType.IsAssignableFrom(originValueType) || (value == null && (valueType.IsClass || valueType.IsInterface)))) {
|
||
Debug.Error($"StaticCachingHelper TryGetIDictionaryGeneric fail, hashEntry.Value: {hashEntry.Value}, 类型不正确: 要求元素类型:{valueType}, 原始数据元素类型:{originValueType}");
|
||
return false;
|
||
}
|
||
dictionary.Add((TKey)key, (TValue)value);//反序列化成员数据失败,有可能成员类型已改变
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool AddHashToRedis<T>(this IDatabase db, RedisKey key, T value, TimeSpan expire) {
|
||
if (value == null) {
|
||
throw new ArgumentNullException("value is null!");
|
||
}
|
||
var type = value.GetType();
|
||
//为了保持缓存对象强类型特性,将泛型类型一并写入,以便取出时检查
|
||
var entrys = new Collection<HashEntry>();
|
||
entrys.Add(new HashEntry(hash_type_field_name, type.AssemblyQualifiedName));
|
||
var dictionary = value as IDictionary;
|
||
if (dictionary != null) {
|
||
if (dictionary.IsReadOnly) {
|
||
throw new ArgumentOutOfRangeException("无法使用只读类型对象!");
|
||
}
|
||
//IDictionary 类型
|
||
foreach (DictionaryEntry item in dictionary) {
|
||
entrys.Add(new HashEntry(GetStringOfJsonWrapper(item.Key), GetStringOfJsonWrapper(item.Value)));
|
||
}
|
||
} else {
|
||
//class 或 struct
|
||
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(p => !p.IsInitOnly).ToArray();
|
||
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0).ToArray();
|
||
|
||
if (fields.Length == 0 && props.Length == 0) {
|
||
throw new ArgumentOutOfRangeException("Redis Hash 不支持简单类型和无成员类型, 必须有公开的可读写内部成员!");
|
||
}
|
||
foreach (var fieldInfo in fields) {
|
||
var name = fieldInfo.Name;
|
||
var fieldValue = fieldInfo.GetValue(value);
|
||
entrys.Add(new HashEntry(name, GetStringOfJsonWrapper(fieldValue)));
|
||
}
|
||
foreach (var propInfo in props) {
|
||
var name = propInfo.Name;
|
||
var propValue = propInfo.GetValue(value);
|
||
entrys.Add(new HashEntry(name, GetStringOfJsonWrapper(propValue)));
|
||
}
|
||
}
|
||
return db.ExecuctRedisTransaction(key, expire, true, transaction => transaction.HashSetAsync(key, entrys.ToArray()));
|
||
}
|
||
|
||
static Task<bool> AddHashToRedisAsync<T>(this IDatabase db, RedisKey key, T value, TimeSpan expire) {
|
||
if (value == null) {
|
||
throw new ArgumentNullException("value is null!");
|
||
}
|
||
var type = value.GetType();
|
||
//为了保持缓存对象强类型特性,将泛型类型一并写入,以便取出时检查
|
||
var entrys = new Collection<HashEntry>();
|
||
entrys.Add(new HashEntry(hash_type_field_name, type.AssemblyQualifiedName));
|
||
var dictionary = value as IDictionary;
|
||
if (dictionary != null) {
|
||
if (dictionary.IsReadOnly) {
|
||
throw new ArgumentOutOfRangeException("无法使用只读类型对象!");
|
||
}
|
||
//IDictionary 类型
|
||
foreach (DictionaryEntry item in dictionary) {
|
||
entrys.Add(new HashEntry(GetStringOfJsonWrapper(item.Key), GetStringOfJsonWrapper(item.Value)));
|
||
}
|
||
} else {
|
||
//class 或 struct
|
||
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(p => !p.IsInitOnly).ToArray();
|
||
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0).ToArray();
|
||
|
||
if (fields.Length == 0 && props.Length == 0) {
|
||
throw new ArgumentOutOfRangeException("Redis Hash 不支持简单类型和无成员类型, 必须有公开的可读写内部成员!");
|
||
}
|
||
foreach (var fieldInfo in fields) {
|
||
var name = fieldInfo.Name;
|
||
var fieldValue = fieldInfo.GetValue(value);
|
||
entrys.Add(new HashEntry(name, GetStringOfJsonWrapper(fieldValue)));
|
||
}
|
||
foreach (var propInfo in props) {
|
||
var name = propInfo.Name;
|
||
var propValue = propInfo.GetValue(value);
|
||
entrys.Add(new HashEntry(name, GetStringOfJsonWrapper(propValue)));
|
||
}
|
||
}
|
||
return db.ExecuctRedisTransactionAsync(key, expire, true, transaction => { transaction.HashSetAsync(key, entrys.ToArray()); return Task.FromResult(true); });
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 以 Redis List 类型存储
|
||
static bool TryGetList<T>(this IDatabase db, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
|
||
outValue = default(T);
|
||
|
||
if (!db.GetFromRedis(key, throwIfKeyTypeWrong, p => p.ListRange(key), out var redisValues)) {
|
||
return false;
|
||
}
|
||
|
||
if (redisValues.Length == 0) {
|
||
return false;
|
||
}
|
||
//获取第一个元素
|
||
var typeString = redisValues.First();
|
||
if (typeString.IsNullOrEmpty) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的目标类型:typeString is empty");
|
||
}
|
||
return false;
|
||
}
|
||
Type originType = null;
|
||
try {
|
||
//获取原始数据类型
|
||
originType = Type.GetType(typeString);
|
||
} catch (Exception ex) {
|
||
Debug.Error($"TryGetList Type.GetType fail, type: {typeString}, ex: {ex}");
|
||
}
|
||
if (originType == null) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无法获取原始类型:{originType}");
|
||
}
|
||
return false;
|
||
}
|
||
redisValues = redisValues.Skip(1).ToArray();
|
||
|
||
var targetType = typeof(T);
|
||
if (!originType.Equals(targetType)) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的目标类型:原始类型:{originType.FullName}, 目标类型:{targetType.FullName}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//检查原始类型与目标类型是否一致
|
||
var listInterface = targetType.GetInterface(typeOfIListGeneric.Name);
|
||
if (listInterface != null) {
|
||
var genericArgs = listInterface.GenericTypeArguments[0];
|
||
//如果目标类型是数组,先准备一个通用集合接收数组成员,
|
||
var collectionType = targetType.IsArray ? typeOfCollectionGeneric.MakeGenericType(genericArgs) : targetType;
|
||
//创建目标对象或接收集合
|
||
var list = Activator.CreateInstance(collectionType);
|
||
//创建泛型方法
|
||
var method = TryGetListGenericMethodInfo.MakeGenericMethod(collectionType, genericArgs);
|
||
//执行泛型方法
|
||
var succ = (bool)method.Invoke(null, new object[] { list, redisValues });
|
||
if (!succ) {
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"TryGetList 解释成员类型不未成功!");
|
||
}
|
||
return false;
|
||
}
|
||
//处理目标类型或接收集合结果
|
||
outValue = !targetType.IsArray ? (T)list : (T)ListToArrayMethodInfo.MakeGenericMethod(genericArgs).Invoke(null, new[] { list });
|
||
return succ;
|
||
} else {
|
||
outValue = Activator.CreateInstance<T>();
|
||
if (outValue is IList list) {
|
||
return TryGetList(list, redisValues, throwIfKeyTypeWrong);
|
||
}
|
||
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的目标类型:原始类型:{originType.FullName}, 目标类型:{targetType.FullName}, 目标类型必须实现 {typeOfIList.FullName} 或 {typeOfIListGeneric.FullName}");
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static MethodInfo ListToArrayMethodInfo { get; } = typeOfRedisCachingHelper.GetMethod(nameof(ListToArray), BindingFlags.Static | BindingFlags.NonPublic);
|
||
static T[] ListToArray<T>(IList<T> list) {
|
||
return list.ToArray();
|
||
}
|
||
|
||
static MethodInfo TryGetListGenericMethodInfo { get; } = typeOfRedisCachingHelper.GetMethod(nameof(TryGetListGeneric), BindingFlags.Static | BindingFlags.NonPublic);
|
||
|
||
static bool TryGetListGeneric<TCollection, TElement>(TCollection list, RedisValue[] redisValues) where TCollection : IList<TElement> {
|
||
var elementType = typeof(TElement);
|
||
foreach (var redisValue in redisValues) {
|
||
if (!redisValue.IsNullOrEmpty) {
|
||
if (GetObjectFromJsonWrapper(redisValue, out var value, out var originelementType, false, false)) {
|
||
if (elementType.IsAssignableFrom(originelementType) || (value == null && (elementType.IsClass || elementType.IsInterface))) {//反序列化成员数据失败,有可能成员类型已改变
|
||
list.Add((TElement)value);
|
||
continue;
|
||
} else {
|
||
Debug.Error($"StaticCachingHelper TryGetListGeneric fail, redisValue: {redisValue}, 元素类型不正确: 要求元素类型:{elementType}, 数据元素类型:{originelementType}");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool TryGetList(IList list, RedisValue[] redisValues, bool throwIfKeyTypeWrong) {
|
||
foreach (var redisValue in redisValues) {
|
||
if (GetObjectFromJsonWrapper(redisValue, out var value, throwIfKeyTypeWrong, throwIfKeyTypeWrong)) {
|
||
list.Add(value);
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static bool AddListToRedis<T>(this IDatabase db, RedisKey key, T obj, TimeSpan expire) where T : IEnumerable {
|
||
if (obj == null) {
|
||
throw new ArgumentOutOfRangeException("list is null or not is IList or IList<> type!");
|
||
}
|
||
if (!(obj is IList list)) {
|
||
throw new ArgumentOutOfRangeException("list is null or not is IList or IList<> type!");
|
||
}
|
||
var valueList = new Collection<RedisValue>();
|
||
valueList.Add(list.GetType().AssemblyQualifiedName);
|
||
foreach (var item in list) {
|
||
valueList.Add(GetStringOfJsonWrapper(item));
|
||
}
|
||
return db.ExecuctRedisTransaction(key, expire, true, transaction => transaction.ListRightPushAsync(key, valueList.ToArray()));
|
||
}
|
||
|
||
static Task<bool> AddListToRedisAsync<T>(this IDatabase db, RedisKey key, T obj, TimeSpan expire) where T : IEnumerable {
|
||
if (obj == null) {
|
||
throw new ArgumentOutOfRangeException("list is null or not is IList or IList<> type!");
|
||
}
|
||
if (!(obj is IList list)) {
|
||
throw new ArgumentOutOfRangeException("list is null or not is IList or IList<> type!");
|
||
}
|
||
var valueList = new Collection<RedisValue>();
|
||
valueList.Add(list.GetType().AssemblyQualifiedName);
|
||
foreach (var item in list) {
|
||
valueList.Add(GetStringOfJsonWrapper(item));
|
||
}
|
||
return db.ExecuctRedisTransactionAsync(key, expire, true, async transaction => (await transaction.ListRightPushAsync(key, valueList.ToArray())) > 0);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 以 Redis Set 类型存储
|
||
|
||
#endregion
|
||
|
||
#region JSON 数据包装
|
||
public static string GetStringOfJsonWrapper(object value) {
|
||
return JToken.FromObject(new { type = (value == null ? typeOfObject : value.GetType()).AssemblyQualifiedName, value }).ToString(Formatting.None);
|
||
}
|
||
|
||
static bool GetObjectFromJsonWrapper(string jsonString, out object value, bool throwIfEmpty = true, bool throwIfJsonStringWrong = true) {
|
||
if (GetObjectFromJsonWrapper(jsonString, out value, out var t, throwIfEmpty, throwIfJsonStringWrong)) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static bool GetObjectFromJsonWrapper<T>(string jsonString, out T value, bool throwIfKeyTypeWrong, bool throwIfEmpty, bool throwIfJsonStringWrong) {
|
||
if (GetObjectFromJsonWrapper(jsonString, out var obj, out var originelementType, throwIfEmpty, throwIfJsonStringWrong)) {
|
||
var targetType = typeof(T);
|
||
if (targetType.IsAssignableFrom(originelementType)) {
|
||
value = (T)obj;
|
||
return true;
|
||
} else if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"无效的目标类型:原始数据类型:{originelementType.FullName},目标类型:{targetType.FullName}");
|
||
}
|
||
}
|
||
value = default(T);
|
||
return false;
|
||
}
|
||
|
||
static bool GetObjectFromJsonWrapper(string jsonString, out object value, out Type type, bool throwIfEmpty, bool throwIfJsonStringWrong) {
|
||
value = null;
|
||
type = null;
|
||
if (string.IsNullOrEmpty(jsonString)) {
|
||
if (throwIfEmpty) {
|
||
throw new ArgumentOutOfRangeException("GetObjectFromJsonWrapper jsonString is empty or null!");
|
||
}
|
||
return false;
|
||
}
|
||
try {
|
||
var json = JObject.Parse(jsonString);
|
||
if (json.TryGetValue("type", out var jType) && json.TryGetValue("value", out var jvalue)) {
|
||
type = Type.GetType(jType.ToObject<string>());
|
||
if (type != null) {
|
||
value = jvalue.ToObject(type);
|
||
return true;
|
||
}
|
||
}
|
||
} catch (Exception ex) {
|
||
Debug.Error("GetObjectFromJsonWrapper fail, ex: " + ex);
|
||
}
|
||
if (throwIfJsonStringWrong) {
|
||
throw new ArgumentOutOfRangeException("GetObjectFromJsonWrapper jsonString: " + jsonString);
|
||
}
|
||
return false;
|
||
}
|
||
#endregion
|
||
|
||
#region common
|
||
static void EnsureKeyNotEmptyOrNULL(RedisKey key) {
|
||
if (string.IsNullOrEmpty(key)) {
|
||
throw new ArgumentOutOfRangeException("key is null or empty!");
|
||
}
|
||
}
|
||
|
||
static bool GetFromRedis<T>(this IDatabase db, RedisKey key, bool throwIfKeyTypeWrong, Func<IDatabase, T> acquire, out T value) {
|
||
value = default(T);
|
||
try {
|
||
//获取List对象
|
||
value = acquire(db);
|
||
return true;
|
||
} catch (RedisServerException rse) {
|
||
Debug.Error($"StaticCachingHelper GetFromRedis fail, key: {key}, rse: {rse}");
|
||
if (throwIfKeyTypeWrong) {
|
||
throw new ArgumentOutOfRangeException($"redis key type wrong, key: {key}", rse);
|
||
}
|
||
} catch (Exception ex) {
|
||
Debug.Error($"StaticCachingHelper GetFromRedis fail, key: {key}, ex: {ex}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static bool ExecuctRedisTransaction(this IDatabase db, RedisKey key, TimeSpan expire, bool deleteKey, Action<ITransaction> action) {
|
||
try {
|
||
var transaction = db.CreateTransaction();
|
||
if (deleteKey) {
|
||
transaction.KeyDeleteAsync(key);
|
||
}
|
||
//为了保持缓存对象强类型特性,将泛型类型一并写入,以便取出时检查
|
||
action.Invoke(transaction);
|
||
if (expire > TimeSpan.Zero) {
|
||
transaction.KeyExpireAsync(key, expire);
|
||
}
|
||
var succ = transaction.Execute();
|
||
if (!succ) {
|
||
Debug.Error($"StaticCachingHelper ExecuctRedisTransaction fail 1, key: {key}, expire: {expire}");
|
||
}
|
||
return succ;
|
||
} catch (Exception ex) {
|
||
Debug.Error($"StaticCachingHelper ExecuctRedisTransaction fail 2, key: {key}, expire: {expire}, ex: {ex}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static async Task<bool> ExecuctRedisTransactionAsync(this IDatabase db, RedisKey key, TimeSpan expire, bool deleteKey, Func<ITransaction, Task<bool>> action) {
|
||
try {
|
||
var transaction = db.CreateTransaction();
|
||
|
||
var deleteOldTask = deleteKey ? transaction.KeyDeleteAsync(key) : null;
|
||
|
||
//为了保持缓存对象强类型特性,将泛型类型一并写入,以便取出时检查
|
||
var result = action.Invoke(transaction);
|
||
var setExpireTask = (expire > TimeSpan.Zero) ? transaction.KeyExpireAsync(key, expire) : null;
|
||
|
||
var succ = transaction.Execute();
|
||
if (!succ) {
|
||
Debug.Error($"StaticCachingHelper ExecuctRedisTransaction fail 1, key: {key}, expire: {expire}");
|
||
}
|
||
|
||
if (deleteOldTask != null) {
|
||
await deleteOldTask;
|
||
}
|
||
|
||
if (setExpireTask != null) {
|
||
await setExpireTask;
|
||
}
|
||
return succ && await result;
|
||
} catch (Exception ex) {
|
||
Debug.Error($"StaticCachingHelper ExecuctRedisTransaction fail 2, key: {key}, expire: {expire}, ex: {ex}");
|
||
}
|
||
return false;
|
||
}
|
||
#endregion
|
||
|
||
#endregion
|
||
}
|
||
}
|