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

来源:互联网 发布:如何制作淘宝店招图片 编辑:程序博客网 时间:2024/05/22 17:41
复制代码
<?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个类:

  1. A2DFramework.SessionService.MongoDBSessionIDManager
  2. 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;            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;        }
复制代码

 

 运行效果:

 

 点击Set Session后:

点击Get Session后:

点击Abandon后:

 

 

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

 

 

0 0
原创粉丝点击