不是说当然这应该是为什么只是为当前的HTTPContext生成一个全新的会话呢?奇怪的!无论如何 – 我写了一个厚脸皮的小实用类,“只是做到这一点:”
(道歉代码格式/突出显示/ Visual Basic我必须做错事)
Imports System.Web Imports System.Web.SessionState Public Class SwitchSession Public Shared Sub SetNewSession(ByVal context As HttpContext) ' This value will hold the ID managers action to creating a response cookie Dim cookieAdded As Boolean ' We use the current session state as a template Dim state As HttpSessionState = context.Session ' We use the default ID manager to generate a new session id Dim idManager As New SessionIDManager() ' We also start with a new,fresh blank state item collection Dim items As New SessionStateItemCollection() ' Static objects are extracted from the current session context Dim staticObjects As HttpStaticObjectsCollection = _ SessionStateUtility.GetSessionStaticObjects(context) ' We construct the replacement session for the current,some parameters are new,others are taken from prevIoUs session Dim replacement As New HttpSessionStateContainer( _ idManager.CreateSessionID(context),_ items,_ staticObjects,_ state.Timeout,_ True,_ state.CookieMode,_ state.Mode,_ state.IsReadOnly) ' Finally we strip the current session state from the current context SessionStateUtility.RemoveHttpSessionStateFromContext(context) ' Then we replace the assign the active session state using the replacement we just constructed SessionStateUtility.AddHttpSessionStateToContext(context,replacement) ' Make sure we clean out the responses of any other inteferring cookies idManager.RemoveSessionID(context) ' Save our new cookie session identifier to the response idManager.SaveSessionID(context,replacement.SessionID,False,cookieAdded) End Sub End Class
它对于请求的其余部分工作正常,并且将其自身正确地标识为新的会话(例如,HTTPContext.Current.Session.SessionID返回新生成的会话标识符)。
惊奇的是,当下一个请求命中服务器时,HTTPContext.Session(一个HTTPSessionState对象)使用正确的SessionID标识自身,但是将IsNewSession设置为True,并且为空,从而丢失先前请求中设置的所有会话值。
因此,先前的HTTPSessionState对象从初始请求中删除,这里的一个事件处理程序,这里的一个回调,一些处理在请求之间持久化会话数据的东西,还是仅仅是我缺少的东西?
有人有任何魔法分享吗?
解决方法
我只用in-cookie,InProc会话模式测试了这些代码。将这些方法放在您的页面中,并将其称为需要重新生成ID的位置(请将您的网络应用设置为完全信任):
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); }
我一直在挖掘.NET源代码(在http://referencesource.microsoft.com/netframework.aspx中可用),并发现没有办法可以重新生成SessionID,而不会窃取会话管理机制的内部。所以我只是这样 – 将SessionStateModule内部的字段,因此它将保存当前会话到一个新的ID。也许当前的HttpSessionState对象仍然具有以前的Id,但是AFAIK的SessionStateModule忽略它。当它必须在某个地方保存状态时,它只需使用内部_rqId字段。我已经尝试过其他方法,像将SessionStateModule复制到具有重新生成ID功能的新类(我计划用此类替换SessionStateModule),但失败,因为它目前已经引用了其他内部类(如InProcSessionStateStore)。使用反思的黑客的缺点是我们需要将我们的应用设置为“完全信任”。
哦,如果你真的需要VB版本,请尝试这些:
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,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,lockId) rqStateNotFoundField.SetValue(ssm,True) rqIdField.SetValue(ssm,newId) End Sub