asp.net core 上使用redis探索(3)--redis示例demo


由於是基於.net-core平台,所以,我們最好是基於IDistributedCache接口來實現。ASP.NET-CORE下的官方redis客戶端實現是基於StackExchange的。但是官方提供的IDistributeCache接口中的方法只是增刪改查,我們可以繼續拓展,增加訂閱/發布,消息隊列,當然這些方法必須是基於底層的StackExchange相對應的方法來做的。
如果我們要實現自己的Redis客戶端,同時不使用底層的StackExchange驅動,可以派生一個繼承自IDistributedCache的接口,定義自己需要的方法,例如:

public interface IServiceStackRedisCache : IDistributedCache
{
    void Delete<T>(T item); // 刪除
    void DeleteAll<T>(T item);
    T Get<T>(string id);
    IQueryable<T> GetAll<T>();
    IQueryable<T> GetAll<T>(string hash, string value);
    IQueryable<T> GetAll<T>(string hash, string value, Expression<Func<T, bool>> filter);
    long PublishMessage(string channel, object item);
    void Set<T>(T item);
    void Set<T>(T item, List<string> hash, List<string> value, string keyName);
    void Set<T>(T item, string hash, string value, string keyName);
    void SetAll<T>(List<T> listItems);
    void SetAll<T>(List<T> list, List<string> hash, List<string> value, string keyName);
    void SetAll<T>(List<T> list, string hash, string value, string keyName);
}

接口有了,接下來就是繼承自接口的類,我們定義一個類來實現接口里的方法,例如:

using ServiceStack.Redis;

namespace Microsoft.Extensions.Caching.Redis
{
    public class ServiceStackRedisCache : IServiceStackRedisCache
    {
        private readonly IRedisClientsManager _redisManager;
        private readonly ServiceStackRedisCacheOptions _options;

        public ServiceStackRedisCache(IOptions<ServiceStackRedisCacheOptions> optionsAccessor)
        {
            if (optionsAccessor == null)
            {
                throw new ArgumentNullException(nameof(optionsAccessor));
            }

            _options = optionsAccessor.Value;

            var host = $"{_options.Password}@{_options.Host}:{_options.Port}";
            RedisConfig.VerifyMasterConnections = false;
            _redisManager = new RedisManagerPool(host);
        }
        #region Base

        public byte[] Get(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            using (var client = _redisManager.GetClient() as IRedisNativeClient)
            {
                if (client.Exists(key) == 1)
                {
                    return client.Get(key);
                }
            }
            return null;
        }

        public async Task<byte[]> GetAsync(string key)
        {
            return Get(key);
        }

        public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            using (var client = _redisManager.GetClient() as IRedisNativeClient)
            {
                var expireInSeconds = GetExpireInSeconds(options);
                if (expireInSeconds > 0)
                {
                    client.SetEx(key, expireInSeconds, value);
                    client.SetEx(GetExpirationKey(key), expireInSeconds, Encoding.UTF8.GetBytes(expireInSeconds.ToString()));
                }
                else
                {
                    client.Set(key, value);
                }
            }
        }

        public async Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options)
        {
            Set(key, value, options);
        }

        public void Refresh(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            using (var client = _redisManager.GetClient() as IRedisNativeClient)
            {
                if (client.Exists(key) == 1)
                {
                    var value = client.Get(key);
                    if (value != null)
                    {
                        var expirationValue = client.Get(GetExpirationKey(key));
                        if (expirationValue != null)
                        {
                            client.Expire(key, int.Parse(Encoding.UTF8.GetString(expirationValue)));
                        }
                    }
                }
            }
        }

        public async Task RefreshAsync(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            Refresh(key);
        }

        public void Remove(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            using (var client = _redisManager.GetClient() as IRedisNativeClient)
            {
                client.Del(key);
            }
        }

        public async Task RemoveAsync(string key)
        {
            Remove(key);
        }

        private int GetExpireInSeconds(DistributedCacheEntryOptions options)
        {
            if (options.SlidingExpiration.HasValue)
            {
                return (int)options.SlidingExpiration.Value.TotalSeconds;
            }
            else if (options.AbsoluteExpiration.HasValue)
            {
                return (int)options.AbsoluteExpirationRelativeToNow.Value.TotalSeconds;
            }
            else
            {
                return 0;
            }
        }

        private string GetExpirationKey(string key)
        {
            return key + $"-{nameof(DistributedCacheEntryOptions)}";
        }
        #endregion
        #region data
        public T Get<T>(string id)
        {
            using (var redisClient = _redisManager.GetClient())
            {
                var redis = redisClient.As<T>();
                return redis.GetById(id.ToLower());
            }
        }

        public IQueryable<T> GetAll<T>()
        {
            using (var redisClient = _redisManager.GetClient())
            {
                var redis = redisClient.As<T>();
                return redis.GetAll().AsQueryable();
            }
        }

        public IQueryable<T> GetAll<T>(string hash, string value, Expression<Func<T, bool>> filter)
        {
            var filtered = _redisManager.GetClient().GetAllEntriesFromHash(hash).Where(c => c.Value.Equals(value, StringComparison.CurrentCultureIgnoreCase));
            var ids = filtered.Select(c => c.Key);

            var ret = _redisManager.GetClient().As<T>().GetByIds(ids).AsQueryable()
                                .Where(filter);

            return ret;
        }

        public IQueryable<T> GetAll<T>(string hash, string value)
        {
            var filtered = _redisManager.GetClient().GetAllEntriesFromHash(hash).Where(c => c.Value.Equals(value, StringComparison.CurrentCultureIgnoreCase));
            var ids = filtered.Select(c => c.Key);

            var ret = _redisManager.GetClient().As<T>().GetByIds(ids).AsQueryable();
            return ret;
        }

        public void Set<T>(T item)
        {
            using (var redisClient = _redisManager.GetClient())
            {
                var redis = redisClient.As<T>();
                redis.Store(item);
            }
        }

        public void Set<T>(T item, string hash, string value, string keyName)
        {
            Type t = item.GetType();
            PropertyInfo prop = t.GetProperty(keyName);

            _redisManager.GetClient().SetEntryInHash(hash, prop.GetValue(item).ToString(), value.ToLower());

            _redisManager.GetClient().As<T>().Store(item);
        }

        public void Set<T>(T item, List<string> hash, List<string> value, string keyName)
        {
            Type t = item.GetType();
            PropertyInfo prop = t.GetProperty(keyName);

            for (int i = 0; i < hash.Count; i++)
            {
                _redisManager.GetClient().SetEntryInHash(hash[i], prop.GetValue(item).ToString(), value[i].ToLower());
            }

            _redisManager.GetClient().As<T>().Store(item);
        }

        public void SetAll<T>(List<T> listItems)
        {
            using (var redisClient = _redisManager.GetClient())
            {
                var redis = redisClient.As<T>();
                redis.StoreAll(listItems);
            }
        }

        public void SetAll<T>(List<T> list, string hash, string value, string keyName)
        {
            foreach (var item in list)
            {
                Type t = item.GetType();
                PropertyInfo prop = t.GetProperty(keyName);

                _redisManager.GetClient().SetEntryInHash(hash, prop.GetValue(item).ToString(), value.ToLower());

                _redisManager.GetClient().As<T>().StoreAll(list);
            }
        }

        public void SetAll<T>(List<T> list, List<string> hash, List<string> value, string keyName)
        {
            foreach (var item in list)
            {
                Type t = item.GetType();
                PropertyInfo prop = t.GetProperty(keyName);

                for (int i = 0; i < hash.Count; i++)
                {
                    _redisManager.GetClient().SetEntryInHash(hash[i], prop.GetValue(item).ToString(), value[i].ToLower());
                }

                _redisManager.GetClient().As<T>().StoreAll(list);
            }
        }

        public void Delete<T>(T item)
        {
            using (var redisClient = _redisManager.GetClient())
            {
                var redis = redisClient.As<T>();
                redis.Delete(item);
            }
        }

        public void DeleteAll<T>(T item)
        {
            using (var redisClient = _redisManager.GetClient())
            {
                var redis = redisClient.As<T>();
                redis.DeleteAll();
            }
        }

        public long PublishMessage(string channel, object item)
        {
            var ret = _redisManager.GetClient().PublishMessage(channel, JsonConvert.SerializeObject(item));
            return ret;
        }

        #endregion
    }
}
View Code

在這里我們使用ServiceStack來作為底層redis驅動。在構造函數中根據配置連接redis服務器。

aps.net-core給我們提供了強大的配置功能,使用強類型的Options,一般,我們實現一個繼承自IOptions<TOptions>的類。定義一些字段用來表示主機,端口等常規redis配置選項。由於IOptions接口定義了一個Value屬性,我們可以通過這個屬性來獲取配置類的實例。
然后我們在redis客戶端類中(也就是上面的ServiceStackRedisCache類),使用構造函數注入。這樣就能獲取到redis的配置了。
然后我們在控制器的構造函數中注入redis客戶端類實例:

private readonly IServiceStackRedisCache _cache;
public ValuesController(IServiceStackRedisCache cache)
{
    _cache = cache;
}

如此,我們才能使用redis客戶端去操作redis服務器。
最后就是最重要的部分了。ASP.NET-CORE框架隨處可見的都是依賴注入。上面所有的程序,都是一個接口對應着一個類。所謂的依賴注入,其實就是繼承自接口的類的實例化過程,但是這個過程是解耦的!DI的作用主要就是用來解耦實例化的過程。
ASP.NET-CORE框架依賴注入部分是在ConfigureService中使用的。
從上面的過程中,我們看到有兩個構造函數的注入過程,因此,我們需要實現兩個DI,分別是配置類的DI和redis客戶端類的DI。

services.Configure(setupAction);

services.Add(ServiceDescriptor.Singleton<IServiceStackRedisCache, ServiceStackRedisCache>());

整個步驟就是:
1.定義接口,用於繼承IDistributedCache的接口。該接口主要封裝了基本的redis操作。
2.實現接口,實現redis的各個邏輯。
3.基於IOptions<TOptions>接口實現redis的常規配置。
4.在控制器的構造函數中注入。
5.依賴注入以上接口的實例。

完整demo下載:鏈接:https://pan.baidu.com/s/17w0c0y9_VF3TzvgilgazjQ 密碼:4u5e


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM