2 // System.Web.SessionState.SessionInProcHandler
5 // Marek Habersack <grendello@gmail.com
7 // (C) 2006 Marek Habersack
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Configuration.Provider;
36 using System.Web.Caching;
37 using System.Web.Configuration;
38 using System.Threading;
40 namespace System.Web.SessionState
42 internal sealed class InProcSessionItem
45 public bool cookieless;
46 public ISessionStateItemCollection items;
47 public DateTime lockedTime;
48 public DateTime expiresAt;
49 public ReaderWriterLock rwlock;
53 internal InProcSessionItem ()
56 this.cookieless = false;
58 this.lockedTime = DateTime.MinValue;
59 this.expiresAt = DateTime.MinValue;
60 this.rwlock = new ReaderWriterLock ();
61 this.lockId = Int32.MinValue;
66 internal class SessionInProcHandler : SessionStateStoreProviderBase
68 private const string CachePrefix = "@@@InProc@";
69 private const Int32 lockAcquireTimeout = 30000;
71 CacheItemRemovedCallback removedCB;
72 //NameValueCollection privateConfig;
73 SessionStateItemExpireCallback expireCallback;
75 public override SessionStateStoreData CreateNewStoreData (HttpContext context, int timeout)
77 return new SessionStateStoreData (new SessionStateItemCollection (),
78 SessionStateUtility.GetSessionStaticObjects(context),
82 void InsertSessionItem (InProcSessionItem item, int timeout, string id)
84 HttpRuntime.Cache.InsertPrivate (id,
87 Cache.NoAbsoluteExpiration,
88 TimeSpan.FromMinutes (timeout),
89 CacheItemPriority.AboveNormal,
93 public override void CreateUninitializedItem (HttpContext context, string id, int timeout)
95 EnsureGoodId (id, true);
96 InProcSessionItem item = new InProcSessionItem ();
97 item.expiresAt = DateTime.UtcNow.AddMinutes (timeout);
98 item.timeout = timeout;
99 InsertSessionItem (item, timeout, CachePrefix + id);
102 public override void Dispose ()
106 public override void EndRequest (HttpContext context)
110 SessionStateStoreData GetItemInternal (HttpContext context,
113 out TimeSpan lockAge,
115 out SessionStateActions actions,
119 lockAge = TimeSpan.MinValue;
120 lockId = Int32.MinValue;
121 actions = SessionStateActions.None;
126 Cache cache = HttpRuntime.Cache;
127 string CacheId = CachePrefix + id;
128 InProcSessionItem item = cache [CacheId] as InProcSessionItem;
134 item.rwlock.AcquireReaderLock (lockAcquireTimeout);
137 lockAge = DateTime.UtcNow.Subtract (item.lockedTime);
138 lockId = item.lockId;
141 item.rwlock.ReleaseReaderLock ();
143 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
145 item.lockedTime = DateTime.UtcNow;
147 lockId = item.lockId;
149 if (item.items == null) {
150 actions = SessionStateActions.InitializeItem;
151 item.items = new SessionStateItemCollection ();
153 return new SessionStateStoreData (item.items,
154 SessionStateUtility.GetSessionStaticObjects(context),
157 // we want such errors to be passed to the application.
160 if (item.rwlock.IsReaderLockHeld)
161 item.rwlock.ReleaseReaderLock ();
162 if (item.rwlock.IsWriterLockHeld)
163 item.rwlock.ReleaseWriterLock ();
167 public override SessionStateStoreData GetItem (HttpContext context,
170 out TimeSpan lockAge,
172 out SessionStateActions actions)
174 EnsureGoodId (id, false);
175 return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, false);
178 public override SessionStateStoreData GetItemExclusive (HttpContext context,
181 out TimeSpan lockAge,
183 out SessionStateActions actions)
185 EnsureGoodId (id, false);
186 return GetItemInternal (context, id, out locked, out lockAge, out lockId, out actions, true);
189 public override void Initialize (string name, NameValueCollection config)
191 if (String.IsNullOrEmpty (name))
192 name = "Session InProc handler";
193 removedCB = new CacheItemRemovedCallback (OnSessionRemoved);
194 //privateConfig = config;
195 base.Initialize (name, config);
198 public override void InitializeRequest (HttpContext context)
200 // nothing to do here
203 public override void ReleaseItemExclusive (HttpContext context,
207 EnsureGoodId (id, true);
208 string CacheId = CachePrefix + id;
209 InProcSessionItem item = HttpRuntime.Cache [CacheId] as InProcSessionItem;
211 if (item == null || lockId == null || lockId.GetType() != typeof(Int32) || item.lockId != (Int32)lockId)
215 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
220 if (item.rwlock.IsWriterLockHeld)
221 item.rwlock.ReleaseWriterLock ();
225 public override void RemoveItem (HttpContext context,
228 SessionStateStoreData item)
230 EnsureGoodId (id, true);
231 string CacheId = CachePrefix + id;
232 Cache cache = HttpRuntime.Cache;
233 InProcSessionItem inProcItem = cache [CacheId] as InProcSessionItem;
235 if (inProcItem == null || lockId == null || lockId.GetType() != typeof(Int32) || inProcItem.lockId != (Int32)lockId)
239 inProcItem.rwlock.AcquireWriterLock (lockAcquireTimeout);
240 cache.Remove (CacheId);
244 if (inProcItem.rwlock.IsWriterLockHeld)
245 inProcItem.rwlock.ReleaseWriterLock ();
249 public override void ResetItemTimeout (HttpContext context, string id)
251 EnsureGoodId (id, true);
252 string CacheId = CachePrefix + id;
253 Cache cache = HttpRuntime.Cache;
254 InProcSessionItem item = cache [CacheId] as InProcSessionItem;
260 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
261 cache.Remove (CacheId);
262 InsertSessionItem (item, item.timeout, CacheId);
266 if (item.rwlock.IsWriterLockHeld)
267 item.rwlock.ReleaseWriterLock ();
271 public override void SetAndReleaseItemExclusive (HttpContext context,
273 SessionStateStoreData item,
277 EnsureGoodId (id, true);
278 string CacheId = CachePrefix + id;
279 Cache cache = HttpRuntime.Cache;
280 InProcSessionItem inProcItem = cache [CacheId] as InProcSessionItem;
282 if (newItem || inProcItem == null) {
283 inProcItem = new InProcSessionItem ();
284 inProcItem.timeout = item.Timeout;
285 inProcItem.expiresAt = DateTime.UtcNow.AddMinutes (item.Timeout);
286 if (lockId.GetType() == typeof(Int32))
287 inProcItem.lockId = (Int32)lockId;
289 if (lockId == null || lockId.GetType() != typeof(Int32) || inProcItem.lockId != (Int32)lockId)
291 cache.Remove (CacheId);
295 inProcItem.rwlock.AcquireWriterLock (lockAcquireTimeout);
296 inProcItem.locked = false;
297 inProcItem.items = item.Items;
298 InsertSessionItem (inProcItem, item.Timeout, CacheId);
302 if (inProcItem.rwlock.IsWriterLockHeld)
303 inProcItem.rwlock.ReleaseWriterLock ();
307 public override bool SetItemExpireCallback (SessionStateItemExpireCallback expireCallback)
309 this.expireCallback = expireCallback;
313 void EnsureGoodId (string id, bool throwOnNull)
317 throw new HttpException ("Session ID is invalid");
321 if (id.Length > SessionIDManager.SessionIDMaxLength)
322 throw new HttpException ("Session ID too long");
325 void OnSessionRemoved (string key, object value, CacheItemRemovedReason reason)
327 if (expireCallback != null)
328 expireCallback (key, value as SessionStateStoreData);