/// <summary> /// Checks if any items have changed in the Session, and stores the results to Redis /// </summary> /// <param name="context">The HttpContext of the current web request</param> /// <param name="id">The Session Id and Redis key name</param> /// <param name="item">The Session properties</param> /// <param name="lockId">The object used to exclusively lock the Session (there shouldn't be one)</param> /// <param name="newItem">Whether or not the Session was created in this HttpContext</param> public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) { try { string currentRedisHashId = RedisSessionStateStoreProvider.RedisHashIdFromSessionId( new HttpContextWrapper(context), id); LocalSharedSessionDictionary sharedSessDict = new LocalSharedSessionDictionary(); RedisSessionStateItemCollection redisItems = sharedSessDict.GetSessionForEndRequest(currentRedisHashId); if (redisItems != null) { RedisSessionStateStoreProvider.SerializeToRedis( new HttpContextWrapper(context), redisItems, currentRedisHashId, this.SessionTimeout); } } catch (Exception e) { if (RedisSessionConfig.SessionExceptionLoggingDel != null) { RedisSessionConfig.SessionExceptionLoggingDel(e); } } }
public void OnBeforeTestExecute() { srsly = new RedisJSONSerializer(); this.items = new RedisSessionStateItemCollection( new Dictionary<string, byte[]> { { "a", Encoding.UTF8.GetBytes(srsly.SerializeOne("a", "x")) }, { "b", Encoding.UTF8.GetBytes(srsly.SerializeOne("b", "y")) }, { "c", Encoding.UTF8.GetBytes(srsly.SerializeOne("c", "z")) } }, "fakeCollection"); }
/// <summary> /// Helper method for serializing objects to Redis /// </summary> /// <param name="confirmedChangedObjects">keys and values that have definitely changed</param> /// <param name="allObjects">keys and values that have been accessed during the current HttpContext</param> /// <param name="allObjectsOriginalState">keys and serialized values before we tampered with them</param> /// <param name="deletedObjects">keys that were deleted during the current HttpContext</param> /// <param name="currentRedisHashId">The current Redis key name</param> /// <param name="redisConn">A connection to Redis</param> public static void SerializeToRedis( HttpContextBase context, RedisSessionStateItemCollection redisItems, string currentRedisHashId, TimeSpan expirationTimeout) { List <HashEntry> setItems = new List <HashEntry>(); List <RedisValue> delItems = new List <RedisValue>(); RedisConnectionWrapper rConnWrap = RedisSessionStateStoreProvider.RedisConnWrapperFromContext( context); foreach (KeyValuePair <string, string> changedObj in redisItems.GetChangedObjectsEnumerator()) { if (changedObj.Value != null) { setItems.Add( new HashEntry( changedObj.Key, changedObj.Value)); } else { delItems.Add(changedObj.Key); } } IDatabase redisConn = rConnWrap.GetConnection(); redisConn.KeyExpire( currentRedisHashId, expirationTimeout, CommandFlags.FireAndForget); if (setItems.Count > 0) { redisConn.HashSet( currentRedisHashId, setItems.ToArray(), CommandFlags.FireAndForget); } if (delItems != null && delItems.Count > 0) { redisConn.HashDelete( currentRedisHashId, delItems.ToArray(), CommandFlags.FireAndForget); } }
/// <summary> /// Helper method for serializing objects to Redis /// </summary> /// <param name="confirmedChangedObjects">keys and values that have definitely changed</param> /// <param name="allObjects">keys and values that have been accessed during the current HttpContext</param> /// <param name="allObjectsOriginalState">keys and serialized values before we tampered with them</param> /// <param name="deletedObjects">keys that were deleted during the current HttpContext</param> /// <param name="currentRedisHashId">The current Redis key name</param> /// <param name="redisConn">A connection to Redis</param> public static void SerializeToRedis(HttpContextBase context, RedisSessionStateItemCollection redisItems, string currentRedisHashId, TimeSpan expirationTimeout) { RedisConnectionWrapper rConnWrap = RedisSessionStateStoreProvider.RedisConnWrapperFromContext(context); var setItems = new List <HashEntry>(); var delItems = new List <RedisValue>(); // Determine if we are adding or removing keys, separate them into their own lists // note that redisItems.GetChangedObjectsEnumerator contains complex logic foreach (KeyValuePair <string, string> changedObj in redisItems.GetChangedObjectsEnumerator()) { if (changedObj.Value != null) { setItems.Add(new HashEntry(changedObj.Key, changedObj.Value)); } else { delItems.Add(changedObj.Key); } } IDatabase redisConn = rConnWrap.GetConnection(currentRedisHashId); if (setItems.Count > 0) { HashEntry[] writeItems = setItems.ToArray(); redisConn.HashSet(currentRedisHashId, writeItems, CommandFlags.FireAndForget); // call appropriate delegate if set for changing keys if (RedisSessionConfig.RedisWriteFieldDel != null) { RedisSessionConfig.RedisWriteFieldDel(context, writeItems, currentRedisHashId); } } if (delItems != null && delItems.Count > 0) { RedisValue[] removeItems = delItems.ToArray(); redisConn.HashDelete(currentRedisHashId, removeItems, CommandFlags.FireAndForget); // call appropriate delegate if set for removing keys if (RedisSessionConfig.RedisRemoveFieldDel != null) { RedisSessionConfig.RedisRemoveFieldDel(context, removeItems, currentRedisHashId); } } // always refresh the timeout of the session hash redisConn.KeyExpire(currentRedisHashId, expirationTimeout, CommandFlags.FireAndForget); }
/// <summary> /// Initializes a new instance of the RedisSessionAccessor class, which provides access to a /// local Redis items collection outside of the standard ASP.NET pipeline Session hooks /// </summary> /// <param name="context">The context of the current request</param> public RedisSessionAccessor(HttpContextBase context) { try { this.RequestContext = context; this.SharedSessions = new LocalSharedSessionDictionary(); // if we have the session ID if (this.RequestContext.Request.Cookies[RedisSessionConfig.SessionHttpCookieName] != null) { this.SessionRedisHashKey = RedisSessionStateStoreProvider.RedisHashIdFromSessionId( this.RequestContext, this.RequestContext.Request.Cookies[RedisSessionConfig.SessionHttpCookieName].Value); } if (!string.IsNullOrEmpty(this.SessionRedisHashKey)) { RedisSessionStateItemCollection items = this.SharedSessions.GetSessionForBeginRequest( this.SessionRedisHashKey, (string redisKey) => { return(RedisSessionStateStoreProvider.GetItemFromRedis( redisKey, this.RequestContext, RedisSessionConfig.SessionTimeout)); }); this.Session = new FakeHttpSessionState( items, this.RequestContext.Request.Cookies[RedisSessionConfig.SessionHttpCookieName].Value); } } catch (Exception exc) { if (RedisSessionConfig.RedisSessionAccessorExceptionLoggingDel != null) { string errMsg = string.Format( "RedisSessionAccessor unable to get Redis session for id: {0}", this.SessionRedisHashKey); RedisSessionConfig.RedisSessionAccessorExceptionLoggingDel( context, errMsg, exc); } } }
public void Dispose() { // record with local shared session storage that we are done with the session so it gets // cleared out sooner RedisSessionStateItemCollection items = this.SharedSessions.GetSessionForEndRequest(this.SessionRedisHashKey); if (items != null) { RedisSessionStateStoreProvider.SerializeToRedis( this.RequestContext, items, this.SessionRedisHashKey, RedisSessionConfig.SessionTimeout); } }
/// <summary> /// Gets a Session from Redis, indicating a non-exclusive lock on the Session. Note that GetItemExclusive /// calls this method internally, meaning we do not support locks at all retrieving the Session. /// </summary> /// <param name="context">The HttpContext of the current request</param> /// <param name="id">The Session Id, which is the key name in Redis</param> /// <param name="locked">Whether or not the Session is locked to exclusive access for a single request /// thread</param> /// <param name="lockAge">The age of the lock</param> /// <param name="lockId">The object used to lock the Session</param> /// <param name="actions">Whether or not to initialize the Session (never)</param> /// <returns>The Session objects wrapped in a SessionStateStoreData object</returns> public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) { locked = false; lockAge = new TimeSpan(0); lockId = null; actions = SessionStateActions.None; if (id == null) { return(this.CreateNewStoreData(context, Convert.ToInt32(this.SessionTimeout.TotalMinutes))); } try { string parsedRedisHashId = RedisSessionStateStoreProvider.RedisHashIdFromSessionId( new HttpContextWrapper(context), id); LocalSharedSessionDictionary sharedSessDict = new LocalSharedSessionDictionary(); RedisSessionStateItemCollection items = sharedSessDict.GetSessionForBeginRequest( parsedRedisHashId, (redisKey) => { return(RedisSessionStateStoreProvider.GetItemFromRedis( redisKey, new HttpContextWrapper(context), this.SessionTimeout)); }); return(new SessionStateStoreData( items, SessionStateUtility.GetSessionStaticObjects(context), Convert.ToInt32(this.SessionTimeout.TotalMinutes))); } catch (Exception e) { if (RedisSessionConfig.SessionExceptionLoggingDel != null) { RedisSessionConfig.SessionExceptionLoggingDel(e); } } return(this.CreateNewStoreData(context, Convert.ToInt32(this.SessionTimeout.TotalMinutes))); }
/// <summary> /// Gets a session for a given redis ID, and increments the count of the number of requests /// that have accessed this redis ID /// </summary> /// <param name="redisHashId">The id of the session in Redis</param> /// <param name="getDel">The delegate to run to fetch the session from Redis</param> /// <returns>A RedisSessionStateItemCollection for the session</returns> public RedisSessionStateItemCollection GetSessionForBeginRequest( string redisHashId, Func <string, RedisSessionStateItemCollection> getDel) { SessionAndRefCount sessAndCount = LocalSharedSessionDictionary.localCache.AddOrUpdate( redisHashId, (redisKey) => { RedisSessionStateItemCollection itms = getDel(redisHashId); return(new SessionAndRefCount(itms)); }, (redisKey, existingItem) => { Interlocked.Increment(ref existingItem.RequestReferences); existingItem.LastAccess = DateTime.Now; return(existingItem); }); return(sessAndCount.Sess); }
/// <summary> /// Checks if any items have changed in the Session, and stores the results to Redis /// </summary> /// <param name="context">The HttpContext of the current web request</param> /// <param name="id">The Session Id and Redis key name</param> /// <param name="item">The Session properties</param> /// <param name="lockId">The object used to exclusively lock the Session (there shouldn't be one)</param> /// <param name="newItem">Whether or not the Session was created in this HttpContext</param> public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) { try { string currentRedisHashId = RedisSessionStateStoreProvider.RedisHashIdFromSessionId( new HttpContextWrapper(context), id); LocalSharedSessionDictionary sharedSessDict = new LocalSharedSessionDictionary(); RedisSessionStateItemCollection redisItems = sharedSessDict.GetSessionForEndRequest(currentRedisHashId); // we were unable to pull it from shared cache, meaning either this is the first request or // something went wrong with the local cache. We still have all the parts needed to write // to redis, however, by looking at SessionStateStoreData passed in from the Session module // and the current hash key provided by the id parameter. if (redisItems == null) { redisItems = (RedisSessionStateItemCollection)item.Items; } if (redisItems != null) { RedisSessionStateStoreProvider.SerializeToRedis( new HttpContextWrapper(context), redisItems, currentRedisHashId, this.SessionTimeout); } } catch (Exception e) { if (RedisSessionConfig.SessionExceptionLoggingDel != null) { RedisSessionConfig.SessionExceptionLoggingDel(e); } } }
/// <summary> /// Initializes a new instance of the SessionAndRefCount class with a given item collection /// and count of requests using it /// </summary> /// <param name="itms">The items in a session</param> /// <param name="count">The number of requests accessing this session</param> public LocalSessionInfo(RedisSessionStateItemCollection itms, int count) { this.SessionData = itms; this.outstandingRequests = count; this.LastAccess = DateTime.Now; }
/// <summary> /// Initializes a new instance of the SessionAndRefCount class with a given item collection /// </summary> /// <param name="itms">The items in a session</param> public LocalSessionInfo(RedisSessionStateItemCollection itms) : this(itms, 1) { }
/// <summary> /// Initializes a new instance of the SessionAndRefCount class with a given item collection /// and count of requests using it /// </summary> /// <param name="itms">The items in a session</param> /// <param name="count">The number of requests accessing this session</param> public SessionAndRefCount(RedisSessionStateItemCollection itms, int count) { this.Sess = itms; this.RequestReferences = count; this.LastAccess = DateTime.Now; }
/// <summary> /// Initializes a new instance of the SessionAndRefCount class with a given item collection /// </summary> /// <param name="itms">The items in a session</param> public SessionAndRefCount(RedisSessionStateItemCollection itms) : this(itms, 1) { }
/// <summary> /// Initializes a new instance of the SessionAndRefCount class with a given item collection /// and count of requests using it /// </summary> /// <param name="itms">The items in a session</param> /// <param name="count">The number of requests accessing this session</param> public SessionAndRefCount(RedisSessionStateItemCollection itms, int count) { this.Sess = itms; this.RequestReferences = count; this.LastAccess = DateTime.Now; }
/// <summary> /// Initializes a new instance of the SessionAndRefCount class with a given item collection /// </summary> /// <param name="itms">The items in a session</param> public SessionAndRefCount(RedisSessionStateItemCollection itms) : this(itms, 1) { }
public void OnBeforeTestExecute() { this.items = new RedisSessionStateItemCollection(); this.srsly = new RedisJSONSerializer(); }
/// <summary> /// Helper method for serializing objects to Redis /// </summary> /// <param name="confirmedChangedObjects">keys and values that have definitely changed</param> /// <param name="allObjects">keys and values that have been accessed during the current HttpContext</param> /// <param name="allObjectsOriginalState">keys and serialized values before we tampered with them</param> /// <param name="deletedObjects">keys that were deleted during the current HttpContext</param> /// <param name="currentRedisHashId">The current Redis key name</param> /// <param name="redisConn">A connection to Redis</param> public static void SerializeToRedis( HttpContextBase context, RedisSessionStateItemCollection redisItems, string currentRedisHashId, TimeSpan expirationTimeout) { List<HashEntry> setItems = new List<HashEntry>(); List<RedisValue> delItems = new List<RedisValue>(); RedisConnectionWrapper rConnWrap = RedisSessionStateStoreProvider.RedisConnWrapperFromContext( context); // Determine if we are adding or removing keys, separate them into their own lists // note that redisItems.GetChangedObjectsEnumerator contains complex logic foreach (KeyValuePair<string, string> changedObj in redisItems.GetChangedObjectsEnumerator()) { if (changedObj.Value != null) { setItems.Add( new HashEntry( changedObj.Key, changedObj.Value)); } else { delItems.Add(changedObj.Key); } } IDatabase redisConn = rConnWrap.GetConnection(); if (setItems.Count > 0) { HashEntry[] writeItems = setItems.ToArray(); redisConn.HashSet( currentRedisHashId, writeItems, CommandFlags.FireAndForget); // call appropriate delegate if set for changing keys if(RedisSessionConfig.RedisWriteFieldDel != null) { RedisSessionConfig.RedisWriteFieldDel( context, writeItems, currentRedisHashId); } } if (delItems != null && delItems.Count > 0) { RedisValue[] removeItems = delItems.ToArray(); redisConn.HashDelete( currentRedisHashId, removeItems, CommandFlags.FireAndForget); // call appropriate delegate if set for removing keys if(RedisSessionConfig.RedisRemoveFieldDel != null) { RedisSessionConfig.RedisRemoveFieldDel( context, removeItems, currentRedisHashId); } } // always refresh the timeout of the session hash redisConn.KeyExpire( currentRedisHashId, expirationTimeout, CommandFlags.FireAndForget); }
public FakeHttpSessionState(RedisSessionStateItemCollection items, string sessID) { this.Items = items; this.sessionID = sessID; }