【C#】自製微型 Asp.net Session

我们在写网站一定会使用到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来存放目前所有SessionSessionObject (支援快取在系统记忆体中)
模拟HttpContext封装Session

实作:
我要简单呈现就选择使用轻便 [泛型处理常式]

ApplicationContext 模拟HttpContext封装SessionPool
创建一个静态的SessionPool物件,因为程式都共用此SessionPool

/// <summary>/// 请求上下文/// </summary>public class ApplicationContext{    /// <summary>    /// 存在Cookie中的SessionID    /// </summary>    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();        }    }    /// <summary>    /// 从SessionPool中取得Session对象    /// </summary>    /// <returns></returns>    private SessionObject GetSessionObj()    {        Guid sessionGuid;        HttpCookie CookieSessionID = Request.Cookies[MySessionID];        //如果没有MySessionID的cookie,做一个新的        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存取物件设置快取

/// <summary>/// 掌管物件存活时间的集合/// </summary>private readonly Dictionary<string, CancellationTokenSource> _expireContaner =    new Dictionary<string, CancellationTokenSource>();

在Task.Delay可以让物件存放在工作执行绪中 等Delay时间到就呼叫 ContinueWith 将物件消毁

/// <summary>/// 设置快取对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="key"></param>/// <param name="create"></param>/// <param name="expireIn"></param>/// <returns></returns>public T Set<T>(string key, Func<T> create, TimeSpan expireIn){    //如果此Key被使用 将原本的内容移除    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物件,没有会帮她创建一个放在池子中

/// <summary>/// 存放所有Session池子/// </summary>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)

/// <summary>/// Session物件/// </summary>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

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原始码


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章