[ACCEPTED]-Generating a new ASP.NET session in the current HTTPContext-httpsession
I would like to share my magic. Actually, no, its 28 not yet magical.. We ought to test and evolve 27 the code more. I only tested these code 26 in with-cookie, InProc session mode. Put 25 these method inside your page, and call 24 it where you need the ID to be regenerated 23 (please set your web app to Full Trust):
void regenerateId()
{
System.Web.SessionState.SessionIDManager manager = new System.Web.SessionState.SessionIDManager();
string oldId = manager.GetSessionID(Context);
string newId = manager.CreateSessionID(Context);
bool isAdd = false, isRedir = false;
manager.SaveSessionID(Context, newId, out isRedir, out isAdd);
HttpApplication ctx = (HttpApplication)HttpContext.Current.ApplicationInstance;
HttpModuleCollection mods = ctx.Modules;
System.Web.SessionState.SessionStateModule ssm = (SessionStateModule)mods.Get("Session");
System.Reflection.FieldInfo[] fields = ssm.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
SessionStateStoreProviderBase store = null;
System.Reflection.FieldInfo rqIdField = null, rqLockIdField = null, rqStateNotFoundField = null;
foreach (System.Reflection.FieldInfo field in fields)
{
if (field.Name.Equals("_store")) store = (SessionStateStoreProviderBase)field.GetValue(ssm);
if (field.Name.Equals("_rqId")) rqIdField = field;
if (field.Name.Equals("_rqLockId")) rqLockIdField = field;
if (field.Name.Equals("_rqSessionStateNotFound")) rqStateNotFoundField = field;
}
object lockId = rqLockIdField.GetValue(ssm);
if ((lockId != null) && (oldId !=null)) store.ReleaseItemExclusive(Context, oldId, lockId);
rqStateNotFoundField.SetValue(ssm, true);
rqIdField.SetValue(ssm, newId);
}
I 22 have been digging around .NET Source code 21 (that were available in http://referencesource.microsoft.com/netframework.aspx), and discovered 20 that there is no way I could regenerate 19 SessionID without hacking the internals 18 of session management mechanism. So I do 17 just that - hack SessionStateModule internal 16 fields, so it will save the current Session 15 into a new ID. Maybe the current HttpSessionState 14 object still has the previous Id, but AFAIK 13 the SessionStateModule ignored it. It just 12 use the internal _rqId field when it has 11 to save the state somewhere. I have tried 10 other means, like copying SessionStateModule 9 into a new class with a regenerate ID functionality, (I 8 was planning to replace SessionStateModule 7 with this class), but failed because it 6 currently has references to other internal 5 classes (like InProcSessionStateStore). The 4 downside of hacking using reflection is 3 we need to set our application to 'Full 2 Trust'.
Oh, and if you really need the VB 1 version, try these :
Sub RegenerateID()
Dim manager
Dim oldId As String
Dim newId As String
Dim isRedir As Boolean
Dim isAdd As Boolean
Dim ctx As HttpApplication
Dim mods As HttpModuleCollection
Dim ssm As System.Web.SessionState.SessionStateModule
Dim fields() As System.Reflection.FieldInfo
Dim rqIdField As System.Reflection.FieldInfo
Dim rqLockIdField As System.Reflection.FieldInfo
Dim rqStateNotFoundField As System.Reflection.FieldInfo
Dim store As SessionStateStoreProviderBase
Dim field As System.Reflection.FieldInfo
Dim lockId
manager = New System.Web.SessionState.SessionIDManager
oldId = manager.GetSessionID(Context)
newId = manager.CreateSessionID(Context)
manager.SaveSessionID(Context, newId, isRedir, isAdd)
ctx = HttpContext.Current.ApplicationInstance
mods = ctx.Modules
ssm = CType(mods.Get("Session"), System.Web.SessionState.SessionStateModule)
fields = ssm.GetType.GetFields(System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)
store = Nothing : rqLockIdField = Nothing : rqIdField = Nothing : rqStateNotFoundField = Nothing
For Each field In fields
If (field.Name.Equals("_store")) Then store = CType(field.GetValue(ssm), SessionStateStoreProviderBase)
If (field.Name.Equals("_rqId")) Then rqIdField = field
If (field.Name.Equals("_rqLockId")) Then rqLockIdField = field
If (field.Name.Equals("_rqSessionStateNotFound")) Then rqStateNotFoundField = field
Next
lockId = rqLockIdField.GetValue(ssm)
If ((Not IsNothing(lockId)) And (Not IsNothing(oldId))) Then store.ReleaseItemExclusive(Context, oldId, lockId)
rqStateNotFoundField.SetValue(ssm, True)
rqIdField.SetValue(ssm, newId)
End Sub
If you're security concious and would like 2 the C# version of this answer removing the 1 old field, please use the following.
private static void RegenerateSessionId()
{
// Initialise variables for regenerating the session id
HttpContext Context = HttpContext.Current;
SessionIDManager manager = new SessionIDManager();
string oldId = manager.GetSessionID(Context);
string newId = manager.CreateSessionID(Context);
bool isAdd = false, isRedir = false;
// Save a new session ID
manager.SaveSessionID(Context, newId, out isRedir, out isAdd);
// Get the fields using the below and create variables for storage
HttpApplication ctx = HttpContext.Current.ApplicationInstance;
HttpModuleCollection mods = ctx.Modules;
SessionStateModule ssm = (SessionStateModule)mods.Get("Session");
FieldInfo[] fields = ssm.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
SessionStateStoreProviderBase store = null;
FieldInfo rqIdField = null, rqLockIdField = null, rqStateNotFoundField = null;
SessionStateStoreData rqItem = null;
// Assign to each variable the appropriate field values
foreach (FieldInfo field in fields)
{
if (field.Name.Equals("_store")) store = (SessionStateStoreProviderBase)field.GetValue(ssm);
if (field.Name.Equals("_rqId")) rqIdField = field;
if (field.Name.Equals("_rqLockId")) rqLockIdField = field;
if (field.Name.Equals("_rqSessionStateNotFound")) rqStateNotFoundField = field;
if (field.Name.Equals("_rqItem")) rqItem = (SessionStateStoreData)field.GetValue(ssm);
}
// Remove the previous session value
object lockId = rqLockIdField.GetValue(ssm);
if ((lockId != null) && (oldId != null))
store.RemoveItem(Context, oldId, lockId, rqItem);
rqStateNotFoundField.SetValue(ssm, true);
rqIdField.SetValue(ssm, newId);
}
As Can Gencer mentioned - ReleaseItemExclusive 8 doesn't remove old session from the store 7 and that leads to that session eventually 6 expiring and calling Session_End in Global.asax. This 5 caused us a huge problem in production, because 4 we are clearing Thread identity in Session_End, and 3 because of this - users were spontaneously 2 losing authentication on thread.
So below 1 is the corrected code that works.
Dim oHTTPContext As HttpContext = HttpContext.Current
Dim oSessionIdManager As New SessionIDManager
Dim sOldId As String = oSessionIdManager.GetSessionID(oHTTPContext)
Dim sNewId As String = oSessionIdManager.CreateSessionID(oHTTPContext)
Dim bIsRedir As Boolean = False
Dim bIsAdd As Boolean = False
oSessionIdManager.SaveSessionID(oHTTPContext, sNewId, bIsRedir, bIsAdd)
Dim oAppContext As HttpApplication = HttpContext.Current.ApplicationInstance
Dim oModules As HttpModuleCollection = oAppContext.Modules
Dim oSessionStateModule As SessionStateModule = _
DirectCast(oModules.Get("Session"), SessionStateModule)
Dim oFields() As FieldInfo = _
oSessionStateModule.GetType.GetFields(BindingFlags.NonPublic Or _
BindingFlags.Instance)
Dim oStore As SessionStateStoreProviderBase = Nothing
Dim oRqIdField As FieldInfo = Nothing
Dim oRqItem As SessionStateStoreData = Nothing
Dim oRqLockIdField As FieldInfo = Nothing
Dim oRqStateNotFoundField As FieldInfo = Nothing
For Each oField As FieldInfo In oFields
If (oField.Name.Equals("_store")) Then
oStore = DirectCast(oField.GetValue(oSessionStateModule), _
SessionStateStoreProviderBase)
End If
If (oField.Name.Equals("_rqId")) Then
oRqIdField = oField
End If
If (oField.Name.Equals("_rqLockId")) Then
oRqLockIdField = oField
End If
If (oField.Name.Equals("_rqSessionStateNotFound")) Then
oRqStateNotFoundField = oField
End If
If (oField.Name.Equals("_rqItem")) Then
oRqItem = DirectCast(oField.GetValue(oSessionStateModule), _
SessionStateStoreData)
End If
Next
If oStore IsNot Nothing Then
Dim oLockId As Object = Nothing
If oRqLockIdField IsNot Nothing Then
oLockId = oRqLockIdField.GetValue(oSessionStateModule)
End If
If (oLockId IsNot Nothing) And (Not String.IsNullOrEmpty(sOldId)) Then
oStore.ReleaseItemExclusive(oHTTPContext, sOldId, oLockId)
oStore.RemoveItem(oHTTPContext, sOldId, oLockId, oRqItem)
End If
oRqStateNotFoundField.SetValue(oSessionStateModule, True)
oRqIdField.SetValue(oSessionStateModule, sNewId)
End If
Have you considered using the HttpSessionState.Abandon method? That ought 5 to clear everything. Then start a new session 4 and populate it with all the items you stored 3 from your code above.
Session.Abandon();
should suffice. Otherwise 2 you could try to go the extra mile with 1 a few more calls if it's still being stubborn:
Session.Contents.Abandon();
Session.Contents.RemoveAll();
Can you not just set:
<sessionState regenerateExpiredSessionId="False" />
in web.config, and 1 then use the solution suggested by Ahmad?
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.