[英]PostSharp Caching MethodInterceptionAspect using ASP.NET Core in-memory cache
[英]ASP.NET Core Converting In-Memory Cache with IMemoryCache to Redis
我有一个带有内存缓存的 ASP.NET 核心项目(面向方面),我使用 IMemoryCache 接口。
我想将此转换为 Redis 缓存...
但我注意到使用 IMemoryCache 的内存缓存可以将数据保持为“对象”类型。
public void Add(string key, object data, int duration)
{
_cache.Set(key, data, TimeSpan.FromMinutes(duration));
}
当我得到值时,它可以将它作为 object...
public object Get(string key)
{
var keyValue = _cache.Get(key); //Get method returns as string
return keyValue;
}
所以,我可以从缓存中获取值作为它的类型并返回它......
当我将它转换为 RedisCacheManager 时;
public static string ToJson(this object value)
{
var aa = JsonConvert.SerializeObject(value, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
return aa;
}
SET
public void Set(string key, object value, int duration)
{
var k = value.ToJson();
_client.GetDatabase().StringSet(key, k, TimeSpan.FromMinutes(duration));
}
GET
public object Get(string key)
{
var keyValue = _client.GetDatabase().StringGet(key); //returns as "RedisValue" type
return keyValue;
}
这返回为“RedisValue”
并且在将内存缓存与 IMemoryCache 一起使用时,值返回为 object 并将被转换为自己的类型(例如“List-Product”或“List-Category”......)
所以我在那个过程中没有触及任何东西,但是当我使用 Redis 时,值返回为 RedisValue 然后它返回这个值
所以我得到了一个关于将值转换为我需要的错误,但我使用拦截器并且没有指定它的类型..
public class CacheAspect : MethodInterception
{
private int _duration;
private IRedisCacheService _cacheManager;
public CacheAspect(int duration = 60)//Default
{
_duration = duration;
_cacheManager = ServiceTool.ServiceProvider.GetService<IRedisCacheService>();
}
public override void Intercept(IInvocation invocation)
{
var methodName = string.Format($"{invocation.Method.ReflectedType.FullName}.{invocation.Method.Name}");
var arguments = invocation.Arguments.ToList();
var key = $"{methodName}({string.Join(",", arguments.Select(x => x != null ? JsonConvert.SerializeObject(x, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }) : "<Null>"))})";
if (_cacheManager.IsAdd(key))
{
var cacheValue = _cacheManager.Get(key); //returns as object
return;
}
invocation.Proceed();
_cacheManager.Set(key, invocation.ReturnValue, _duration);
}
}
有没有人遇到过这种情况或者我能做些什么来处理这个?
我已经通过使用通用 class "RedisCacheAspect" 解决了这个问题
public class RedisCacheAspect<T> : MethodInterception where T : class
{
private int _duration;
private IRedisCacheManager _cacheManager;
public RedisCacheAspect(int duration = 60)
{
_duration = duration;
_cacheManager = ServiceTool.ServiceProvider.GetService<IRedisCacheManager>();
}
public async override void Intercept(IInvocation invocation)
{
var methodName = string.Format($"{invocation.Method.ReflectedType.Name}.{invocation.Method.Name}");
var arguments = invocation.Arguments.ToList();
var key = $"{methodName}({string.Join(",", arguments.Select(x => x != null ? JsonConvert.SerializeObject(x) : "<Null>"))})";
if (_cacheManager.KeyExists(key))
{
var cacheValue = _cacheManager.Get(key);
var data = JsonConvert.DeserializeObject<T>(cacheValue, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
var isAsync = invocation.Method.IsReturnTask();
if (isAsync)
{
var returnValue = Task.FromResult(data);
invocation.ReturnValue = returnValue;
}
else
invocation.ReturnValue = data;
return;
}
invocation.Proceed();
var method = invocation.MethodInvocationTarget;
var isAsync2 = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
if (isAsync2 && typeof(Task).IsAssignableFrom(method.ReturnType))
{
var cacheValue = await InterceptAsync((dynamic)invocation.ReturnValue);
_cacheManager.Set(key, cacheValue, _duration);
}
else
_cacheManager.Set(key, invocation.ReturnValue, _duration);
}
private static async Task InterceptAsync(Task task)
{
await task.ConfigureAwait(false);
// do the continuation work for Task...
}
private static async Task<T> InterceptAsync<T>(Task<T> task)
{
T result = await task.ConfigureAwait(false);
// do the continuation work for Task<T>...
return result;
}
}
使用此 class,您可以将其用作此类方法的属性;
数据:DataResult<List<CategoryDto<<
[RedisCacheAspect<DataResult<List<CategoryDto<<>(持续时间:60)]
如您所见,我使用 DataResult,但在缓存值时不应使用接口。 这会给您一个错误,因为从 Redis 缓存中反序列化 object 必须映射到您指定的 object 并且无法映射接口。
RedisCacheManager 的一个例子;
public class RedisCacheManager : IRedisCacheManager, IDisposable
{
private readonly ConnectionMultiplexer _client;
private const string RedisDbName = "RedisCache1:";
private readonly string _connectionString;
private readonly ConfigurationOptions _configurationOptions;
public RedisCacheManager(IConfiguration configuration)
{
_connectionString = configuration.GetSection("RedisConfiguration:ConnectionString")?.Value;
var connectionStrings = _connectionString.Split(",");
_configurationOptions = new ConfigurationOptions()
{
//EndPoints = { aa.ToString() },
AbortOnConnectFail = false,
AsyncTimeout = 10000,
ConnectTimeout = 10000,
KeepAlive = 180
//ServiceName = ServiceName, AllowAdmin = true
};
foreach (var item in connectionStrings)
{
_configurationOptions.EndPoints.Add(item);
}
_client = ConnectionMultiplexer.Connect(_configurationOptions);
}
public IDatabase GetDatabase()
{
return _client.GetDatabase();
}
public T Get<T>(string key) where T : class
{
string value = _client.GetDatabase().StringGet(RedisDbName + key);
return value.ToObject<T>();
}
public async Task<T> GetAsync<T>(string key) where T : class
{
string value = await _client.GetDatabase().StringGetAsync(RedisDbName + key);
return value.ToObject<T>();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.