随笔 - 57,  文章 - 0,  评论 - 25,  阅读 - 26583

一般缓存采用redis缓存,当然也存在没有redis的情况,所以备用方案是memory缓存。

但是使用的时候要进行统一的注入,起码要保证两者继承的接口是一致的

需要用到的包

Microsoft.Extensions.Caching.StackExchangeRedis

 

1. 建立缓存的 接口和实现。CacheService和ICacheService,用于注入的时候使用

接口比较简单,包括常用的 添加,删除,清空,获取,判断是否存在,采用异步方式,异步好一些

    public interface ICacheService
    {
        Task SetAsync(string key, object value, TimeSpan? expirationTime = null);
        Task GetAsync(string key);
        Task RemoveAsync(string key);
        Task<bool> ExistAsync(string key);
        Task ClearAsync();
    }

 

2.分别建立redis和memory 实现接口ICacheService

redis 实现如下

复制代码
    public class RedisCacheService(IConnectionMultiplexer connection) : ICacheService
    {
        private readonly IConnectionMultiplexer connection = connection;
        private readonly IDatabase redis = connection.GetDatabase();

        public async Task ClearAsync()
        {
            var endpoints = connection.GetEndPoints();
            var tasks = endpoints.Select(async x =>
            {
                var server = connection.GetServer(x);
                foreach (var key in server.Keys())
                {
                    await redis.KeyDeleteAsync(key);
                }
            });

            await Task.WhenAll(tasks);
        }

        public async Task<bool> ExistAsync(string key)
        {
            return await redis.KeyExistsAsync(key);
        }

        public async Task<string> GetAsync(string key)
        {
            return await redis.StringGetAsync(key);
        }

        public async Task RemoveAsync(string key)
        {
            await redis.KeyDeleteAsync(key);
        }

        public async Task SetAsync(string key, object value, TimeSpan? expirationTime = null)
        {
            if (value != null)
            {
                //默认2H
                expirationTime ??= TimeSpan.FromHours(2);
                if (value is string cacheStr)
                {
                    await redis.StringSetAsync(key, cacheStr, expirationTime);
                }
                else
                {
                    await redis.StringSetAsync(key, JsonSerializer.Serialize(value), expirationTime);
                }
            }
        }
    }
复制代码

memory 实现如下: 需要注意下,memory没有清空的操作,可能有些大佬封装的好一些,目前我这里没有添加,但是我项目里是通过hashset来存储键的,拆出来的时候图省事直接不写了,不是很影响,强迫症例外

复制代码
    public class MemoryCacheService(IMemoryCache memory) : ICacheService
    {
        private readonly IMemoryCache memory = memory;

        public Task ClearAsync()
        {

        return Task.CompletedTask;

        }

        public Task<bool> ExistAsync(string key)
        {
            var exists = memory.TryGetValue(key, out _);
            return Task.FromResult(exists);
        }

        public Task<string> GetAsync(string key)
        {
            if (memory.TryGetValue(key, out string value))
            {
                return Task.FromResult(value);
            }

            return Task.FromResult<string>(null);
        }

        public Task RemoveAsync(string key)
        {
            memory.Remove(key);
            return Task.CompletedTask;
        }

        public Task SetAsync(string key, object value, TimeSpan? expirationTime = null)
        {
            if (value != null)
            {
                //默认2H
                expirationTime ??= TimeSpan.FromHours(2);
                if (value is string cacheStr)
                {
                    memory.Set(key, cacheStr, expirationTime.Value);
                }
                else
                {
                    memory.Set(key, JsonSerializer.Serialize(value), expirationTime.Value);
                }
            }
            return Task.CompletedTask;
        }
    }
复制代码

3. 这一步比较重要,只是添加一种缓存那确实没啥问题,我要的效果是,哪天redis挂了,项目会默认使用memory,但是这对于开发来说,他无需在乎你挂没挂,使用习惯仍然是一样的,而不是要注入两者不同的接口。就是体现在CacheService里面。类似于工厂类,注入之后会判断下redis有没有连接,连接了用redis,没连接用memory。原理较为简单

复制代码
public class CacheService : ICacheService
{
    private readonly ICacheService cache;

    public CacheService(IConnectionMultiplexer connection, IMemoryCache memory)
    {
        if (connection.IsConnected)
        {
            cache = new RedisCacheService(connection);
        }
        else
        {
            cache = new MemoryCacheService(memory);
        }
    }

    public async Task ClearAsync()
    {
        await cache.ClearAsync();
    }

    public async Task<bool> ExistAsync(string key)
    {
        return await cache.ExistAsync(key);
    }

    public async Task<string> GetAsync(string key)
    {
        return await cache.GetAsync(key);
    }

    public async Task RemoveAsync(string key)
    {
        await cache.RemoveAsync(key);
    }

    public async Task SetAsync(string key, object value, TimeSpan? expirationTime = null)
    {
        await cache.SetAsync(key, value, expirationTime);
    }
}
复制代码

4.如何注入:redis配置主要是通过配置文件读取,格式如下,未启用或连接有问题时,则开启memory缓存。 redis瞬时注入,因为数据在redis里共享,memory是整个程序的内存,单例好些

  "Redis": {
    "Enable": false,
    "UseCluster": false,
    "ConnectionSingle": "127.0.0.1:6379",
    "ConnectionCluster": "node1:6379,node2:6379,node3:6379",
    "InstanceName": ""
  }
复制代码
        public static void AddCacheSetup(this IServiceCollection services)
        {
            if (AppSettings.AppString("Redis:Enable").ToBool())
            {
                var redisConfig = string.Empty;

                if (AppSettings.AppString("Redis:UseCluster").ToBool())
                {
                    redisConfig = AppSettings.AppString("Redis:ConnectionCluster");
                }
                else
                {
                    redisConfig = AppSettings.AppString("Redis:ConnectionSingle");
                }

                var configurationOptions = ConfigurationOptions.Parse(redisConfig);
                configurationOptions.ResolveDns = true;

                try
                {
                    var connectionMultiplexer = ConnectionMultiplexer.Connect(configurationOptions);

                    services.AddStackExchangeRedisCache(x =>
                    {
                        x.ConnectionMultiplexerFactory = () => Task.FromResult(connectionMultiplexer as IConnectionMultiplexer);
                        var instanceName = AppSettings.AppString("Redis:InstanceName");
                        if (!string.IsNullOrEmpty(instanceName))
                        {
                            x.InstanceName = instanceName;
                        }
                    });

                    services.AddTransient<ICacheService, RedisCacheService>();
                }
                catch (Exception)
                {
                    services.AddMemoryCache();
                    services.AddSingleton<ICacheService, MemoryCacheService>();
                }
            }
            else
            {
                services.AddMemoryCache();
                services.AddSingleton<ICacheService, MemoryCacheService>();
            }
        }
复制代码

最后Program里:     builder.Services.AddCacheSetup();

只需要在使用的地方注入ICacheService,就可以使用了,而不用在意用的是redis缓存还是memory缓存

posted on   尝尝手指  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示