如何利用MongoDB打造.Net的分布式Session子系统
本篇文章为大家展示了如何利用MongoDB打造.Net的分布式Session子系统,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
成都创新互联公司主要从事网站建设、成都网站制作、网页设计、企业做网站、公司建网站等业务。立足成都服务安阳,十余年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:13518219792
Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式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.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); } }
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; MongoCollectioncollection = 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 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 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 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 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 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 MongoCollectionGetMongoDBCollection(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 collection = db.GetCollection (SessionConfiguration.MongoDBCollectionName); return collection; }
运行效果:
点击Set Session后:
点击Get Session后:
点击Abandon后:
源代码已经更新到A2D Framework中了。
上述内容就是如何利用MongoDB打造.Net的分布式Session子系统,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注创新互联行业资讯频道。
分享文章:如何利用MongoDB打造.Net的分布式Session子系统
URL地址:http://ybzwz.com/article/jjhpde.html