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

网友投稿 539 2023-04-25

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

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

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

先看看配置文件:

 <***Session>   SessionDB   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost    mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost   mongodb://localhost 

从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("");              Response.Write(Session["B"].ToString());              Response.Write("");              Response.Write(Session["C"].ToString());          }          protected void btnAbandon_Click(object sender, EventArgs e)          {              Session.Abandon();          }

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

这个要配置web.config:

                                    

这里会牵扯出2个类:

A2DFramework.SessionService.***SessionIDManagerA2DFramework.SessionService.***SessionStateStore

***SessionIDManager

自定义生成的cookie值(也就是SessionID),在这个sample中,会生成如“E.asadfalkasdfjal”这样的SessionID,其中前缀E代表这个Session的信息会映射到哪台***上。关键代码

public class ***SessionIDManager : 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#

***SessionStateStore

自定义Session过程中最核心的一个类,代码如下(较多):

public sealed class ***SessionStateStore : 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              ***SessionEntity session = new ***SessionEntity();              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<***SessionEntity> collection = Helper.Get***Collection(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<***SessionEntity> collection = Helper.Get***Collection(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<***SessionEntity> collection = Helper.Get***Collection(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<***SessionEntity> collection = Helper.Get***Collection(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<***SessionEntity> collection = Helper.Get***Collection(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                  ***SessionEntity session = new ***SessionEntity();                  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())));                  ***SessionEntity 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<***SessionEntity> collection = Helper.Get***Collection(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", ***.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));              ***SessionEntity 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<***SessionEntity> Get***Collection(string sessionId)          {              IPartitionResolver resolver = new ***SessionPartitionResolver();              string mongoDbConnectionString = resolver.ResolvePartition(sessionId);               MongoClient client = new MongoClient(mongoDbConnectionString);              MongoServer srv = client.GetServer();              MongoDatabase db = srv.GetDatabase(SessionConfiguration.***Name);              if (!db.CollectionExists(SessionConfiguration.***CollectionName))                  db.CreateCollection(SessionConfiguration.***CollectionName);               MongoCollection<***SessionEntity> collection = db.GetCollection<***SessionEntity>(SessionConfiguration.***CollectionName);               return collection;          }

#p#

运行效果:

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:MySQL创始人:毫无理由再继续使用MySQL
下一篇:phpMyAdmin项目诞生15周年
相关文章