Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 92 additions & 93 deletions src/RedisSessionStateProvider/RedisSessionStateProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,12 @@ public class RedisSessionStateProvider : SessionStateStoreProviderAsyncBase
internal static object configurationCreationLock = new object();
internal ICacheConnection cache;

private static object _lastException = new object();

/// <summary>
/// We do not want to throw exception from session state provider because this will break customer application and they can't get chance to handel it.
/// So if exception occurs because of some problem we store it in HttpContext using a key that we know and return null to customer. Now, when customer
/// get null from any of session operation they should call this method to identify if there was any exception and because of that got null.
/// How to handle exceptions alternative for LastException
/// </summary>
public static Exception LastException
{
get
{
if (HttpContext.Current != null)
{
return (Exception) HttpContext.Current.Items[_lastException];
}
return null;
}

set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[_lastException] = value;
}
}
}
public Action<Exception> ExceptionHandler { get; set; }

private void GetAccessToStore(string id)
private void GetAccessToStore(string id)
{
if (cache == null)
{
Expand All @@ -68,15 +46,15 @@ private void GetAccessToStore(string id)
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
if (config == null)
{
{
throw new ArgumentNullException("config");
}

if (name == null || name.Length == 0)
{
name = "MyCacheStore";
}

if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
Expand All @@ -88,7 +66,7 @@ public override void Initialize(string name, System.Collections.Specialized.Name
// If configuration exists then use it otherwise read from config file and create one
if (configuration == null)
{
lock (configurationCreationLock)
lock (configurationCreationLock)
{
if (configuration == null)
{
Expand Down Expand Up @@ -143,7 +121,11 @@ public override async Task EndRequestAsync(HttpContextBase context)
catch (Exception e)
{
LogUtility.LogError("EndRequest => {0}", e.ToString());
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand All @@ -163,20 +145,21 @@ public override async Task CreateUninitializedItemAsync(HttpContextBase context,
{
try
{
if (LastException == null)
{
LogUtility.LogInfo("CreateUninitializedItem => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
ISessionStateItemCollection sessionData = new ChangeTrackingSessionStateItemCollection(redisUtility);
sessionData["SessionStateActions"] = SessionStateActions.InitializeItem;
GetAccessToStore(id);
// Converting timout from min to sec
cache.Set(sessionData, (timeout * FROM_MIN_TO_SEC));
}
LogUtility.LogInfo("CreateUninitializedItem => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
ISessionStateItemCollection sessionData = new ChangeTrackingSessionStateItemCollection(redisUtility);
sessionData["SessionStateActions"] = SessionStateActions.InitializeItem;
GetAccessToStore(id);
// Converting timout from min to sec
cache.Set(sessionData, (timeout * FROM_MIN_TO_SEC));
}
catch (Exception e)
{
LogUtility.LogError("CreateUninitializedItem => {0}", e.ToString());
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand Down Expand Up @@ -222,7 +205,7 @@ private SessionStateStoreData GetItemFromSessionStore(bool isWriteLockRequired,
}
GetAccessToStore(id);
ISessionStateItemCollection sessionData = null;

int sessionTimeout;
bool isLockTaken = false;
//Take read or write lock and if locking successful than get data in sessionData and also update session timeout
Expand Down Expand Up @@ -253,7 +236,7 @@ private SessionStateStoreData GetItemFromSessionStore(bool isWriteLockRequired,
// If locking is not successful then do not return any result just return lockAge, locked=true and lockId.
// ASP.NET tries to acquire lock again in 0.5 sec by calling this method again. Using lockAge it finds if
// lock has been taken more than http request timeout than ASP.NET calls ReleaseItemExclusive and calls this method again to get lock.
if (locked)
if (locked)
{
lockAge = cache.GetLockAge(lockId);
return null;
Expand All @@ -266,9 +249,9 @@ private SessionStateStoreData GetItemFromSessionStore(bool isWriteLockRequired,
ReleaseItemExclusiveAsync(context, id, lockId, cancellationToken).Wait();
return null;
}

// Restore action flag from session data
if (sessionData["SessionStateActions"] != null)
if (sessionData["SessionStateActions"] != null)
{
actions = (SessionStateActions)Enum.Parse(typeof(SessionStateActions), sessionData["SessionStateActions"].ToString());
}
Expand All @@ -285,7 +268,11 @@ private SessionStateStoreData GetItemFromSessionStore(bool isWriteLockRequired,
lockId = null;
lockAge = TimeSpan.Zero;
actions = 0;
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand All @@ -298,18 +285,21 @@ public override async Task ResetItemTimeoutAsync(HttpContextBase context, string
{
try
{
if (LastException == null)
{
LogUtility.LogInfo("ResetItemTimeout => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
GetAccessToStore(id);
cache.UpdateExpiryTime((int)configuration.SessionTimeout.TotalSeconds);
cache = null;
}

LogUtility.LogInfo("ResetItemTimeout => Session Id: {0}, Session provider object: {1}.", id, this.GetHashCode());
GetAccessToStore(id);
cache.UpdateExpiryTime((int)configuration.SessionTimeout.TotalSeconds);
cache = null;

}
catch (Exception e)
{
LogUtility.LogError("ResetItemTimeout => {0}", e.ToString());
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand All @@ -322,17 +312,19 @@ public override async Task RemoveItemAsync(HttpContextBase context, string id, o
{
try
{
if (LastException == null)
{
LogUtility.LogInfo("RemoveItem => Session Id: {0}, Session provider object: {1}, Lock ID: {2}.", id, this.GetHashCode(), lockId);
GetAccessToStore(id);
cache.TryRemoveAndReleaseLock(lockId);
}
LogUtility.LogInfo("RemoveItem => Session Id: {0}, Session provider object: {1}, Lock ID: {2}.", id, this.GetHashCode(), lockId);
GetAccessToStore(id);
cache.TryRemoveAndReleaseLock(lockId);

}
catch (Exception e)
{
LogUtility.LogError("RemoveItem => {0}", e.ToString());
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand All @@ -356,7 +348,7 @@ public override async Task ReleaseItemExclusiveAsync(HttpContextBase context, st
sessionTimeoutInSeconds = (int)configuration.SessionTimeout.TotalSeconds;
}

if (LastException == null && lockId != null)
if (lockId != null)
{
LogUtility.LogInfo("ReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => For lockId: {2}.", id, this.GetHashCode(), lockId);
GetAccessToStore(id);
Expand All @@ -371,7 +363,11 @@ public override async Task ReleaseItemExclusiveAsync(HttpContextBase context, st
catch (Exception e)
{
LogUtility.LogError("ReleaseItemExclusive => {0}", e.ToString());
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand All @@ -384,50 +380,53 @@ public override async Task SetAndReleaseItemExclusiveAsync(HttpContextBase conte
{
try
{
if (LastException == null)

GetAccessToStore(id);
// If it is new record
if (newItem)
{
GetAccessToStore(id);
// If it is new record
if (newItem)
ISessionStateItemCollection sessionItems = null;
if (item != null && item.Items != null)
{
ISessionStateItemCollection sessionItems = null;
if (item != null && item.Items != null)
{
sessionItems = item.Items;
}
else
{
sessionItems = new ChangeTrackingSessionStateItemCollection(redisUtility);
}
sessionItems = item.Items;
}
else
{
sessionItems = new ChangeTrackingSessionStateItemCollection(redisUtility);
}

if (sessionItems["SessionStateActions"] != null)
{
sessionItems.Remove("SessionStateActions");
}
if (sessionItems["SessionStateActions"] != null)
{
sessionItems.Remove("SessionStateActions");
}

// Converting timout from min to sec
cache.Set(sessionItems, (item.Timeout * FROM_MIN_TO_SEC));
LogUtility.LogInfo("SetAndReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => created new item in session.", id, this.GetHashCode());
} // If update if lock matches
else
// Converting timout from min to sec
cache.Set(sessionItems, (item.Timeout * FROM_MIN_TO_SEC));
LogUtility.LogInfo("SetAndReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => created new item in session.", id, this.GetHashCode());
} // If update if lock matches
else
{
if (item != null && item.Items != null)
{
if (item != null && item.Items != null)
if (item.Items["SessionStateActions"] != null)
{
if (item.Items["SessionStateActions"] != null)
{
item.Items.Remove("SessionStateActions");
}
// Converting timout from min to sec
cache.TryUpdateAndReleaseLock(lockId, item.Items, (item.Timeout * FROM_MIN_TO_SEC));
LogUtility.LogInfo("SetAndReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => updated item in session, Lock ID: {2}.", id, this.GetHashCode(), lockId);
item.Items.Remove("SessionStateActions");
}
// Converting timout from min to sec
cache.TryUpdateAndReleaseLock(lockId, item.Items, (item.Timeout * FROM_MIN_TO_SEC));
LogUtility.LogInfo("SetAndReleaseItemExclusive => Session Id: {0}, Session provider object: {1} => updated item in session, Lock ID: {2}.", id, this.GetHashCode(), lockId);
}
}

}
catch (Exception e)
{
LogUtility.LogError("SetAndReleaseItemExclusive => {0}", e.ToString());
LastException = e;

//ExceptionHandler raises exception
if (ExceptionHandler != null)
ExceptionHandler.Invoke(e);

if (configuration.ThrowOnError)
{
throw;
Expand Down