Session是互联网应用中非常重要的玩意儿,对于超过单台部署的站点集群,都会存在会话共享的需求。在web.config中,微软提供了sessionstate节点来定义不同的Session状态存储方式。本文就自定义模式下的Session状态存储驱动提供一些干货。

首先,想要接管Session状态存储,需要了解一些基本的东西。

SessionIDManager

/// <summary>
/// 自定义SessionID管理器
/// </summary>
public class CustomSessionIDManager : SessionIDManager
{
/// <summary>
/// 创建SessionID
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override string CreateSessionID(HttpContext context)
{
return string.Format("{0}.{1}", SessionProviderConfigurationSectionHandler.SessionProviderSettings.SessionProfix, base.CreateSessionID(context));
} /// <summary>
/// 验证
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public override bool Validate(string id)
{
string prefix = string.Empty;
string realId = string.Empty; if (string.IsNullOrEmpty(id) || id.Trim().Length == )
{
return false;
}
var parsedValues = id.Split('.');
if (parsedValues == null || parsedValues.Length != )
{
return false;
} prefix = parsedValues[];
realId = parsedValues[]; return base.Validate(realId);
} }

想要共享Session,肯定就会有SessionID的前缀需求,而SessionIDManager就提供了可自定义的虚方法,这边以CustomSessionIDManager举例。CreateSessionID方法提供了创建SessionID的实现,重载该方法,用{0}.{1}的方式提供基于前缀的SessionID生成。而Validate是拆解带前缀的SessionID来验证真实的SessionID。

SessionStateStoreProviderBase

/// <summary>
/// 自定义Session状态存储驱动
/// </summary>
public sealed class CustomSessionStateStoreProvider : SessionStateStoreProviderBase
{ /// <summary>
/// 构造函数
/// </summary>
public CustomSessionStateStoreProvider()
{
sessionStateStoreBehavior = SessionProviderBehaviorFactory.CreateSessionStateStoreBehaviorInstance();
} /// <summary>
/// Session状态存储行为
/// </summary>
readonly ISessionStateStoreBehavior sessionStateStoreBehavior; /// <summary>
/// 创建新的存储数据
/// </summary>
/// <param name="context"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public override SessionStateStoreData CreateNewStoreData(System.Web.HttpContext context, int timeout)
{
return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), timeout);
} /// <summary>
/// 创建未初始化的项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="timeout"></param>
public override void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout)
{
sessionStateStoreBehavior.CreateUninitializedItem(context, id, timeout);
} /// <summary>
/// 获取项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="locked"></param>
/// <param name="lockAge"></param>
/// <param name="lockId"></param>
/// <param name="actions"></param>
/// <returns></returns>
public override SessionStateStoreData GetItem(System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
return sessionStateStoreBehavior.GetItem(false, context, id, out locked, out lockAge, out lockId, out actions);
} /// <summary>
/// 独占获取项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="locked"></param>
/// <param name="lockAge"></param>
/// <param name="lockId"></param>
/// <param name="actions"></param>
/// <returns></returns>
public override SessionStateStoreData GetItemExclusive(System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
return sessionStateStoreBehavior.GetItem(true, context, id, out locked, out lockAge, out lockId, out actions);
} /// <summary>
/// 独占释放项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="lockId"></param>
public override void ReleaseItemExclusive(System.Web.HttpContext context, string id, object lockId)
{
sessionStateStoreBehavior.ReleaseItem(context, id, lockId);
} /// <summary>
/// 移除项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="lockId"></param>
/// <param name="item"></param>
public override void RemoveItem(System.Web.HttpContext context, string id, object lockId, SessionStateStoreData item)
{
sessionStateStoreBehavior.RemoveItem(context, id, lockId);
} /// <summary>
/// 重设项的超时时间
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
public override void ResetItemTimeout(System.Web.HttpContext context, string id)
{
sessionStateStoreBehavior.ResetItemTimeout(context, id);
} /// <summary>
/// 独占设置并释放项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="item"></param>
/// <param name="lockId"></param>
/// <param name="newItem"></param>
public override void SetAndReleaseItemExclusive(System.Web.HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
{
sessionStateStoreBehavior.SetAndReleaseItem(context, id, item, lockId, newItem);
} /// <summary>
/// 回收
/// </summary>
public override void Dispose() { } /// <summary>
/// 结束请求
/// </summary>
/// <param name="context"></param>
public override void EndRequest(System.Web.HttpContext context) { } /// <summary>
/// 初始化请求
/// </summary>
/// <param name="context"></param>
public override void InitializeRequest(System.Web.HttpContext context) { } /// <summary>
/// 设置项过期回掉
/// </summary>
/// <param name="expireCallback"></param>
/// <returns></returns>
public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) { return false; }
}

SessionStateStoreProviderBase是提供Session状态存储驱动的基类。从基类分析,想要灵活扩展,核心就是对Session存储的那些方法实现进行抽象,让驱动在执行方法的时候不关心实现由谁来提供。因此,写一个SessionStateStoreBehavior接口,在CustomSessionStateStoreProvider的构造函数中,通过工厂在运行时得到实例。

SessionStateStoreBehavior

/// <summary>
/// Session状态存储行为接口
/// </summary>
public interface ISessionStateStoreBehavior
{
/// <summary>
/// 创建未初始化的项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="timeout"></param>
void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout); /// <summary>
/// 获取项
/// </summary>
/// <param name="lockRecord"></param>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="locked"></param>
/// <param name="lockAge"></param>
/// <param name="lockId"></param>
/// <param name="actions"></param>
/// <returns></returns>
SessionStateStoreData GetItem(bool lockRecord, System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions); /// <summary>
/// 释放项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="lockId"></param>
void ReleaseItem(System.Web.HttpContext context, string id, object lockId); /// <summary>
/// 移除项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="lockId"></param>
void RemoveItem(System.Web.HttpContext context, string id, object lockId); /// <summary>
/// 重设项的超时时间
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
void ResetItemTimeout(System.Web.HttpContext context, string id); /// <summary>
/// 设置并释放项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="item"></param>
/// <param name="lockId"></param>
/// <param name="newItem"></param>
void SetAndReleaseItem(System.Web.HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem);
}

创建一个ISessionStateStoreBehavior,将涉及Session存储的方法公开。

/// <summary>
/// Session驱动行为工厂
/// </summary>
class SessionProviderBehaviorFactory
{
/// <summary>
/// 当前Session状态存储行为实例
/// </summary>
static ISessionStateStoreBehavior currentSessionStateStoreBehavior; /// <summary>
/// 创建Session状态存储行为实例
/// </summary>
/// <returns></returns>
public static ISessionStateStoreBehavior CreateSessionStateStoreBehaviorInstance()
{
if (currentSessionStateStoreBehavior == null)
{
var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => !t.IsAbstract && t.GetInterface(typeof(ISessionStateStoreBehavior).Name) != null);
var currentType = types.FirstOrDefault(t => t.Name == string.Format("{0}SessionStateStoreBehavior", SessionProviderConfigurationSectionHandler.SessionProviderSettings.SessionStateStoreProviderBehaviorName));
if (currentType != null)
{
currentSessionStateStoreBehavior = (ISessionStateStoreBehavior)Activator.CreateInstance(currentType);
}
} return currentSessionStateStoreBehavior;
}
}

通过工厂得到当前应用程序域下的继承了ISessionStateStoreBehavior接口的所有实现类,并读取配置得到当前实例。

基于MongoDB的一个行为实现

/// <summary>
/// 基于Mongo的Session状态存储行为
/// </summary>
public class MongoSessionStateStoreBehavior : SessionStateStoreBehaviorBase, ISessionStateStoreBehavior
{
/// <summary>
/// 构造函数
/// </summary>
public MongoSessionStateStoreBehavior()
: base()
{
if (collection == null)
{
collection = GetMongoDBCollection();
var expiresKey = IndexKeys.Ascending("Expires");
var options = IndexOptions.SetTimeToLive(base.SessionStateSection.Timeout);
collection.EnsureIndex(expiresKey, options);
collection.EnsureIndex("LockId", "Locked");
}
} static MongoCollection<MongoDBSessionDo> collection; /// <summary>
/// 获取Mongo集合
/// </summary>
/// <returns></returns>
static MongoCollection<MongoDBSessionDo> GetMongoDBCollection()
{
var url = new MongoUrl(SessionProviderConfigurationSectionHandler.SessionProviderSettings.StorageConnectionString);
var client = new MongoClient(url);
var database = client.GetServer().GetDatabase(url.DatabaseName, WriteConcern.Unacknowledged);
return database.GetCollection<MongoDBSessionDo>(ConfigSection.SessionProviderConfigurationSectionHandler.SessionProviderSettings.SessionProfix);
} /// <summary>
/// 创建未初始化项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="timeout"></param>
public void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout)
{
var session = new MongoDBSessionDo()
{
SessionId = id,
Created = DateTime.Now,
Expires = DateTime.Now.AddMinutes(base.SessionStateSection.Timeout.TotalMinutes),
LockDate = DateTime.Now,
LockId = ,
Timeout = timeout,
Locked = false,
Flags = (int)SessionStateActions.InitializeItem,
};
collection.Save(session);
SetSessionIdCookieExpires(context, session.Expires);
} /// <summary>
/// 获取项
/// </summary>
/// <param name="lockRecord"></param>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="locked"></param>
/// <param name="lockAge"></param>
/// <param name="lockId"></param>
/// <param name="actions"></param>
/// <returns></returns>
public System.Web.SessionState.SessionStateStoreData GetItem(bool lockRecord, System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out System.Web.SessionState.SessionStateActions actions)
{
var item = default(SessionStateStoreData);
lockAge = TimeSpan.Zero;
lockId = null;
locked = false;
actions = ; bool foundRecord = false;
bool deleteData = false; var session = collection.AsQueryable().FirstOrDefault(s => s.SessionId == id); if (lockRecord)
{
locked = session != null && !session.Locked && session.Expires > DateTime.Now;
} if (session != null)
{
if (session.Expires < DateTime.Now)
{
locked = false;
deleteData = true;
}
else
{
foundRecord = true;
}
} if (deleteData)
{
collection.Remove(Query.EQ("_id", id));
} if (!foundRecord)
locked = false; if (foundRecord && !locked)
{
lockId = lockId == null ? : (int)lockId + ;
collection.Update(Query.EQ("_id", id), Update.Set("LockId", (int)lockId).Set("Flags", (int)SessionStateActions.None));
var timeout = actions == SessionStateActions.InitializeItem ? (int)base.SessionStateSection.Timeout.TotalMinutes : session.Timeout;
var sessionStateItemCollection = actions == SessionStateActions.InitializeItem ? new SessionStateItemCollection() : Helper.Deserialize(session.SessionItems);
item = new SessionStateStoreData(sessionStateItemCollection, SessionStateUtility.GetSessionStaticObjects(context), timeout);
} return item;
} /// <summary>
/// 释放项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="lockId"></param>
public void ReleaseItem(System.Web.HttpContext context, string id, object lockId)
{
var expires = DateTime.Now.AddMinutes(base.SessionStateSection.Timeout.TotalMinutes);
collection.Update(Query.And(Query.EQ("LockId", int.Parse(lockId.ToString())), Query.EQ("_id", id)), Update.Set("Locked", false).Set("Expires", expires));
SetSessionIdCookieExpires(context, expires);
} /// <summary>
/// 移除项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="lockId"></param>
public void RemoveItem(System.Web.HttpContext context, string id, object lockId)
{
collection.Remove(Query.And(Query.EQ("LockId", int.Parse(lockId.ToString())), Query.EQ("_id", id)));
SetSessionIdCookieExpires(context, DateTime.Now.AddDays(-), true);
} /// <summary>
/// 重设项超时时间
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
public void ResetItemTimeout(System.Web.HttpContext context, string id)
{
var expires = DateTime.Now.AddMinutes(base.SessionStateSection.Timeout.TotalMinutes);
collection.Update(Query.And(Query.EQ("_id", id)), Update.Set("Expires", expires));
SetSessionIdCookieExpires(context, expires);
} /// <summary>
/// 设置并释放项
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
/// <param name="item"></param>
/// <param name="lockId"></param>
/// <param name="newItem"></param>
public void SetAndReleaseItem(System.Web.HttpContext context, string id, System.Web.SessionState.SessionStateStoreData item, object lockId, bool newItem)
{
var session = default(MongoDBSessionDo);
if (newItem)
{
session = new MongoDBSessionDo();
session.SessionId = id;
session.Created = DateTime.Now;
session.Expires = DateTime.Now.AddMinutes(base.SessionStateSection.Timeout.TotalMinutes);
session.LockDate = DateTime.Now;
session.LockId = ;
session.Timeout = item.Timeout;
session.Locked = false;
session.Flags = (int)SessionStateActions.None;
session.SessionItems = Helper.Serialize((SessionStateItemCollection)item.Items);
}
else
{
session = collection.FindOne(Query.And(Query.EQ("_id", id), Query.EQ("LockId", int.Parse(lockId.ToString()))));
session.Expires = DateTime.Now.AddMinutes(item.Timeout);
session.SessionItems = Helper.Serialize((SessionStateItemCollection)item.Items);
session.Locked = false;
}
collection.Save(session);
SetSessionIdCookieExpires(context, session.Expires);
}
}

配置相关

<configSections>
<section name="SessionProviderSettings" type="CustomSessionDemo.SessionProviderConfigurationSectionHandler, CustomSessionDemo"/>
</configSections> <SessionProviderSettings>
<SessionProfix>Test</SessionProfix>
<IsSynchronousSessionIdTimeout>true</IsSynchronousSessionIdTimeout>
<SessionStateStoreProviderBehaviorName>Mongo</SessionStateStoreProviderBehaviorName>
<StorageConnectionString>mongodb://192.168.1.43:27017/TestSessionDB</StorageConnectionString>
</SessionProviderSettings> <system.web>
<sessionState mode="Custom" customProvider="SessionProvider" sessionIDManagerType="CustomSessionDemo.CustomSessionIDManager" timeout="">
<providers>
<add name="SessionProvider" type="CustomSessionDemo.CustomSessionStateStoreProvider, CustomSessionDemo"/>
</providers>
</sessionState>

执行效果

可灵活扩展的自定义Session状态存储驱动的更多相关文章

  1. 【ASP.NET Core】自定义Session的存储方式

    在开始今天的表演之前,老周先跟大伙伴们说一句:"中秋节快乐". 今天咱们来聊一下如何自己动手,实现会话(Session)的存储方式.默认是存放在分布式内存中.由于HTTP消息是无状 ...

  2. 自定义session的存储机制

    <?php class MSession implements SessionHandlerInterface{ // reids 对象 protected $handler = null; / ...

  3. ThinkPHP - session 数据库存储驱动

    命名格式: Session + 驱动名称 + .class.php 所有的方法要有,但不一定要实现. <?php /** * @category Extend * @package Extend ...

  4. Session 知识点再整理(二) 自定义 Session 存储机制

    对于访问量大的网站,用默认的 Session 存储方式(以文件存储)不适合,因为文件的 I/O 开销会非常大,另外 Session 机制本身使 Session 不能跨机访问,在 Web 集群中无法达到 ...

  5. Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局

    Android实训案例(八)--单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局 阿法狗让围棋突然就被热议了,鸿洋大神也顺势出了篇五子棋单机游戏的视频,我看到了就像膜拜膜拜,就 ...

  6. Web APi 2.0优点和特点?在Web APi中如何启动Session状态?

    前言 曾几何时,微软基于Web服务技术给出最流行的基于XML且以扩展名为.asmx结尾的Web Service,此服务在.NET Framework中风靡一时同时也被.NET业界同仁所青睐,几年后在此 ...

  7. ASP.net 中关于Session的存储信息及其它方式存储信息的讨论与总结

    通过学习和实践笔者总结一下Session 的存储方式.虽然里面的理论众所周知,但是我还是想记录并整理一下.作为备忘录吧.除了ASP.net通过Web.config配置的方式,还有通过其它方式来存储的方 ...

  8. session的存储方式和配置

    Session又称为会话状态,是Web系统中最常用的状态,用于维护和当前浏览器实例相关的一些信息.我们控制用户去权限中经常用到Session来存储用户状态,这篇文章会讲下Session的存储方式.在w ...

  9. Tornado之自定义session

      面向对象基础 面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ .__delitem__.__setitem__方法 #!/usr/bin/env python # -*- ...

随机推荐

  1. 关于VS2010error RC2170 : bitmap file res\tmp1.bmp is not in 3.00 format

      我们有时候向VS中的程序插入图片,会出现如下错误: 这是VS的一个bug,对于不能识别的资源,添加的时候,VS会弹出一个对话框让你填类型,这个类型其实是字符串表示,而不是像内置类型,例如整数. 解 ...

  2. CentOS7下通过rpm方式安装MySQL及插入中文问题解决 [原创]

    一 CentOS下通过rpm方式安装MySQL CentOS版本:CentOS-7 MySQL版本:MySQL-5.6.22 在网上搜了一下,Linux下安装MYSQL有三种方式: 1) 通过yum命 ...

  3. Daily Scrum3

    今天我们小组开会内容分为以下部分: part 1: 汇报之前分配的任务进度: part 2:分配明天的任务. ◆Part 1 组员进度报告 彭佟小组完成的优化目标:     关于软件防滥用及垃圾信息拦 ...

  4. 封装insertAfter、addClass、格式化时间

    insertAfter,在JS节点操作中,并没有insertAfter方法,因此需要重新封装 function insertAfter(newEle,targetNode) { var oParent ...

  5. Xamarin.Android之山有木兮之木有枝,心悦君兮君不知。

    Xamarin.Android之山有木兮之木有枝,心悦君兮君不知. 第一步,写项目中的第一个界面. <?xml version="1.0" encoding ="  ...

  6. 我给女朋友讲编程html系列(2) --Html标题标签h1

    Html是一门标签语言,因此学习Html最快的方式就是学习使用html标签. html标题标签:h1,h2,h3,h4,h5,h6 标题标签总共有6个,h1,h2,h3,h4,h5,h6,从h1到h6 ...

  7. The code of method _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit

    如果你是通过搜索来到本文的,相信你应该是遇到了如下的错误 The code of method _jspService(HttpServletRequest, HttpServletResponse) ...

  8. 【BZOJ】【1878】【SDOI2009】HH的项链

    树状数组/前缀和 Orz lct1999 好神的做法... 先看下暴力的做法:对于区间[l,r],我们依次扫过去,如果这个数是第一次出现,那么我们种类数+1. 我们发现:区间中相同的几个数,只有最左边 ...

  9. 【BZOJ】【1520】【POI2006】Szk-Schools

    网络流/费用流 比较裸的一道题 依旧是二分图模型,由源点S连向每个学校 i (1,0),「注意是连向第 i 所学校,不是连向学校的标号m[i]……唉这里WA了一次」 然后对于每所学校 i 连接 j+n ...

  10. Android ADT中增大AVD内存后无法启动:emulator failed to allocate memory 8 (转)

    Android ADT中增大AVD内存后无法启动:emulator failed to allocate memory 8http://www.crifan.com/android_emulator_ ...