Context,我爱上你给的痛

 在 《ASP.NET,抬起头来,让朕瞧瞧》一文中,我曾经提起要对我的“老相好”Context专门写一篇blog。是的,这篇就是了。 请原谅我把这个题目起成这样,但是,Context确实曾经带给了我很多痛,然一直以来又为其着迷的很,所以......

  我以前学过很长一段时间Lotus Domino/Notes。应该说,它是我第一个了解得比较深入的软件,正是因为它,我才走上编程这条路。但是,在我对Lotus Domino/Notes的C/S模式编程有了比较深刻的理解后,在很长一段时间内,对B/S模式却始终不得其门而入。后来,经高人指点,知道不能使用Domino/Notes的那些前端类(比如UIDocument之类),而要使用DocumentContext类,通过它才可以访问请求信息,访问客户端和服务器环境变量。现在想来,原因很简单,就是因为HTTP是个无状态,无连接的协议,对于每次请求,都当作一个新的请求,而不是像客户端编程那样,服务端会为你维持状态。然而,我虽然意识到DocumentContext类是B/S模式编程的核心,但一直对它理解的不好。Context,翻译成中文是“上下文”,“上下文”?三个字的词,就像“运行时”一样,读起来让人觉得不爽,理解起来也甚是抽象。它到底能够提供给我们什么?直到后来看了一本《Lotus Domino/Notes R5 Web高级编程》(如果你对Domino开发有兴趣,这本书当是所有Domino书中的翘楚)才开始有所领会。但是,我得承认,即使是自己看了不少别人的代码,自己也写了一些之后,但是,DocumentContext对于我来说,还是“犹抱琵琶半遮面”。

     在开始学习asp.net之后,我再次遇到了Context----HttpContext。虽然这回不再那么陌生,但是,依然无法真正把握它。它到底是怎么样的一个东西?它和request,response,session,application,server这几个我们在页面中常用的状态变量是怎么样的一个关系。终于在这次分析asp.net的底层实现的时候看到了她的庐山真面目。

    其实,就像每一个故事中间每个情节的发生都不是突来其笔,或者前面有伏笔,或者后面有照应,都是有“上下文”的,是有环境因素来影响的(想想胡戈的《一个馒头引发的血案》,是不是?)。上下文,也就是事件处理的环境,这个环境决定了在某一步该做如何处理,为什么这样处理。ASP.NET对于我们的每一个请求,都有一个HTTPContext对象,这个对象就代表着这个请求的上下文环境。我们说当前的环境,描述环境好坏的办法就是用数据来表示,让数据说话。这就好像我们说一个对象的状态,是通过其当前字段的值来表示是一样的。然而,这样的数据太多了,需要分类,从不同的角度来组织这些信息,以方便我们使用。因此,httpContext把自己的状态信息分类: 有请求信息类别(request)的,有响应信息类别(response)的,有属于当前会话类别(session)的,有属于服务器信息类别(server)的,有应用程序级别(application)的,还有认证信息,缓存信息等等。可以说,它包容了处理当前请求所需要的所有信息。

    前些日子,还看了几集《汉武大帝》,当时想到一个比喻,觉得甚妙,拿出来和大家分享。皇上(客户:客户就是上帝,就是至高无上的皇上)下达了作战指令,要攻打哪个目标,实现什么要求,把任务交给了HttpApplication元帅。是的,HttpApplication作为事件调度中心,就像是坐镇中央,运筹帷幄,决胜千里的元帅,而http module,http handler则是HttpApplication手下的大将,其中,http handler更是是其锋线尖刀,具体来说就是http module负责作进攻前的佯攻和进攻后的善后处理,http handler则是真正的主力,直捣黄龙,一剑封喉。 Http Context则象是当前战争的形势,敌方情报,应敌对策都在这里面,HttpApplication向http module,http handler各位将军传达形势之后,各位将军各司其职,竭尽所能改变战争形势,使得战争形势朝我方有利方向发展,直到结束战斗。最后向皇上发回军报:战争的结果。

   在《ASP.NET,抬起头来,让朕瞧瞧》一文中,我特意提到httpContext有一个非常有用的属性:Items。是的,它真的非常有用,它是一个可以存储任何对象的集合。真的是任何对象都可以存储,通过Reflector,你可以看到它的声明,如下:

private  Hashtable _items;

public  IDictionary Items
{
      
get
      {
            
if  ( this ._items  ==   null )
            {
                  
this ._items  =   new  Hashtable();
            }
            
return   this ._items;
      }
}

  它存储的对象没有任何限制,连ViewState中存储的对象都要能序列化(因为viewState中的数据要在客户端和服务器端来回跑),而它却什么都不要,因为它只贮存在服务器上!然而,它真正有用的原因,不是因为它“海纳百川”这一点,而是因为它是在HttpContext对象中!还记得吗?我说过“ASP.NET对于我们的每一个请求,都有一个HTTPContext对象”,是的,一个请求就有一个HTTPContext对象,换言之,这个请求处理完了,这个HTTPContext对象也就完了。我们的项目组曾经遇到了这样一个问题,在一个高级查询页面生成查询条件,然后传递给查询结果显示页面,由其显示结果。但是这个查询字符串可能会很长很长(超过256个字符),不能使用QueryString来传递,这个时候我们该怎么办呢?使用session吗?是一个方法,但是session意味着在会话期间的长久保存。是的,你可以说在查询结果显示页面得到查询条件字符串之后就手动删除,很好,这是一个办法。但是我得告诉你,如果session状态被存储为独立的状态服务器或sql server中的时候,就会遭受响应的性能冲突。那怎么办呢?上天有好生之德,而无绝人之路,我们有HttpContext,HttpContext里面有Items。它可以保存任何类型的数据,并且无论里面放什么内容,都会在这个请求处理完毕之后,随着对应的HttpContext的销毁而自动删除。对了,还有,在我们使用Item保存了查询条件之后,我们使用Server.Transfer()跳转到结果显示页面,在那里取出查询条件。注意,不是使用Response.Redirect(),而是Server.Transfer(),从这两个方法所属的对象上,你应该知道它们的差别在哪里。

    还有一个问题,也是一个很重要的问题。我们反复提到:“ASP.NET对于我们的每一个请求,都有一个HTTPContext对象”,请求处理完毕,这个HTTPContext对象的生命也跟着走到了尽头。糟糕,那里面保存着我们的Application状态的数据啊,是不是也跟着销毁了?哈哈哈,让我们通过reflector来看看HTTPContext对象中的这个Application对象吧:

 

public  HttpApplicationState Application
{
      
get
      {
        
return  HttpApplicationFactory.ApplicationState;
      }
}

 

   你可注意到了它是在HttpApplicationFactory中保存的,而不是在httpApplication中保存的?那就接下来再看看HttpApplicationFactory.ApplicationState是怎么回事:

private  HttpApplicationState _state
private   static  HttpApplicationFactory _theApplicationFactory;
 

internal   static  HttpApplicationState ApplicationState
{
      
get
      {
            HttpApplicationState state1 
=  HttpApplicationFactory._theApplicationFactory._state;
            
if  (state1  ==   null )
            {
                  state1 
=   new  HttpApplicationState();
            }
            
return  state1;
      }

 

 

     在《ASP.NET,抬起头来,让朕瞧瞧》一文中提到过,对于每个请求,HttpRuntime会去向HttpApplicationFactory要一个httpApplication,每个请求都有一个httpApplication,但是对于这个网站运行期间,是只有一个HttpApplicationFactory在运行着的,它维护着一个httpApplication对象池。我们的Application中保存的数据保存在HttpApplicationFactory中,并且_theApplicationFactory还是static的,当然不会随着每个请求处理的结束而丢失,除非网站重启。其实,想想,它存储在HttpApplicationFactory中,这也是我们为什么说它里面存储的数据是应用程序级别的全局的数据的根本原因所在。

     文章写到这,已经相当长了,甚至有些偏离了我本来对Context的讨论。尽管如此,我还得告诉你,如果你以后看Web Service,你还会碰到另外一个与Context相关的对象:SoapContext。也很有意思,但是本质上还是一样,表示提供上下文环境的数据支持。在此,我只能祝你好运,因为我对它也了解的不多,看来,我与Context还要再续一段情缘啊,哈哈哈......

 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值