在编码中,我们常常会碰到一个概念:上下文,如 线程上线文(Thread.CurrentContext),Http上下文(HttpContext.Current)等,那么上下文到底是什么,它们存在的意义是什么?
一:上下文
1:来源
可能无从追溯,但是早期 上下文 这个概念,可能来自于 CPU时间片 的切换。在单CPU阶段,我们知道,虽然程序可以模拟出来是多进程(如多个EXE)或多线程运行的,但是实际上到了CPU这个层面,同时只能执行一条指令。CPU的快速切换,为程序模拟出来了多进程执行,但是,为了这种模拟,即:当一个进程时间片到了或者资缺的时候就会让出cpu,当另一个进程开始始用CPU之前,系统要保存即将退出进程的执行状态,以便轮到时间片或有资源的时候现场恢复,这就所谓的 上下文切换。
后来,我们把保留状态、以及恢复状态这种事情,都叫成了 上下文切换。Http上下文,指的就是这种情况,服务器要应对来自各地的请求,每次请求之间的状态保留和恢复(主要是 Request、Response、Session-即会话等)就叫做 Http上下文 切换,那么,这些工作所在的这个类,在 .NET 中,就是 HttpContext。
上下文的更进一步阅读,可以参考:
2:HttpContext.Current 的本质
现在,回归到语言学上的本质,其本质必定是一个 static 的对象,为什么,因为如果不是 static 的,我们就不能快捷的访问它。试想,如果是 new HttpContext 的,就会给程序员造成误解,原来上下文每次请求都是重新生成的呀。它当然不应该是,为什么呢,因为本次请求的上下文信息在上次请求中就已经是存在的了。这是 Current 属性的源码:
如果再沿着 ContextBase.Current 跟踪下去,还可以追踪到这里,可以看到,Http上下文 居然也是和 Thread 相关的,这也从另一个方面印证了其实上下文在本质上都是某种状态的保存和切换:
二:会话
1:会话是什么?
现实世界中,会话就是两个人直接的对象,只要两个人还存在,就可以一直延续对话,在 WEB 应用中,这两个人一个就是客户端,一个就是服务器,只要客户端还在有效时间内,那么跟服务器就可以继续通信,并且服务器还能知道你就是那个北京的客户端,而不是上海的客户端,虽然可能上海也有客户端在跟我通信。那么,知道你就是那个北京的客户端,就是 HttpContext 所干的事情(底层),而客户端和服务器通信的数据(上层),就是会话数据,这些通信数据可以被储存在 Session(即会话) 中。
2:会话的本质
有了上面的理解,我们可以发现,会话不就是上下文吗。其实,这么理解是正确的,只不过,上下文偏向于底层多一点,而会话偏向于上层多一点。由于 Session 是依附在 Http上下文 中的,所以 Session 也就变成 static 的了。那么 Session 的本质是什么呢:
其本质是个 Items,它就是个 Dictionary。如果我们自己要实现一个所谓的 Session,我们本质上完全可以类似这样来实现:
class MyContent
{ public static Dictionary<string, object> Session = new Dictionary<string, object>();}
3:Session的限制
ASP.NET 默认实现的 Session 机制,是把数据保存在了内存中,内存在不够的时候的,数据是要易失的,所以 ASP.NET 引擎也提供了其它的数据保存机制,如数据库,同时它也允许我们自己实现自己的数据保存。
4:利用默认的 Session 数据保存机制
即便这样,Session 仍旧有广泛的应用,如:保存业务逻辑意义上的会话。如,在 领域驱动开发 中,领域模型 对象可以保存在会话中,因为领域模型是有状态的,它有维护自己状态的 Key,我们可以利用这一点,将对象保存在 Session 中,这样,就没有必要每次请求,都重新恢复 领域对象,因为恢复领域对象,就意味着要从数据库中进行读取,而交给 Session,我们就可以绕开数据库读取,只要在对象被失去的时候,再从新从数据库恢复就可以了。