繁体   English   中英

ASP.NET 内核将带 IMemoryCache 的内存缓存转换为 Redis

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM