場景: 在不動 業務邏輯的情況下, 實現讀寫快取
這裡使用的AOP的方式 在 方法上加註解, 這目前有個弊端不能傳陣列, 涉及到排序問題
/// <summary>
/// Json Redis快取
/// </summary>
public class RedisInterceptorAttribute : AbstractInterceptorAttribute
{
readonly string _cacheKey;
bool _isDb = false; //是否走快取
int _expireSeconds = -1;
public RedisInterceptorAttribute(string cacheKey, int expireSeconds = -1,bool isDb=false)
{
_cacheKey = cacheKey;
_isDb = isDb;
_expireSeconds = expireSeconds;
}
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
Type returnType = context.ServiceMethod.ReturnType;
Type genericArgument = returnType.GetGenericArguments()[0];
// 生成快取的key
string cacheKeyWithParams = GenerateCacheKey(context);
if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
{
//透過型別獲取快取方法,並且呼叫 GetAsync 方法
MethodInfo method = this.GetType().GetMethod("GetAsync", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
MethodInfo genericMethod = method.MakeGenericMethod(genericArgument);
var cacheTask = (Task)genericMethod.Invoke(this, new object[] { cacheKeyWithParams });
await cacheTask.ConfigureAwait(true);
var resultProperty = cacheTask.GetType().GetProperty("Result");
var cacheResult = resultProperty.GetValue(cacheTask);
if (cacheResult != null)
{
context.ReturnValue = ConvertToReturnType(cacheResult, returnType);
// 設定快取的邏輯
await Task.CompletedTask;
}
else
{
await context.Invoke(next);
// 設定快取
if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
{
MethodInfo setMethod = this.GetType().GetMethod("SetAsync", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
MethodInfo genericSetMethod = setMethod.MakeGenericMethod(genericArgument);
var resultProperty1 = context.ReturnValue.GetType().GetProperty("Result");
var result = resultProperty1.GetValue(context.ReturnValue);
await (Task)genericSetMethod.Invoke(this, new object[] { cacheKeyWithParams, result });
}
}
}
else
{
await next(context);
}
}
private string GenerateCacheKey(AspectContext context)
{
var keyBuilder = new System.Text.StringBuilder(_cacheKey);
foreach (var parameter in context.Parameters)
{
keyBuilder.Append(":").Append(FormatParameter(parameter));
}
return keyBuilder.ToString();
}
/// <summary>
/// 格式化引數(類似url過濾一下資料,: 會影響閱讀)
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
private string FormatParameter(object parameter)
{
return JsonConvert.SerializeObject(parameter).Replace(":", "=").Replace("{", "").Replace("}", "").Replace("\"", "").Replace(",", "&");
}
/// <summary>
/// 將返回值轉換為原有型別
/// </summary>
/// <param name="result"></param>
/// <param name="returnType"></param>
/// <returns></returns>
private object ConvertToReturnType(object result, Type returnType)
{
Type taskResultType = returnType.GetGenericArguments()[0];
return typeof(Task).GetMethod(nameof(Task.FromResult))
.MakeGenericMethod(taskResultType)
.Invoke(null, new[] { result });
}
async Task<T> GetAsync<T>(string key)
{
var result = await RedisHelper.GetAsync<T>(key);
return result;
}
async Task SetAsync<T>(string cacheKey, T data)
{
if (data != null)
{
await RedisHelper.SetAsync(cacheKey, data, _expireSeconds);
}
}
}
這樣就簡單實現了
只需要在方法上加註解, 一定要加virtual
//一定要加virtual
[RedisInterceptor("school")]
public virtual async Task<List<string>> SelectAsync(Guid[] schoolId)
{
///業務
return new();
}
QQ群: 929412850 (Byte.Core 框架交流群)
未經作者同意,禁止轉發