基于MongoDB打造.Net的分布式Session子系统

发布时间:2025-05-18 00:45:53 作者:益华网络 来源:undefined 浏览量(1) 点赞(2)
摘要:Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式Session框架。 先看看配置文件: <?xmlversion="1.0"encoding="utf-8"?><MongoDBSession><DbName>SessionDB<

Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式Session框架。

先看看配置文件:

<?xml version="1.0" encoding="utf-8" ?> 

<MongoDBSession>   <DbName>SessionDB</DbName>   <IdentityMap Identity="A">mongodb://localhost</IdentityMap>   <IdentityMap Identity="B">mongodb://localhost</IdentityMap>   <IdentityMap Identity="C">mongodb://localhost</IdentityMap>   <IdentityMap Identity="D">mongodb://localhost</IdentityMap>   <IdentityMap Identity="E">mongodb://localhost</IdentityMap>   <IdentityMap Identity="F">mongodb://localhost</IdentityMap>   <IdentityMap Identity="G">mongodb://localhost</IdentityMap>   <IdentityMap Identity="H">mongodb://localhost</IdentityMap>   <IdentityMap Identity="I">mongodb://localhost</IdentityMap>   <IdentityMap Identity="J">mongodb://localhost</IdentityMap>   <IdentityMap Identity="K">mongodb://localhost</IdentityMap>   <IdentityMap Identity="L">mongodb://localhost</IdentityMap>   <IdentityMap Identity="M">mongodb://localhost</IdentityMap>   <IdentityMap Identity="N">mongodb://localhost</IdentityMap>   <IdentityMap Identity="O">mongodb://localhost</IdentityMap>   <IdentityMap Identity="P">mongodb://localhost</IdentityMap>   <IdentityMap Identity="Q">mongodb://localhost</IdentityMap>   <IdentityMap Identity="R">mongodb://localhost</IdentityMap>   <IdentityMap Identity="S">mongodb://localhost</IdentityMap>   <IdentityMap Identity="T">mongodb://localhost</IdentityMap>   <IdentityMap Identity="U">mongodb://localhost</IdentityMap>   <IdentityMap Identity="V">mongodb://localhost</IdentityMap>   <IdentityMap Identity="W">mongodb://localhost</IdentityMap>   <IdentityMap Identity="X">mongodb://localhost</IdentityMap>   <IdentityMap Identity="Y">mongodb://localhost</IdentityMap>   <IdentityMap Identity="Z">mongodb://localhost</IdentityMap> </MongoDBSession>

从Identity A一直到Z,默认分成了26个Map,具体的C#应用代码:

protected void btnTest_Click(object sender, EventArgs e)          {              Session["A"] = DateTime.Now;              Session["B"] = 1111111111111;              Session["C"] = "fffffffffffffff";          }          protected void btnGetSession_Click(object sender, EventArgs e)          {              Response.Write(Session["A"].ToString());              Response.Write("<br />");              Response.Write(Session["B"].ToString());              Response.Write("<br />");              Response.Write(Session["C"].ToString());          }          protected void btnAbandon_Click(object sender, EventArgs e)          {              Session.Abandon();          }

呵呵,就是普通的Session用法。

这个要配置web.config:

<system.web>     <sessionState mode="Custom" customProvider="A2DSessionProvider" sessionIDManagerType="A2DFramework.SessionService.MongoDBSessionIDManager">       <providers>         <add name="A2DSessionProvider" type="A2DFramework.SessionService.MongoDBSessionStateStore"/>       </providers>     </sessionState>   </system.web>

这里会牵扯出2个类:

A2DFramework.SessionService.MongoDBSessionIDManager A2DFramework.SessionService.MongoDBSessionStateStore

 MongoDBSessionIDManager

自定义生成的cookie值(也就是SessionID),在这个sample中,会生成如“E.asadfalkasdfjal”这样的SessionID,其中前缀E代表这个Session的信息会映射到哪台MongoDB上。 关键代码 public class MongoDBSessionIDManager : SessionIDManager      {          private Random rnd = new Random();          private object oLock = new object();          public override string CreateSessionID(System.Web.HttpContext context)          {              int index = 0;              lock(this.oLock)              {                  index = rnd.Next(SessionConfiguration.SessionServerIdentities.Length);              }              string sessionId = string.Format("{0}.{1}", SessionConfiguration.SessionServerIdentities[index], base.CreateSessionID(context));              return sessionId;          }          public override string Encode(string id)          {              return DESEncryptor.Encode(id, SessionConfiguration.DESKey);          }          public override string Decode(string id)          {              return DESEncryptor.Decode(id, SessionConfiguration.DESKey);          }          public override bool Validate(string id)          {              string prefix;              string realId;              if (!Helper.ParseSessionID(id, out prefix, out realId))                  return false;              return base.Validate(realId);          }      }

#p#

MongoDBSessionStateStore

自定义Session过程中最核心的一个类,代码如下(较多): public sealed class MongoDBSessionStateStore : SessionStateStoreProviderBase      {          private SessionStateSection pConfig;          private string pApplicationName;          public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)          {              base.Initialize(name, config);              pApplicationName =System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;              System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(pApplicationName);              pConfig =(SessionStateSection)cfg.GetSection("system.web/sessionState");          }          public override SessionStateStoreData CreateNewStoreData(System.Web.HttpContext context, int timeout)          {              return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), timeout);          }          public override void CreateUninitializedItem(System.Web.HttpContext context, string id, int timeout)          {              //insert to db              MongoDBSessionEntity session = new MongoDBSessionEntity();              session.ApplicationName = this.pApplicationName;              session.SessionId = id;              session.Created = DateTime.Now;              session.Expires = DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);              session.LockDate = DateTime.Now;              session.LockId = 0;              session.Timeout = timeout;              session.Locked = false;              session.Flags = (int)SessionStateActions.InitializeItem;              MongoCollection<MongoDBSessionEntity> collection = Helper.GetMongoDBCollection(id);              collection.Save(session);          }          public override void Dispose()          {          }          public override void EndRequest(System.Web.HttpContext context)          {          }          public override SessionStateStoreData GetItem(System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)          {              return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actions);          }          public override SessionStateStoreData GetItemExclusive(System.Web.HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)          {              return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actions);          }          public override void InitializeRequest(System.Web.HttpContext context)          {          }          public override void ReleaseItemExclusive(System.Web.HttpContext context, string id, object lockId)          {              //update locked=0, expired=, where lockId=?              MongoCollection<MongoDBSessionEntity> collection = Helper.GetMongoDBCollection(id);              var query = Query.And(  Query.EQ("LockId", int.Parse(lockId.ToString())),                                      Query.EQ("_id", id),                                       Query.EQ("ApplicationName", pApplicationName));              var update = Update.Set("Locked", false)                                  .Set("Expires", DateTime.Now.AddMinutes(pConfig.Timeout.Minutes));              collection.Update(query, update);          }          public override void RemoveItem(System.Web.HttpContext context, string id, object lockId, SessionStateStoreData item)          {              //delete where sessionId=? and lockId=? and applicationname=?              MongoCollection<MongoDBSessionEntity> collection = Helper.GetMongoDBCollection(id);              var query = Query.And(Query.EQ("LockId", int.Parse(lockId.ToString())),                                      Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName));              collection.Remove(query);          }          public override void ResetItemTimeout(System.Web.HttpContext context, string id)          {              //update expire date              MongoCollection<MongoDBSessionEntity> collection = Helper.GetMongoDBCollection(id);              var query = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName));              var update = Update.Set("Expires", DateTime.Now.AddMinutes(pConfig.Timeout.Minutes));              collection.Update(query, update);          }          public override void SetAndReleaseItemExclusive(System.Web.HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)          {              MongoCollection<MongoDBSessionEntity> collection = Helper.GetMongoDBCollection(id);              if (newItem)              {                  //delete expired items                  var query = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName),                                      Query.LT("Expires", DateTime.Now));                  collection.Remove(query);                  //insert new item                  MongoDBSessionEntity session = new MongoDBSessionEntity();                  session.ApplicationName = this.pApplicationName;                  session.SessionId = id;                  session.Created = DateTime.Now;                  session.Expires = DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);                  session.LockDate = DateTime.Now;                  session.LockId = 0;                  session.Timeout = item.Timeout;                  session.Locked = false;                  session.Flags = (int)SessionStateActions.None;                  session.SessionItems = Helper.Serialize((SessionStateItemCollection)item.Items);                  collection.Save(session);              }              else             {                  //update item                  var query = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName),                                      Query.EQ("LockId", int.Parse(lockId.ToString())));                  MongoDBSessionEntity entity= collection.FindOne(query);                  entity.Expires = DateTime.Now.AddMinutes(item.Timeout);                  entity.SessionItems = Helper.Serialize((SessionStateItemCollection)item.Items);                  entity.Locked = false;                  collection.Save(entity);              }          }          public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)          {              return false;          }          private SessionStateStoreData GetSessionStoreItem(bool lockRecord, System.Web.HttpContext context,                                                               string id,                                                              out bool locked,                                                              out TimeSpan lockAge,                                                              out object lockId,                                                              out SessionStateActions actions)          {              SessionStateStoreData item = null;                lockAge = TimeSpan.Zero;              lockId = null;              locked = false;              actions = 0;              bool foundRecord = false;              bool deleteData = false;              MongoCollection<MongoDBSessionEntity> collection = Helper.GetMongoDBCollection(id);              if (lockRecord)              {                   //update db, set locked=1, lockdate=now                  var query1 = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName),                                      Query.EQ("Locked", MongoDB.Bson.BsonValue.Create(false)),                                      Query.GT("Expires", DateTime.UtcNow));                  long count = collection.Find(query1).Count();                  if (count == 0)                  {                      locked = true;                  }                  else                 {                      var update = Update.Set("Locked", true).Set("LockDate", DateTime.Now);                      collection.Update(query1, update);                      locked = false;                  }              }              //get item by id              var query2 = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName));              MongoDBSessionEntity entity=collection.FindOne(query2);              if (entity != null)              {                  if (entity.Expires < DateTime.Now)                  {                      locked = false;                      deleteData = true;                  }                  else                 {                      foundRecord = true;                  }              }              //delete item if session expired              if (deleteData)              {                  var query3 = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName));                  collection.Remove(query3);              }              if (!foundRecord)                  locked = false;              if (foundRecord && !locked)              {                  if (lockId == null)                      lockId = 0;                  lockId = (int)lockId + 1;                  var query4 = Query.And(Query.EQ("_id", id),                                      Query.EQ("ApplicationName", pApplicationName));                  var update4 = Update.Set("LockId", (int)lockId)                                          .Set("Flags", (int)SessionStateActions.None);                  collection.Update(query4, update4);                  if (actions == SessionStateActions.InitializeItem)                      item = CreateNewStoreData(context, pConfig.Timeout.Minutes);                  else                     item = Helper.Deserialize(context, entity.SessionItems, entity.Timeout);              }              return item;          }      }

由于很多方法会用到MongoCollection,因此写了个static公用函数,如下:

public static MongoCollection<MongoDBSessionEntity> GetMongoDBCollection(string sessionId)          {              IPartitionResolver resolver = new MongoDBSessionPartitionResolver();              string mongoDbConnectionString = resolver.ResolvePartition(sessionId);              MongoClient client = new MongoClient(mongoDbConnectionString);              MongoServer srv = client.GetServer();              MongoDatabase db = srv.GetDatabase(SessionConfiguration.MongoDBName);              if (!db.CollectionExists(SessionConfiguration.MongoDBCollectionName))                  db.CreateCollection(SessionConfiguration.MongoDBCollectionName);              MongoCollection<MongoDBSessionEntity> collection = db.GetCollection<MongoDBSessionEntity>(SessionConfiguration.MongoDBCollectionName);              return collection;          }

#p#

运行效果:

 

 点击Set Session后:

点击Get Session后:

点击Abandon后:

 

 源代码已经更新到A2D Framework中了。

原文链接:http://www.cnblogs.com/aarond/p/MongoSession.html

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!