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

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

Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

从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();  
        } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

呵呵,就是普通的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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这里会牵扯出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);  
        }  
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

#p#

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;  
        }  
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.

由于很多方法会用到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;  
        } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

#p#

运行效果:

 

 点击Set Session后:

点击Get Session后:

点击Abandon后:

 

 

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

原文链接:http://www.cnblogs.com/aarond/p/MongoSession.html

责任编辑:林师授 来源: 博客园
相关推荐

2023-12-29 08:18:31

Session分布式系统微服务

2011-11-03 10:07:09

ASP.NET

2023-05-12 08:23:03

分布式系统网络

2023-02-11 00:04:17

分布式系统安全

2017-10-24 11:28:23

Zookeeper分布式锁架构

2015-04-21 09:39:03

javajava分布式爬虫

2023-05-29 14:07:00

Zuul网关系统

2024-05-06 00:00:00

.NET分布式锁技术

2019-07-31 08:44:27

Session共享Memcache

2021-03-08 09:56:24

存储分布式Session

2017-10-27 08:40:44

分布式存储剪枝系统

2023-10-26 18:10:43

分布式并行技术系统

2011-05-11 16:42:21

.NET Remoti

2017-04-13 10:51:09

Consul分布式

2022-03-08 15:24:23

BitMapRedis数据

2017-10-17 08:33:31

存储系统分布式

2019-07-17 22:23:01

分布式系统负载均衡架构

2017-12-05 09:43:42

分布式系统核心

2023-04-26 08:01:09

分布式编译系统

2009-02-10 08:57:01

分布式缓存.Net开发
点赞
收藏

51CTO技术栈公众号