黄东旭解析 TiDB 的核心优势
499
2023-04-25
基于***打造.Net的分布式Session子系统
Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于***的支持最多26台***的分布式Session框架。
先看看配置文件:
<***Session>
从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小时内删除侵权内容。