简体   繁体   English

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

[英]ASP.NET Core Converting In-Memory Cache with IMemoryCache to Redis

I have an ASP.NET Core Project ( Aspect-Oriented ) with In-Memory Cache and I use IMemoryCache interface for it.我有一个带有内存缓存的 ASP.NET 核心项目(面向方面),我使用 IMemoryCache 接口。

I want to convert this to Redis caching...我想将此转换为 Redis 缓存...

But I noticed that In-Memory caching with IMemoryCache can keep data as "object" type.但我注意到使用 IMemoryCache 的内存缓存可以将数据保持为“对象”类型。

public void Add(string key, object data, int duration)
{
   _cache.Set(key, data, TimeSpan.FromMinutes(duration));
}

And when I get the value, it can bring it as object...当我得到值时,它可以将它作为 object...

public object Get(string key)
{
    var keyValue = _cache.Get(key);  //Get method returns as string
    return keyValue;
}

SO, I can get the value from cache as the type of it and return it...所以,我可以从缓存中获取值作为它的类型并返回它......

And when I convert it to RedisCacheManager;当我将它转换为 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;
}

this returns as "RedisValue"这返回为“RedisValue”

and while using In-Memory cache with IMemoryCache, value returns as object and would be cast to its own type (for example as "List-Product" or "List-Category"....)并且在将内存缓存与 IMemoryCache 一起使用时,值返回为 object 并将被转换为自己的类型(例如“List-Product”或“List-Category”......)

So I wasn't touching anything in that process but when I use Redis, value returns as RedisValue then it returns this value所以我在那个过程中没有触及任何东西,但是当我使用 Redis 时,值返回为 RedisValue 然后它返回这个值

SO I GOT AN ERROR about Casting the value to whatever I need, But I use Interceptor and don't specify the type of it..所以我得到了一个关于将值转换为我需要的错误,但我使用拦截器并且没有指定它的类型..

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);
  }
} 

Is there ANYONE who has encountered with this situation or what can I do to deal with this??有没有人遇到过这种情况或者我能做些什么来处理这个?

I have solved this problem by using Generic class "RedisCacheAspect"我已经通过使用通用 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;
    }
}

With this class, you can use it as an attribute on a method like this;使用此 class,您可以将其用作此类方法的属性;

Data: DataResult<List<CategoryDto<<数据:DataResult<List<CategoryDto<<

[RedisCacheAspect<DataResult<List<CategoryDto<<>(duration: 60)] [RedisCacheAspect<DataResult<List<CategoryDto<<>(持续时间:60)]

As you see I use DataResult, but you shouldn't use an Interface while caching a value.如您所见,我使用 DataResult,但在缓存值时不应使用接口。 This gives you an error because Deserializing an object from Redis cache has be to be mapped to an object that you specify and interfaces cannot be mapped.这会给您一个错误,因为从 Redis 缓存中反序列化 object 必须映射到您指定的 object 并且无法映射接口。

An example to RedisCacheManager; 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.

相关问题 PostSharp Caching MethodInterceptionAspect 使用 ASP.NET Core 内存缓存 - PostSharp Caching MethodInterceptionAspect using ASP.NET Core in-memory cache 我可以在 ASP.NET 内核中为 SQL 服务器分布式缓存使用内存引擎吗? - Can I use In-Memory Engine for SQL Server Distributed Cache in ASP.NET Core? 使用内存缓存时,Asp.Net MVC中的InvalidOperationException - InvalidOperationException in Asp.Net MVC while using In-Memory Cache Asp.Net Core内存中TestServer中的ReflectionTypeLoadException异常 - ReflectionTypeLoadException exception in Asp.Net Core in-memory TestServer ASP.NET Core 中的持久内存并发字典 - Persistent in-memory concurrent dictionary in ASP.NET Core XUnit如何模拟IMemoryCache ASP.NET Core - XUnit how to mock IMemoryCache ASP.NET Core 如果*不*注入依赖项,是否可以在 ASP.NET Core 中使用 IMemoryCache? - Possible to use IMemoryCache in ASP.NET Core if it is *not* dependency injected? 测试ASP.NET Core IMemoryCache的正确方法 - Proper way of testing ASP.NET Core IMemoryCache 为什么在ASP.Net Core中获取IMemoryCache的多个实例? - Why getting multiple instances of IMemoryCache in ASP.Net Core? 在 ASP.net 核心应用程序中使用 IMemoryCache 和 Unity DI Container - Use IMemoryCache with Unity DI Container in ASP.net core application
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM