Redis Fun使用

using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Configuration;
using System.Reflection;
using System.Threading.Tasks;
using System.Text;

namespace Lemon.Common
{
    public static class RedisUtil
    {
        //缓存失效时长
        private static TimeSpan _expiry = TimeSpan.FromMinutes(30);
        private static object _locker = new Object();
        private static ConnectionMultiplexer _instance = null;

        /// <summary>
        /// 使用一个静态属性来返回已连接的实例,如下列中所示。这样,一旦 ConnectionMultiplexer 断开连接,便可以初始化新的连接实例。
        /// </summary>
        public static ConnectionMultiplexer Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_locker)
                    {
                        if (_instance == null || !_instance.IsConnected)
                        {
                            _instance = ConnectionMultiplexer.Connect(EnvironmentCache.ConnectionStrings["RedisConnection"]);
                        }
                    }
                }
                //注册如下事件
                _instance.ConnectionFailed += MuxerConnectionFailed;
                _instance.ConnectionRestored += MuxerConnectionRestored;
                _instance.ErrorMessage += MuxerErrorMessage;
                _instance.HashSlotMoved += MuxerHashSlotMoved;
                _instance.InternalError += MuxerInternalError;
                return _instance;
            }
        }

        static RedisUtil()
        {
        }
                  
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static IDatabase GetDatabase(int db)
        {
            return Instance.GetDatabase(db);
        }
               
        /// <summary>
        /// 异步获取缓存数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbIndex">Redis数据库索引</param>
        /// <param name="key">Redis键</param>
        /// <param name="fun">从其他地方获取数据源,并缓存到Redis中</param>
        /// <returns></returns>
        public static async Task<T> GetAsync<T>(int dbIndex, string key, Func<T> fun)
        {
            var db = GetDatabase(dbIndex);
            if (db.KeyExists(key))
            {
                return JsonConvert.DeserializeObject<T>(db.StringGet(key));
            }
            T data = default(T);
            if (fun != null)
            {
                data = await Task.Run(() =>
                {
                    return fun();
                });
                db.Set(key, data);
            }
            return data;
        }

        /// <summary>
        /// 同步获取缓存数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbIndex">Redis数据库索引</param>
        /// <param name="key">Redis键</param>
        /// <param name="fun">从其他地方获取数据源,并缓存到Redis中</param>
        /// <returns></returns>
        public static T Get<T>(int dbIndex, string key, Func<T> fun)
        {
            var db = GetDatabase(dbIndex);
            if (db.KeyExists(key))
            {
                return JsonConvert.DeserializeObject<T>(db.StringGet(key));
            }
            T data = default(T);
            if (fun != null)
            {
                data = fun();
                db.Set(key, data);
            }
            return data;
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void Set(this IDatabase db,string key, object value)
        {
            db.StringSet(key, JsonConvert.SerializeObject(value), _expiry);
        }

        /// <summary>
        /// 实现递增
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        //public static long Increment(string key)
        //{
        //    //三种命令模式
        //    //Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
        //    //Async,异步模式直接走的是Task模型。
        //    //Fire - and - Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
        //    //即发即弃:通过配置 CommandFlags 来实现即发即弃功能,在该实例中该方法会立即返回,如果是string则返回null 如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
        //    return GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
        //}

        /// <summary>
        /// 实现递减
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        //public static long Decrement(string key, string value)
        //{
        //    return GetDatabase().HashDecrement(key, value, flags: CommandFlags.FireAndForget);
        //}

        /// <summary>
        /// 发生错误时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
        {
            Logger.Error(e.Message);
        }
        /// <summary>
        /// 重新建立连接之前的错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
        {
            Logger.Error(sender, e.Exception);
        }
        /// <summary>
        /// 连接失败 , 如果重新连接成功你将不会收到这个通知
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
         //   LogHelper.WriteInfoLog("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message)));
        }
        /// <summary>
        /// 更改集群
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
        {
           // LogHelper.WriteInfoLog("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
        }
        /// <summary>
        /// redis类库错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
        {
            Logger.Error(sender, e.Exception);
        }

        //场景不一样,选择的模式便会不一样,大家可以按照自己系统架构情况合理选择长连接还是Lazy。
        //建立连接后,通过调用ConnectionMultiplexer.GetDatabase 方法返回对 Redis Cache 数据库的引用。从 GetDatabase 方法返回的对象是一个轻量级直通对象,不需要进行存储。

        /// <summary>
        /// 使用的是Lazy,在真正需要连接时创建连接。
        /// 延迟加载技术
        /// 微软azure中的配置 连接模板
        /// </summary>
        //private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
        //{
        //    //var options = ConfigurationOptions.Parse(constr);
        //    ////options.ClientName = GetAppName(); // only known at runtime
        //    //options.AllowAdmin = true;
        //    //return ConnectionMultiplexer.Connect(options);
        //    ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(Coonstr);
        //    muxer.ConnectionFailed += MuxerConnectionFailed;
        //    muxer.ConnectionRestored += MuxerConnectionRestored;
        //    muxer.ErrorMessage += MuxerErrorMessage;
        //    muxer.ConfigurationChanged += MuxerConfigurationChanged;
        //    muxer.HashSlotMoved += MuxerHashSlotMoved;
        //    muxer.InternalError += MuxerInternalError;
        //    return muxer;
        //});

        #region  当作消息代理中间件使用 一般使用更专业的消息队列来处理这种业务场景
        /// <summary>
        /// 当作消息代理中间件使用
        /// 消息组建中,重要的概念便是生产者,消费者,消息中间件。
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static long Publish(string channel, string message)
        {
            ISubscriber sub = Instance.GetSubscriber();
            //return sub.Publish("messages", "hello");
            return sub.Publish(channel, message);
        }

        /// <summary>
        /// 在消费者端得到该消息并输出
        /// </summary>
        /// <param name="channelFrom"></param>
        /// <returns></returns>
        public static void Subscribe(string channelFrom)
        {
            ISubscriber sub = Instance.GetSubscriber();
            sub.Subscribe(channelFrom, (channel, message) =>
            {
                Console.WriteLine((string)message);
            });
        }
        #endregion
    }}
 /// <summary>
        ///通过secretkey对应的平台id
        /// </summary>
        /// <param name="secretKey"></param>
        /// <returns></returns>
        public int GetChannel(string secretKey, string appKey)
        {
            string key = string.Format("{0}&{1}",secretKey,appKey);
            int channelId = RedisUtil.Get<int>(0, key, () =>
            {
                using (var context = new MediaDBContext())
                {
                    return context.ChannelApps.Where(a => a.AppKey == appKey && a.Channel.SecretKey == secretKey && !a.IsDel)
                        .Select(c => c.ChannelId)
                        .FirstOrDefault();
                }
            });
            return channelId;
        }
 <add name="RedisConnection" connectionString="127.0.0.1,password=Lemon82211852" />