自定義會話狀態存儲提供程序web
此版本程序只是說明 自定義會話 能夠放在不一樣的地方, 能夠改形成 把會話分佈式存儲 等。服務器
1、Web.config session
<sessionState mode="Custom" customProvider="JinshuaiCustomSessionStateProvider">
<providers>
<add name="JinshuaiCustomSessionStateProvider" type="SessionStateWebApplication.Sessions.JinshuaiCustomSessionStateProvider" connectionStringName="DefaultConnection" />
</providers>
</sessionState>多線程
2、 JinshuaiCustomSessionStateProvider 提供程序併發
1 using System; 2 using System.Collections.Generic; 3 using System.Collections.Specialized; 4 using System.IO; 5 using System.Linq; 6 using System.Web; 7 using System.Web.SessionState; 8 9 namespace SessionStateWebApplication.Sessions 10 { 11 public class JinshuaiCustomSessionStateProvider : SessionStateStoreProviderBase 12 { 13 private static Dictionary<string, CustomSession> _dic = new Dictionary<string, CustomSession>(); 14 15 public string AppName 16 { 17 get { return "jinshuaiTest"; } 18 } 19 20 public int TimeOut { get; set; } 21 22 23 public override void Initialize(string name, NameValueCollection config) 24 { 25 TimeOut = 20; 26 27 base.Initialize(name, config); 28 } 29 30 31 public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout) 32 { 33 TimeOut = timeout; 34 return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), timeout); 35 } 36 37 public override void CreateUninitializedItem(HttpContext context, string id, int timeout) 38 { 39 var newSession = new CustomSession 40 { 41 SessionId = id, 42 LockDate = DateTime.Now, 43 Locked = false, 44 LockId = 0, 45 SessionItems = string.Empty, 46 Timeout = timeout, 47 Expires = DateTime.Now.AddMinutes(timeout), 48 Created = DateTime.Now, 49 ApplicationName = AppName 50 }; 51 _dic.Add(id, newSession); 52 53 } 54 55 public override void Dispose() 56 { 57 58 } 59 60 public override void EndRequest(HttpContext context) 61 { 62 63 } 64 65 public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) 66 { 67 68 return GetItemByExclusive(false, context, id, out locked, out lockAge, out lockId, out actions); 69 } 70 71 public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) 72 { 73 return GetItemByExclusive(true, context, id, out locked, out lockAge, out lockId, out actions); 74 } 75 76 77 78 public SessionStateStoreData GetItemByExclusive(bool isExclusive, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) 79 { 80 locked = false; 81 lockAge = TimeSpan.Zero; 82 lockId = null; 83 actions = SessionStateActions.None; 84 85 CustomSession tempSession = null; 86 87 88 if (_dic.ContainsKey(id)) 89 { 90 tempSession = _dic[id]; 91 } 92 else 93 { 94 //沒找到相應的會話 95 return null; 96 } 97 98 //若是過時 99 if (tempSession.Expires <= DateTime.Now) 100 { 101 _dic.Remove(id); 102 return null; 103 } 104 105 106 //是否獨佔訪問 107 if (isExclusive) 108 { 109 if (tempSession.Locked) 110 { 111 locked = true; 112 lockAge = (DateTime.Now - tempSession.LockDate); 113 lockId = tempSession.LockId; 114 actions = (SessionStateActions)tempSession.Flags; 115 return null; 116 } 117 } 118 119 return Deserialize(context, tempSession.SessionItems, tempSession.Timeout); 120 121 } 122 123 124 125 126 127 public override void InitializeRequest(HttpContext context) 128 { 129 130 } 131 132 public override void ReleaseItemExclusive(HttpContext context, string id, object lockId) 133 { 134 if (!_dic.ContainsKey(id)) return; 135 136 var tempSession = _dic[id]; 137 tempSession.LockId = (int)(lockId??0); 138 tempSession.Locked = false; 139 tempSession.Expires = DateTime.Now.AddMinutes(tempSession.Timeout); 140 } 141 142 public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item) 143 { 144 145 if (!_dic.ContainsKey(id)) return; 146 147 _dic.Remove(id); 148 149 } 150 151 public override void ResetItemTimeout(HttpContext context, string id) 152 { 153 154 if (!_dic.ContainsKey(id)) return; 155 156 var tempSession = _dic[id]; 157 tempSession.Expires = DateTime.Now.AddMinutes(tempSession.Timeout); 158 159 } 160 161 public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) 162 { 163 164 string sessItems = Serialize((SessionStateItemCollection)item.Items); 165 166 if (newItem) 167 { 168 var newSession = new CustomSession 169 { 170 SessionId = id, 171 LockDate = DateTime.Now, 172 Locked = false, 173 LockId = 0, 174 SessionItems = sessItems, 175 Timeout = TimeOut, 176 Expires = DateTime.Now.AddMinutes(TimeOut), 177 Created = DateTime.Now, 178 ApplicationName = AppName 179 }; 180 _dic.Add(id, newSession); 181 182 } 183 else 184 { 185 186 if (!_dic.ContainsKey(id)) 187 { 188 var newSession = new CustomSession 189 { 190 SessionId = id, 191 LockDate = DateTime.Now, 192 Locked = false, 193 LockId = 0, 194 SessionItems = sessItems, 195 Timeout = TimeOut, 196 Expires = DateTime.Now.AddMinutes(TimeOut), 197 Created = DateTime.Now, 198 ApplicationName = AppName 199 }; 200 _dic.Add(id, newSession); 201 202 } 203 204 var tempSession = _dic[id]; 205 tempSession.Expires = DateTime.Now.AddMinutes(TimeOut); 206 tempSession.SessionItems = sessItems; 207 tempSession.LockId =(int)(lockId??0); 208 tempSession.LockDate = DateTime.Now; 209 210 } 211 212 213 } 214 215 public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback) 216 { 217 218 return false; 219 } 220 221 222 223 224 225 226 227 private string Serialize(SessionStateItemCollection items) 228 { 229 MemoryStream ms = new MemoryStream(); 230 BinaryWriter writer = new BinaryWriter(ms); 231 232 if (items != null) 233 items.Serialize(writer); 234 235 writer.Close(); 236 237 return Convert.ToBase64String(ms.ToArray()); 238 } 239 240 private SessionStateStoreData Deserialize(HttpContext context, 241 string serializedItems, int timeout) 242 { 243 MemoryStream ms = 244 new MemoryStream(Convert.FromBase64String(serializedItems)); 245 246 SessionStateItemCollection sessionItems = 247 new SessionStateItemCollection(); 248 249 if (ms.Length > 0) 250 { 251 BinaryReader reader = new BinaryReader(ms); 252 sessionItems = SessionStateItemCollection.Deserialize(reader); 253 } 254 255 return new SessionStateStoreData(sessionItems, 256 SessionStateUtility.GetSessionStaticObjects(context), 257 timeout); 258 } 259 260 261 } 262 263 264 [Serializable] 265 public class CustomSession 266 { 267 268 public string SessionId 269 { 270 get; 271 set; 272 } 273 274 public string ApplicationName 275 { 276 get; 277 set; 278 } 279 public DateTime Created 280 { 281 get; 282 set; 283 } 284 public DateTime Expires 285 { 286 get; 287 set; 288 } 289 public DateTime LockDate 290 { 291 get; 292 set; 293 } 294 public int LockId 295 { 296 get; 297 set; 298 } 299 public int Timeout 300 { 301 get; 302 set; 303 } 304 public bool Locked 305 { 306 get; 307 set; 308 } 309 public string SessionItems 310 { 311 get; 312 set; 313 } 314 public int Flags 315 { 316 get; 317 set; 318 } 319 320 321 } 322 }
三 、 使用 框架
protected void Button1_Click(object sender, EventArgs e)
{分佈式
Session["jinshuai"] = "你好:" + DateTime.Now.ToString();ide
}this
protected void Button2_Click(object sender, EventArgs e)
{
this.Label1.Text = (Session["jinshuai"]?? "沒找到值").ToString();
}spa
附:
https://msdn.microsoft.com/zh-cn/library/system.web.sessionstate.sessionstatestoreproviderbase(VS.80).aspx
ASP.NET 會話狀態使用會話狀態存儲提供程序將會話數據寫入數據存儲區,並從中讀取會話數據。會話狀態存儲提供程序是一個類,它繼承SessionStateStoreProviderBase 抽象類並使用特定於數據存儲區的實現重寫其成員。在處理 ASP.NET 頁的過程當中,SessionStateModule 類會調用會話狀態存儲提供程序以便與數據存儲區進行通訊,從而存儲和檢索會話變量和相關的會話信息,如超時值。
對於每一個 SessionID 屬性,每一個 ASP.NET 應用程序內的會話數據都將單獨存儲。ASP.NET 應用程序不共享會話數據。
如本主題中的示例所示,能夠爲 ASP.NET 應用程序指定一個自定義 SessionStateStoreProviderBase 實現,方法是將 sessionState 配置元素的mode 屬性設置爲 Custom,並將 customProvider 屬性設置爲自定義提供程序的名稱。
因爲 ASP.NET 應用程序是多線程的,支持對併發請求的響應,所以併發請求可能會嘗試訪問同一會話信息。考慮下面一種狀況,其中一個框架集中的多個框架都訪問同一應用程序。框架集內每一個框架的單獨請求可能會在 Web 服務器中的不一樣線程上併發執行。若是每一個框架源代碼的 ASP.NET 頁都訪問會話狀態變量,則可能會出現多個線程併發訪問會話存儲區。
爲避免在會話存儲區發生數據衝突以及意外的會話狀態行爲,SessionStateModule 和 SessionStateStoreProviderBase 類包含了鎖定功能,能夠在 ASP.NET 頁執行期間,以獨佔方式爲特定的會話鎖定會話存儲項。請注意,即便 EnableSessionState 屬性標記爲 ReadOnly,同一應用程序中的其餘 ASP.NET 頁也能夠向會話存儲區寫入,所以對於存儲區中只讀會話數據的請求可能最終仍將等待鎖定數據的釋放。
在調用 GetItemExclusive 方法的過程當中,在請求開始時就會對會話存儲區數據設置鎖定。請求完成後,在調用 SetAndReleaseItemExclusive 方法期間釋放鎖定。
若是 SessionStateModule 對象在調用 GetItemExclusive 或 GetItem 方法期間遇到鎖定的會話數據,它將以半秒爲間隔從新請求會話數據,直到鎖定被釋放或者會話數據的鎖定時間超過 ExecutionTimeout 屬性的值。若是超過了執行超時時間,SessionStateModule 對象將調用ReleaseItemExclusive 方法以釋放會話存儲區數據並隨即請求會話存儲區數據。
在針對當前的響應調用 SetAndReleaseItemExclusive 方法前,因爲鎖定的會話存儲區數據可能已經經過調用單獨線程上的ReleaseItemExclusive 方法而釋放,所以可能會嘗試設置和釋放已被另外一會話釋放並修改的會話狀態存儲區數據。爲了不這種狀況,GetItem 和GetItemExclusive 方法返回一個鎖定標識符。此鎖定標識符必須包含在每一個請求中以修改鎖定的會話存儲區數據。僅當數據存儲區中的鎖定標識符與 SessionStateModule 提供的鎖定標識符匹配時,才能修改會話存儲區數據。
當針對特定的會話調用 Abandon 方法時,將使用 RemoveItem 方法從數據存儲區中刪除該會話的數據;不然,數據將保留在會話數據存儲區供會話的之後請求使用。由 SessionStateStoreProviderBase 實現來刪除過時的會話數據。