Redis中的StackExchange.redis在C#中的应用
Redis,基于这种Key-Value的内存数据库很适合来做分布式Session。本示例将基于StackExchange.Redis.dll进行实现,序列化使用的是Newtonsoft.json.dll。
为了避免APP等客户端重复登录导致同一个用户出现重复的Session,将以ServerID(可以是数据库主键)为服务端令牌,并生成一个新的GUID作为其客户端令牌,客户端令牌将返回给客户端。
两个令牌都将存储在Redis中,形成2个键值对,在服务端令牌中保存了其对应的客户端令牌ID。当同一用户再次登录时,将首先检查是否有基于其ServerID的服务端令牌存在,如果存在,则直接取其值(客户端令牌)返回给客户端,以此避免重复的Session浪费。
Web.config:
- <!--Redis数据库编号(范围:0~15)-->
- <add key="SessionRedisDBIndex" value="0"/>
- <!--主Redis连接串-->
- <add key="SessionRedisMaster" value="pass:192.168.1.236:6379"/>
- <!--Session有效时长,单位:分钟-->
- <add key="SessionTimeOut" value="120"/>
Session基类:
- public abstract class BaseSession
- {
- DateTime mExpiresTime = DateTime.Now;
- [JsonConverter(typeof(TimestampConverter))]
- public DateTime ExpiresTime
- {
- get { return mExpiresTime; }
- }
- /// <summary>
- /// 设置Session过期时间
- /// </summary>
- /// <param name="aExpiresTime"></param>
- internal void SetExpiresTime(DateTime aExpiresTime)
- {
- mExpiresTime = aExpiresTime;
- }
- [JsonIgnore]
- /// <summary>
- /// 获取服务端ID
- /// </summary>
- public abstract string ServerID { get; }
- }
- public static class SessionService
- {
- /// <summary>
- /// Session有效时长,默认120分钟
- /// </summary>
- static int TimeOutMinutes=120;
- /// <summary>
- /// Redis缓存访问对象
- /// </summary>
- static ConnectionMultiplexer mRedisSession;
- /// <summary>
- /// Session管理
- /// </summary>
- static SessionService()
- {
- try
- {
- TimeOutMinutes = int.Parse(ConfigurationManager.AppSettings["SessionTimeOut"]);
- string[] redisMaster = ConfigurationManager.AppSettings["SessionRedisMaster"].Split(':');
- ConfigurationOptions fRedisConfig = new ConfigurationOptions()
- {
- Password = redisMaster[0],
- EndPoints ={ { redisMaster[1], int.Parse(redisMaster[2]) } },
- KeepAlive = 180,
- DefaultDatabase = int.Parse(ConfigurationManager.AppSettings["SessionRedisDBIndex"])
- };
- mRedisSession = ConnectionMultiplexer.Connect(fRedisConfig);
- }
- catch (Exception ex)
- {
- Lib.LocalLog.Append("Session Error(SessionService):" + ex.Message, "", "SessionError", "SessionError");
- throw ex;
- }
- }
- /// <summary>
- /// 添加Session
- /// </summary>
- /// <typeparam name="T">Session对象类型</typeparam>
- /// <param name="aSession">要存为Session的对象</param>
- /// <param name="aPrefix">前缀</param>
- /// <returns>令牌</returns>
- public static string Add<T>(T aSession,string aPrefix="") where T:BaseSession
- {
- try
- {
- IDatabase client = mRedisSession.GetDatabase();
- aSession.SetExpiresTime(DateTime.Now.AddMinutes(TimeOutMinutes));
- string fExistToken = client.StringGet(aSession.ServerID);//获取服务端唯一码当前对应的客户端令牌
- if (fExistToken != null)
- {//存在客户端令牌
- //更新客户端令牌
- if (client.StringSet(fExistToken,
- JsonConvert.SerializeObject(aSession),
- aSession.ExpiresTime.Subtract(DateTime.Now)))
- {
- return fExistToken;
- }
- }
- else
- {
- string token = aPrefix + Guid.NewGuid().ToString("N");
- if(client.StringSet(token,
- JsonConvert.SerializeObject(aSession),
- aSession.ExpiresTime.Subtract(DateTime.Now)) &&//添加Session
- client.StringSet(aSession.ServerID,
- token,
- aSession.ExpiresTime.AddSeconds(-5).Subtract(DateTime.Now)))//绑定服务端唯一码与客户端令牌(将比Session早5秒失效)
- {
- return token;
- }
- }
- }
- catch (Exception ex)
- {
- Lib.LocalLog.Append("Session Error(Add<T>):" + ex.Message, "", "SessionError", "SessionError");
- }
- return null;
- }
- /// <summary>
- /// 获取Session
- /// </summary>
- /// <typeparam name="T">Session对象类型</typeparam>
- /// <param name="aToken">令牌</param>
- /// <returns>令牌对应的Session对象</returns>
- public static T Get<T>(string aToken) where T : BaseSession
- {
- try
- {
- IDatabase client = mRedisSession.GetDatabase();
- T fEntity = null;
- string fSessionValue = client.StringGet(aToken);
- if (!string.IsNullOrEmpty(fSessionValue))
- {
- fEntity = JsonConvert.DeserializeObject<T>(fSessionValue);
- CheckExpireTime<T>(aToken, fEntity, client);
- }
- return fEntity;
- }
- catch (Exception ex)
- {
- Lib.LocalLog.Append("Session Error(Get<T>):" + ex.Message, "", "SessionError", "SessionError");
- }
- return default(T);
- }
- /// <summary>
- /// 获取Session 字符串值
- /// </summary>
- /// <param name="aToken">令牌</param>
- /// <returns>令牌对应的Session 字符串值</returns>
- public static string GetValue<T>(string aToken) where T : BaseSession
- {
- try
- {
- IDatabase client = mRedisSession.GetDatabase();
- string fSessionValue = client.StringGet(aToken);
- if (fSessionValue != null)
- {
- CheckExpireTime<T>(aToken, JsonConvert.DeserializeObject<T>(fSessionValue), client);
- }
- return fSessionValue;
- }
- catch (Exception ex)
- {
- Lib.LocalLog.Append("Session Error(GetValue<T>):" + ex.Message, "", "SessionError", "SessionError");
- }
- return null;
- }
- /// <summary>
- /// 删除Session
- /// </summary>
- /// <param name="aToken">令牌</param>
- public static void Remove<T>(string aToken) where T : BaseSession
- {
- try
- {
- IDatabase client = mRedisSession.GetDatabase();
- T fEntity = null;
- string fSessionValue = client.StringGet(aToken);
- if (!string.IsNullOrEmpty(fSessionValue))
- {
- fEntity = JsonConvert.DeserializeObject<T>(fSessionValue);
- client.KeyDelete(fEntity.ServerID);
- client.KeyDelete(aToken);
- }
- }
- catch (Exception ex)
- {
- Lib.LocalLog.Append("Session Error(Remove):" + ex.Message, "", "SessionError", "SessionError");
- }
- }
- /// <summary>
- /// 令牌有效时间检查
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="aToken">令牌</param>
- /// <param name="aSession"></param>
- static void CheckExpireTime<T>(string aToken, T aSession, IDatabase client) where T : BaseSession
- {
- if (aSession.ExpiresTime.Subtract(DateTime.Now).TotalMinutes < 10)
- {//离Session过期时间小于10分钟,延长Session有效期
- try
- {
- aSession.SetExpiresTime(DateTime.Now.AddMinutes(TimeOutMinutes));
- client.StringSet(aToken, JsonConvert.SerializeObject(aSession), aSession.ExpiresTime.Subtract(DateTime.Now));
- client.KeyExpire(aSession.ServerID, aSession.ExpiresTime.AddSeconds(-5).Subtract(DateTime.Now));
- }
- catch (Exception ex)
- {
- Lib.LocalLog.Append("Session Error(6):" + ex.Message, "", "SessionError", "SessionError");
- }
- }
- }
- }
相关推荐
- GLSL(3)-在opengl中初始化Uniform Block 的流程-小结
- 棉花糖多少钱_如何在6.0棉花糖及更高版本中访问Android的正在运行的应用程序列表...
- alexa是什么_什么是Alexa应用程序中的“队列”选项卡?
- 在window10中的IIS 7.5中创建Experiment网站,复制VSC 2017中的Expt1Site网站到IIS 7.5中Experiment网站下的Web应用程序Expt1
- Redis的使用及安装以及面试中的常见面试题
- 在 net(C )中随机生成较深的颜色
- 左程云算法初级课 在排好序的矩阵中找数问题 题目解析和代码实现 宏观调度问题
- EVC入门之二: 在未被加载的DLL中设置断点 (虽然没有遇到这个问题,不过先摘抄下来)...
- GSM Hacking:静默短信(Silent SMS)在技术侦查中的应用
- 如何检查Linux服务器中的端口是否在使用?
- Vue基于“依赖收集”的响应式原理
- 第2章 统计学习-感知机