溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何利用MongoDB打造.Net的分布式Session子系統(tǒng)

發(fā)布時(shí)間:2021-10-29 17:32:43 來(lái)源:億速云 閱讀:140 作者:柒染 欄目:編程語(yǔ)言

本篇文章為大家展示了如何利用MongoDB打造.Net的分布式Session子系統(tǒng),內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

Taobao有她自己的分布式session框架,.net陣營(yíng)也不能落后了,在下做了個(gè)基于MongoDB的支持最多26臺(tái)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,默認(rèn)分成了26個(gè)Map,具體的C#應(yīng)用代碼:

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用法。

這個(gè)要配置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>

這里會(huì)牽扯出2個(gè)類:

  1. A2DFramework.SessionService.MongoDBSessionIDManager

  2. A2DFramework.SessionService.MongoDBSessionStateStore

MongoDBSessionIDManager

  • 自定義生成的cookie值(也就是SessionID),在這個(gè)sample中,會(huì)生成如“E.asadfalkasdfjal”這樣的SessionID,其中前綴E代表這個(gè)Session的信息會(huì)映射到哪臺(tái)MongoDB上。

  • 關(guān)鍵代碼

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);          }      }

MongoDBSessionStateStore

  • 自定義Session過(guò)程中最核心的一個(gè)類,代碼如下(較多):

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;          }      }

由于很多方法會(huì)用到MongoCollection,因此寫了個(gè)static公用函數(shù),如下:

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;          }

運(yùn)行效果:

如何利用MongoDB打造.Net的分布式Session子系統(tǒng)

點(diǎn)擊Set Session后:

如何利用MongoDB打造.Net的分布式Session子系統(tǒng)

點(diǎn)擊Get Session后:

如何利用MongoDB打造.Net的分布式Session子系統(tǒng)

點(diǎn)擊Abandon后:

如何利用MongoDB打造.Net的分布式Session子系統(tǒng)

源代碼已經(jīng)更新到A2D Framework中了。

上述內(nèi)容就是如何利用MongoDB打造.Net的分布式Session子系統(tǒng),你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI