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