我們在寫網站一定會使用到 Session
今天就跟大家分享自製微型 Asp.net Session
分析Session->實作Session->使用Session
在實作之前您必須先了解甚麼是Session 網路上一大堆介紹Session文章在此我就不多介紹 或可以點進之前小弟的介紹文來簡單了解 SessionID.cookie,Session傻傻分不清楚??
簡單說明: Http協議是一個無狀態協議。
核心是 請求=>處理=>回應
每次請求都是獨立不會記住上一次做了甚麼 Session可以幫我們把資料存在Server記憶體,方便我們下次請求使用 上網連線眾多使用者,Server怎麼知道哪份資料,屬於哪個使用者的? 這就要依靠 SessonID SessionID 就像使用者的號碼牌,可以到Server拿相對應的資料
分析:
使用者請求頁面時會攜帶該網域下Cookies。
Asp.net接收到並使用Key為SessionID的Cookie,使用Cookie的Value來SessionPool中查找屬於使用者的Session。 如果是第一次請求或是沒有SessionID 會幫他產生一個新的並加入回應的Cookie中
取得Session物件後就可以在程式中使用。
分析如下圖:
我們作出幾個核心來完成模擬Session:
SessionPool來存放目前所有Session
SessionObject (支援快取在系統記憶體中) 模擬HttpContext封裝Session
實作: 我要簡單呈現就選擇使用輕便 [泛型處理常式]
ApplicationContext 模擬HttpContext封裝SessionPool 創建一個靜態的SessionPool物件,因為程式都共用此SessionPool
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class ApplicationContext { private readonly string MySessionID = "MySessionID" ; public HttpRequest Request { get ; private set ; } public HttpResponse Respone { get ; private set ; } public ApplicationContext (HttpContext context ) { Respone = context.Response; Request = context.Request; } private static SessionPool _container = new SessionPool(); public SessionObject Session { get { return GetSessionObj(); } } private SessionObject GetSessionObj () { Guid sessionGuid; HttpCookie CookieSessionID = Request.Cookies[MySessionID]; if (CookieSessionID == null ) { sessionGuid = Guid.NewGuid(); HttpCookie cookie = new HttpCookie(MySessionID, sessionGuid.ToString()) { Expires = DateTime.Now.AddDays(60 ) }; Respone.Cookies.Add(cookie); } else { sessionGuid = Guid.Parse(CookieSessionID.Value); } return _container[sessionGuid]; } }
CacheDictionary 負責快取
使用一個 Dictionary 來對Session存取物件設置快取
1 2 3 4 5 private readonly Dictionary<string , CancellationTokenSource> _expireContaner = new Dictionary<string , CancellationTokenSource>();
在Task.Delay可以讓物件存放在工作執行緒中 等Delay時間到就呼叫 ContinueWith 將物件消毀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public T Set <T >(string key, Func<T> create, TimeSpan expireIn ){ if (_expireTasks.ContainsKey(key)) { _expireTasks[key].Cancel(); _expireTasks.Remove(key); } var expirationTokenSource = new CancellationTokenSource(); var expirationToken = expirationTokenSource.Token; Task.Delay(expireIn, expirationToken).ContinueWith(_ => Expire(key), expirationToken); _expireTasks[key] = expirationTokenSource; return (T)(this [key] = create()); }
SeesionPool 存放所有Session 取Session會判斷此Guid是否有對應的Session物件,沒有會幫她創建一個放在池子中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class SessionPool { private Dictionary<Guid, SessionObject> _SessionContain = new Dictionary<Guid, SessionObject>(); public SessionObject this [Guid index] { get { SessionObject obj; if (_SessionContain.TryGetValue(index, out obj)) { return obj; } else { obj = new SessionObject(); _SessionContain.Add(index, obj); } return obj; } } }
SessionObject 控制讀取時的值 (一般我們所使用的Session)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class SessionObject { private CacheDictionary cache = new CacheDictionary(); public object this [string index] { get { return GetObj(index); } set { SetCache(index, value ); } } private void SetCache (string key, object value ) { cache.Set(key, () => value ); } private object GetObj (string key ) { return cache.GetOrDefault(key, () => default (object )); } }
使用:
在建構子中創建一個 ApplicationContext 之後,即可Asp.net那樣來使用Session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private ApplicationContext app;public SessionHanlder (){ app = new ApplicationContext(HttpContext.Current); } public void ProcessRequest (HttpContext context ){ if (null == app.Session["Time" ]) { app.Session["Time" ] = $"Hello {DateTime.Now.ToString("yyyy-MM-dd hh-mm-ss" )} " ; } context.Response.Write(app.Session["Time" ]); context.Response.ContentType = "text/plain" ; }
上面程式是簡單模擬Session核心作用的程式
但並未處理多執行緒並發讀寫…等等問題,所以建議別再實際專案中使用XD!!
專案使用 VS2015 GitHub原始碼
__此文作者__:Daniel Shih(石頭) __此文地址__: https://isdaniel.github.io/own-session/ __版權聲明__:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!