时间:2021-07-01 10:21:17 帮助过:12人阅读
如果在数据存储区中找到会话项数据但该数据已锁定,则 GetItemExclusive 方法将 locked 输出参数设置为 true,将 lockAge输出参数设置为当前日期和时间与该项锁定日期和时间的差,将 lockId 输出参数设置为从数据存储区中检索的锁定标识符,并返回 null。这将导致 SessionStateModule 隔半秒后再次调用 GetItemExclusive 方法,以尝试检索会话项信息和获取对数据的锁定。如果 lockAge 输出参数的设置值超过 ExecutionTimeout 值,SessionStateModule 将调用 ReleaseItemExclusive 方法以清除对会话项数据的锁定,然后再次调用 GetItemExclusive 方法。
如果 regenerateExpiredSessionId 属性设置为 true,则 actionFlags 参数用于其 Cookieless 属性为 true 的会话。actionFlags 值设置为 InitializeItem (1) 则指示会话数据存储区中的项是需要初始化的新会话。通过调用CreateUninitializedItem 方法可以创建会话数据存储区中未初始化的项。如果会话数据存储区中的项已经初始化,则actionFlags 参数设置为零。
如果提供程序支持无 Cookie 会话,请将 actionFlags 输出参数设置为当前项从会话数据存储区中返回的值。如果被请求的会话存储项的 actionFlags 参数值等于 InitializeItem 枚举值 (1),则 GetItemExclusive 方法在设置 actionFlags out 参数之后应将数据存储区中的值设置为零。
GetItem 方法
除了不尝试锁定数据存储区中的会话项以外,此方法与 GetItemExclusive 方法执行的操作相同。GetItem 方法在EnableSessionState 属性设置为 ReadOnly 时调用。
SetAndReleaseItemExclusive 方法
采用当前请求的 HttpContext 实例、当前请求的 SessionID 值、包含要存储的当前会话值的 SessionStateStoreData 对象、当前请求的锁定标识符以及指示要存储的数据是属于新会话还是现有会话的值作为输入。
如果 newItem 参数为 true,则 SetAndReleaseItemExclusive 方法使用提供的值将一个新项插入到数据存储区中。否则,数据存储区中的现有项使用提供的值进行更新,并释放对数据的任何锁定。请注意,只有与提供的 SessionID 值和锁定标识符值匹配的当前应用程序的会话数据才会更新。
调用 SetAndReleaseItemExclusive 方法后,SessionStateModule 调用 ResetItemTimeout 方法来更新会话项数据的过期日期和时间。
ReleaseItemExclusive 方法
采用当前请求的 HttpContext 实例、当前请求的 SessionID 值以及当前请求的锁定标识符作为输入,并释放对会话数据存储区中的项的锁定。在调用 GetItem 或 GetItemExclusive 方法,并且数据存储区指定被请求项已锁定,但锁定时间已超过ExecutionTimeout 值时会调用此方法。此方法清除锁定,释放该被请求项以供其他请求使用。
RemoveItem方法
采用当前请求的 HttpContext 实例、当前请求的 SessionID 值以及当前请求的锁定标识符作为输入,并删除数据存储区中与提供的 SessionID 值、当前应用程序和提供的锁定标识符相匹配的数据存储项的会话信息。此方法在 Abandon 方法被调用时调用。
CreateUninitializedItem方法
采用当前请求的 HttpContext 实例、当前请求的 SessionID 值以及当前请求的锁定标识符作为输入,并向会话数据存储区添加一个 actionFlags 值为 InitializeItem 的未初始化项。
如果 regenerateExpiredSessionId 属性设置为 true,则 CreateUninitializedItem 方法用于无 Cookie 会话,这将导致遇到过期会话 ID 时,SessionStateModule 会生成一个新的 SessionID 值。
生成新的 SessionID 值的过程需要浏览器重定向到包含新生成的会话 ID 的 URL。在包含过期的会话 ID 的初始请求期间,会调用CreateUninitializedItem 方法。SessionStateModule 获取一个新的 SessionID 值来替换过期的会话 ID 之后,它会调用CreateUninitializedItem 方法以将一个未初始化项添加到会话状态数据存储区中。然后,浏览器重定向到包含新生成的SessionID 值的 URL。如果会话数据存储区中存在未初始化项,则可以确保包含新生成的 SessionID 值的重定向请求被视为新的会话,而不会被误认为是对过期会话的请求。
会话数据存储区中未初始化的项与新生成的 SessionID 值关联,并且仅包含默认值,其中包括到期日期和时间以及与 GetItem 和GetItemExclusive 方法的 actionFlags 参数相对应的值。会话状态存储区中的未初始化项应包含一个与 InitializeItem 枚举值 (1) 相等的 actionFlags 值。此值由 GetItem 和 GetItemExclusive 方法传递给 SessionStateModule,并针对SessionStateModule 指定当前会话是新会话。然后,SessionStateModule 将初始化该新会话,并引发 Session_OnStart 事件。
CreateNewStoreData 方法
采用当前请求的 HttpContext 实例和当前会话的 Timeout 值作为输入,并返回带有空 ISessionStateItemCollection 对象的新的 SessionStateStoreData 对象、一个 HttpStaticObjectsCollection 集合和指定的 Timeout 值。使用GetSessionStaticObjects 方法可以检索 ASP.NET 应用程序的 HttpStaticObjectsCollection 实例。
SetItemExpireCallback 方法
采用引用 Global.asax 文件中定义的 Session_OnEnd 事件的委托作为输入。如果会话状态存储提供程序支持 Session_OnEnd事件,则设置对 SessionStateItemExpireCallback 参数的局部引用,并且此方法返回 true;否则,此方法返回 false。
由于本机只有SQLServer作为数据存储,所有就用SqlServer作为代码演示,其原理都一样的,直接改成Redis或者其他的就可以。
表结构
1 CREATE TABLE [dbo].[ASPStateTempSessions]( 2 [SessionId] [nvarchar](88) NOT NULL,--唯一的SessionId 3 [Created] [datetime] NOT NULL,--Session的创建时间 4 [Expires] [datetime] NOT NULL,--过期的时间 5 [LockDate] [datetime] NOT NULL,--锁定的时间 6 [LockId] [int] NOT NULL,--锁定的Id 7 [Timeout] [int] NOT NULL,--过期时间(分钟) 8 [Locked] [bit] NOT NULL,--是否锁定 9 [SessionItem] [nvarchar](max) NULL,--Session数据 10 [Flags] [int] NOT NULL,--标记是否是初始化数据 11 CONSTRAINT [PK_ASPStateTempSessions] PRIMARY KEY CLUSTERED 12 ( 13 [SessionId] ASC 14 ) 15 )
1 /// <summary> 2 /// 自定义Session实现方式 3 /// </summary> 4 public class MyCustomSessionStateStoreProvider : SessionStateStoreProviderBase 5 { 6 /// <summary> 7 /// 获取配置文件的设置的默认超时时间 8 /// </summary> 9 private static TimeSpan _expiresTime; 10 11 /// <summary> 12 /// 获取Web.config 在sessionState设置的超时时间 13 /// </summary> 14 static MyCustomSessionStateStoreProvider() 15 { 16 System.Web.Configuration.SessionStateSection sessionStateSection = (System.Web.Configuration.SessionStateSection)System.Configuration.ConfigurationManager.GetSection("system.web/sessionState"); 17 _expiresTime = sessionStateSection.Timeout; 18 } 19 20 /// <summary> 21 /// 创建新的存储数据 22 /// </summary> 23 /// <param name="context"></param> 24 /// <param name="timeout"></param> 25 /// <returns></returns> 26 public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout) 27 { 28 return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), timeout); 29 } 30 31 /// <summary> 32 /// 创建未初始化的项,就是初始化Session数据 33 /// </summary> 34 /// <param name="context"></param> 35 /// <param name="id"></param> 36 /// <param name="timeout"></param> 37 public override void CreateUninitializedItem(HttpContext context, string id, int timeout) 38 { 39 using (SessionStateEF db = new SessionStateEF()) 40 { 41 var session = new ASPStateTempSessions 42 { 43 Created = DateTime.Now, 44 Expires = DateTime.Now.AddMinutes(timeout), 45 Flags = (int)SessionStateActions.InitializeItem, 46 LockDate = DateTime.Now, 47 Locked = false, 48 SessionId = id, 49 LockId = 0, 50 Timeout = timeout 51 }; 52 db.ASPStateTempSessions.Add(session); 53 db.SaveChanges(); 54 } 55 } 56 57 /// <summary> 58 /// 释放锁定的项,就是把锁定的Session的锁的状态清除掉 59 /// </summary> 60 /// <param name="context"></param> 61 /// <param name="id"></param> 62 /// <param name="lockId"></param> 63 public override void ReleaseItemExclusive(HttpContext context, string id, object lockId) 64 { 65 using (SessionStateEF db = new SessionStateEF()) 66 { 67 var session = db.ASPStateTempSessions.Find(id); 68 if (session == null) 69 { 70 return; 71 } 72 73 // 把locked设置为false 74 session.Locked = false; 75 session.Expires = DateTime.Now + _expiresTime; 76 db.SaveChanges(); 77 } 78 79 } 80 81 /// <summary> 82 /// 删除Session,会在Session.Abandon()的时候调用 83 /// </summary> 84 /// <param name="context"></param> 85 /// <param name="id"></param> 86 /// <param name="lockId"></param> 87 /// <param name="item"></param> 88 public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item) 89 { 90 using (SessionStateEF db = new SessionStateEF()) 91 { 92 var session = db.ASPStateTempSessions.Find(id); 93 if (session == null) 94 { 95 return; 96 } 97 98 db.ASPStateTempSessions.Remove(session); 99 db.SaveChanges(); 100 } 101 } 102 103 /// <summary> 104 /// 设置超时时间 105 /// </summary> 106 /// <param name="context"></param> 107 /// <param name="id"></param> 108 public override void ResetItemTimeout(HttpContext context, string id) 109 { 110 using (SessionStateEF db = new SessionStateEF()) 111 { 112 var session = db.ASPStateTempSessions.Find(id); 113 if (session == null) 114 { 115 return; 116 } 117 session.Expires = DateTime.Now + _expiresTime; 118 db.SaveChanges(); 119 } 120 } 121 122 /// <summary> 123 /// 新建或者释放锁定的项并设置Session的值 124 /// </summary> 125 /// <param name="context"></param> 126 /// <param name="id"></param> 127 /// <param name="item"></param> 128 /// <param name="lockId"></param> 129 /// <param name="newItem"></param> 130 public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) 131 { 132 using (SessionStateEF db = new SessionStateEF()) 133 { 134 // 判断是否是新建,如果是新建则和CreateUninitializedItem不同在于Timeout和有初始值。 135 if (newItem) 136 { 137 var session = new ASPStateTempSessions 138 { 139 Created = DateTime.Now, 140 Expires = DateTime.Now.AddMinutes(item.Timeout), 141 Flags = (int)SessionStateActions.None, 142 LockDate = DateTime.Now, 143 Locked = false, 144 SessionId = id, 145 LockId = 0, 146 Timeout = item.Timeout, 147 SessionItem = Serialize((SessionStateItemCollection)item.Items) 148 }; 149 db.ASPStateTempSessions.Add(session); 150 db.SaveChanges(); 151 } 152 else// 释放锁定的项并设置Session的值 153 { 154 var session = db.ASPStateTempSessions.FirstOrDefault(i => i.SessionId == id); 155 if (session == null) 156 { 157 return; 158 } 159 160 session.Expires = DateTime.Now.AddMinutes(item.Timeout); 161 session.Locked = false; 162 session.LockId = Convert.ToInt32(lockId); 163 session.SessionItem = Serialize((SessionStateItemCollection)item.Items); 164 db.SaveChanges(); 165 } 166 } 167 } 168 169 /// <summary> 170 /// 获取项,这个方式主要是把Session状态设置为只读状态时调用。 171 /// </summary> 172 /// <param name="context"></param> 173 /// <param name="id"></param> 174 /// <param name="locked"></param> 175 /// <param name="lockAge"></param> 176 /// <param name="lockId"></param> 177 /// <param name="actions"></param> 178 /// <returns></returns> 179 public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) 180 { 181 return DoGet(false, context, id, out locked, out lockAge, out lockId, out actions); 182 } 183 184 /// <summary> 185 /// 独占获取项,除了Session状态为只读时调用 186 /// </summary> 187 /// <param name="context"></param> 188 /// <param name="id"></param> 189 /// <param name="locked"></param> 190 /// <param name="lockAge"></param> 191 /// <param name="lockId"></param> 192 /// <param name="actions"></param> 193 /// <returns></returns> 194 public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) 195 { 196 return DoGet(true, context, id, out locked, out lockAge, out lockId, out actions); 197 } 198 199 /// <summary> 200 /// 获取Session的值 201 /// </summary> 202 /// <param name="isExclusive"></param> 203 /// <param name="context"></param> 204 /// <param name="id"></param> 205 /// <param name="locked"></param> 206 /// <param name="lockAge"></param> 207 /// <param name="lockId"></param> 208 /// <param name="actions"></param> 209 /// <returns></returns> 210 public SessionStateStoreData DoGet(bool isExclusive, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) 211 { 212 using (SessionStateEF db = new SessionStateEF()) 213 { 214 // 设置初始值 215 var item = default(SessionStateStoreData); 216 lockAge = TimeSpan.Zero; 217 lockId = null; 218 locked = false; 219 actions = 0; 220 221 // 如果数据存储区中未找到任何会话项数据,则GetItemExclusive 方法将 locked 输出参数设置为false,并返回 null。 222 // 这将导致 SessionStateModule调用 CreateNewStoreData 方法来为请求创建一个新的SessionStateStoreData 对象。 223 var session = db.ASPStateTempSessions.Find(id); 224 if (session == null) 225 { 226 return null; 227 } 228 229 // 判断session是否是ReadOnly 模式,不是readonly模式得判断是否锁住 230 if (isExclusive) 231 { 232 // 如果在数据存储区中找到会话项数据但该数据已锁定,则GetItemExclusive 方法将 locked 输出参数设置为true, 233 // 将 lockAge 输出参数设置为当前日期和时间与该项锁定日期和时间的差,将 lockId 输出参数设置为从数据存储区中检索的锁定标识符,并返回 nul 234 if (session.Locked) 235 { 236 locked = true; 237 lockAge = session.LockDate - DateTime.Now; 238 lockId = session.LockId; 239 return null; 240 } 241 } 242 243 // 判断是否过期 244 if (session.Expires < DateTime.Now) 245 { 246 db.ASPStateTempSessions.Remove(session); 247 return null; 248 } 249 250 // 处理值 251 lockId = lockId == null ? 0 : (int)lockId + 1; 252 session.Flags = (int)SessionStateActions.None; 253 session.LockId = Convert.ToInt32(lockId); 254 255 // 获取timeout 256 var timeout = actions == SessionStateActions.InitializeItem ? _expiresTime.TotalMinutes : session.Timeout; 257 258 // 获取SessionStateItemCollection 259 SessionStateItemCollection sessionStateItemCollection = null; 260 261 // 获取Session的值 262 if (actions == SessionStateActions.None && !string.IsNullOrEmpty(session.SessionItem)) 263 { 264 sessionStateItemCollection = Deserialize((session.SessionItem)); 265 } 266 267 item = new SessionStateStoreData(sessionStateItemCollection ?? new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), (int)timeout); 268 269 return item; 270 271 } 272 273 } 274 275 276 #region 序列化反序列化Session的值 277 /// <summary> 278 /// 反序列化Session的数据 279 /// </summary> 280 /// <param name="item"></param> 281 /// <returns></returns> 282 public SessionStateItemCollection Deserialize(string item) 283 { 284 MemoryStream stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(item)); 285 SessionStateItemCollection collection = new SessionStateItemCollection(); 286 if (stream.Length > 0) 287 { 288 BinaryReader reader = new BinaryReader(stream); 289 collection = SessionStateItemCollection.Deserialize(reader); 290 } 291 return collection; 292 } 293 294 /// <summary> 295 /// 序列化Session的数据 296 /// </summary> 297 /// <param name="items"></param> 298 /// <returns></returns> 299 public string Serialize(SessionStateItemCollection items) 300 { 301 MemoryStream ms = new MemoryStream(); 302 BinaryWriter writer = new BinaryWriter(ms); 303 if (items != null) 304 items.Serialize(writer); 305 writer.Close(); 306 return System.Text.Encoding.ASCII.GetString(ms.ToArray()); 307 } 308 309 #endregion 310 311 312 public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) 313 { 314 return true; 315 } 316 public override void InitializeRequest(HttpContext context) 317 { 318 } 319 public override void EndRequest(HttpContext context) 320 { 321 } 322 public override void Dispose() 323 { 324 } 325 326 }
1 <sessionState mode="Custom" customProvider="mySessionProvider"> 2 <providers> 3 <add name="mySessionProvider" type="CustomSessionState.MyCustomSessionStateStoreProvider,CustomSessionState"/> 4 </providers> 5 </sessionState>
Githug地址
https://github.com/Emrys5/Asp.net-CustomSessionState
最后的最后,求推荐
Asp.net 实现Session分布式储存(Redis,Mongodb,Mysql等) sessionState Custom
标签:完全 state 标识 net varchar encoding 关联 arc 验证