【转】ASP.NET应用程序生命周期趣谈

这几天一直在看ASP.net应用程序生命周期,真是太难了,我理解起来费了劲了,但偏偏它又是那么重要,所以我希望能给大家带来一篇容易理解又好用的文章来帮助学习ASP.NET应用程序生命周期。这篇就是了。

  当你访问博客园想看我的这篇文章的时候,这个请求就被博客园的Web SERVER(IIS)接收到了。博客园IIS看了一眼我的请求,“噢,是.aspx啊,给ASP.NET去处理吧,就把我这个请求给了ASP.NET, 并且说:“这个你来处理,你处理完了之后把HTML给我,我好给邱爽一个回复”。

  ASP.NET收到IIS传递过来的请求后也没时间抱怨啊 就开始干活儿了。怎么干的呢?

  第一,它先创建了一个Context对象,它就像个箱子,箱子当然是来装东西的啦,装什么呢?

  第二,ASP.NET创建了一个Request对象,包含了IIS传递给它的所有信息(IIS传递过来的实际就是个Request嘛)。

  第三,ASP.NET接着又创建了一个Response对象,用来装HTML的,也放进箱子(Context)

  第四,然后,ASP.NET说,太累了,这活儿没个干,还是雇个人吧。就雇了个项目经理(HttpApplication对象),然后就把箱子 (Context)交给项目经理并且对它说,这里有我们收到的 Request,你需要做的就是把里面的Reponse填一下,具体怎么干你掂量着吧,就走了。

  这个项目经理(HttpApplication对象)就想啊,凭啥活儿我干钱你们拿啊?不行,我得找俩苦力去,于是就有了:程序员 HttpModule和程序员HttpHandler,姑且就称他们为P_Module和 P_Handler吧,项目经理先找到了P_Module.

  P_Module(HttpModule)非常的能干,它能够去查看 ASP.NET交给项目经理(HttpApplication对象)的箱子(Context),并且根据里面的东西做一些决定,比如安全啊 (FormsAuthenticationModule),状态啊(SessionStateModule )等等吧。在P_Module工作完成之后 (也许已经改变了箱子里(Context)的内容),项目经理开始找P_Handler来做填充Response的工作。现在招人难啊,找了好久也没招 到,好吧,找猎头(HttpHandler Factory)吧。猎头公司一看,“噢,要.aspx Handler啊",于是找来了一个天生就善于并且愿意处理页面的P_Handler(.aspx页面最终会编译成一个有继承机构的 IHttpHander),然后交给项目经理(HttpApplication)。项目经理看了一眼P_Handler之后,觉得还行,就把 P_Module处理过的箱子交给它并且说:"处理一下这个箱子里的东西,然后交给我"。

  P_Handler是个天生的处理页面的牛人,它根据Request 对象里的东西是用了一招"乾坤大挪移",不知道怎么挪的,就挪出了HTML并塞进了Response对象中。P_Handler自信的笑了一声,把箱子交 还给了项目经理(HttpApplication对象)。项目经理从箱子里面把Response对象拿出来直接给了IIS,IIS又给了你了,你就看到这 篇文章了。

  故事就是故事,故事就是故去的事,就是往事。那往事肯定就有遗漏的地方。那我们这个故事遗漏了哪些地方呢?

  第一,IIS和ASP.NET之间的交互不是像我说的那么简单而直接的,中间还发生了很多事情。

  第二,HttpModule,也就是我们的程序员P_Module, 它其实还能干很多事情,我们并没有去发掘。

  第三,HttpHandler,也就是我们的程序员P_Handler,它的"乾坤大挪移"就是ProcessRequest方法,这里并没有详述到。

  第四,。。。等我再想想再跟您聊。ASP.NET应用程序生命周期趣谈(一)

  希望这边小文能够帮助你更容易的理解ASP.NET生命周期,我会继续努力,争取以最简单明了的方式来speak out ASP.NET原理和运行机制。欢迎拍砖,谢谢。

 

ASP.NET应用程序生命周期趣谈(二)

 

  在上回书开始的时候我们提到博客园的IIS看了一眼我的请求后就直接交给ASP.net去处理了,并且要求ASP.NET处理完之后返回HTML以供展示。

  那么我们不仅要问:

  1,    IIS肯定是没有眼睛的啦,那它是怎么“看”的呢?

  2,    在“看”到了.aspx的页面请求后又是如何把它交给ASP.NET的呢?如果不做任何处理那它的存在又有什么意义呢?

  3,    ASP.NET收到这个处理请求后又是如何做的呢?它是怎么创建Context对象又是如何“雇佣”项目经理HttpApplication对象的呢?

  本文将就这些问题进行深入而简单的探讨。

  当你点击了这篇文章的链接,在很短的一段时间内博客园的IIS就收到了你的请求。它要“看”了。正如我们知道的,它没有眼睛,所以它依靠 ISAPI来“看”请求的后缀。我们这次请求的是.ASPX文件。ISAPI是全称Inernet Server Application Programe Interface, 它就是IIS的眼睛和路由器,先看后缀然后分发给各个应用,我们可以通过访问IIS的站点的属性—》主目录—》配置 来查看它的路由映射。

ASP.NET应用程序生命周期趣谈(二)

  我们发现,在.aspx extension对应的Executable Path里,真正处理asp.net应用程序的是aspnet_isapi.dll。可以清楚的看到,它还能处理ASAX,ASCX, ASHX, ASD,BROWER,CD等等等一堆啊,真是功能强大。

  然而,在“看”的方法方式上,IIS5和IIS6有一些不同。

  IIS5通过inetinfo.exe进程在TCP端口(默认是80)来“看”那些进来的Request。正如我们刚才看到的,如果这些 Request是需要aspnet_isapi.dll来处理,则aspnet_isapi.dll创建(不太确定worker process是不是aspnet_isapi.dll创建的,但是它们通过命名管道来交互)并持续监视一个aspnet_wp.exe进程,它就是 asp.net最重要的组件:worker process。几乎所有的工作都是在这个进程中完成,它在IIS6中被改名叫做w3wp.exe。

  IIS6则通过内核模式中的HTTP.SYS来“看”那些进来的Request。HTTP.SYS把进来的Request发送到相应的 Application Pool(应用程序池)。应用程序池再把Request传递给aspnet_isapi来进行创建worker process的工作。IIS6中的worker process已经是w3wp.exe了。

  接下来在最重要的worker process中发生了什么呢?项目经理HttpApplication又是怎么被雇来的呢?请听我慢慢道来。

  ASPNET_ISAPI在创建了worker process加载了CLR完成了托管环境的布局后,就什么都不管啦。Worker process开始管理一切,它把所有的工作都交给了HttpRuntime。最后,是HttpRuntime雇佣了项目经理 HttpApplication。然后,HttpRuntime并不是什么工作都没有做,它已经通过配置文件创建了所有的HttpModule并填写在了 HttpApplication的“工作列表”中,项目经理HttpApplicaiton事根据这个列表来工作的。HttpRuntime也创建了 HttpContext这个箱子并交给了项目经理HttpApplication。乎!现在我们终于理解“asp.net创建了HttpContext” 这句话了吧。现在总结一下HttpRuntime都干了什么:

  1,    打造了HttpContext这个箱子来存储Request和Response

  2,    建立了工作列表HttpModule

  3,    雇佣了项目经理HttpApplication并把箱子Context交给它,然后把工作列表作为效绩考核列表也交给他。

  4,    等着返回结果

  PS:在这个过程中,其实还有更详细的过程,但是我觉得那无助与我们理解真正的重要的东西,反而会带来更高的难度,所以也就没往上写。有兴趣的筒子们可以去微软网站搜索相关资源。

  接下来,“项目经理”HttpApplication所作的事相信大家已经在前一篇文章中有所了解啦,什么?没看?那就赶紧去看看吧。

 

 

ASP.NET应用程序生命周期趣谈(三) HttpModule

  在之前的文章中,我们提到过P_Module(HttpModule)这个能干的程序员哥们儿,它通过在项目经理 HttpApplication那里得到的授权,插手整个应用程序级别的事件处理。所有的HttpModule都要实现IHttpModule接口,那么 我们看IHttpModule的定义:

 

 namespace System.Web   {
  public interface IHttpModule   {   void Dispose();
  void Init(HttpApplication context);   }
  }

  可以看到,HttpModule 主要就做了两件事,一个就是大家都明白的释放资源Dispose(),另一个则是初始化。用什么初始化呢?当然是HttpApplication。刚才已 经说过,P_Module程序员是经过了项目经理HttpApplication的授权了的,这里我们就可以看到,初始化方法参数就是 HttpApplication对象,那么HttpModule又是怎么处理应用程序级别的事件的呢?且看:

ASP.NET应用程序生命周期趣谈(三) HttpModule

  我们可以看到,项目经理HttpApplication可是实实在在的放权啊,它非常的相信P_Module可以做好这些事情,所以在初始化方 法 Init(HttpApplication context)中,程序员P_Module可以注册很多事件,比如说常用的BeginRequest, EndRequest, AuthenticateRequest, AuthorizeRequest等等,还有一些其它的不常用的事件我们就不再赘述。总而言之,HttpModule强大到可以插手整个应用程序周期的所 有事件---因为得到了充分授权嘛。下面是注册BeginRequest事件示例代码:

 

 public void Init(HttpApplication context)
  {   context.EndRequest+= new EventHandler(context_EndRequest);   }
  private void context_EndRequest(object sender, EventArgs e)   {
  //do something when the request end   }

  那么这里,我们要澄清一个问题:在ASP.net应用程序生命周期趣谈(一)中我们曾经在后面提到“P_Handler自信的笑了一声,把箱子 交还给了项目经理(HttpApplication对象)”,这是不完全准确的。事实上P_Module已经是一个非常高级的程序员,他在有必要的情况下 (注册了EndRequest事件)是要review中级程序员 P_Module的工作的,这个review的事件就是HttpApplication的EndRequest的事件。当然,有时候也不review就直 接交给HttpApplication了,所以我们得出结论:ASP.NET请求处理是基于管道模型的,request从管道这头进去,经过了 HttpModule的一些列处理,到那头儿的HttpHandler再处理,最后再经过管道原路返回。一次请求HttpHandler只能有一个,而 HttpModule却可以有若干个。(ps: --!真是废话,MSND上写的比谁都清楚)

  总的来说,P_Module高级程序员主要就是从项目经理HttpApplication那得到授权(传入HttpApplication参 数)处理应用程序级别的一些重要事件,这些事件贯穿整个应用程序生命周期。我们经常会使用到ASP.NET自带的HttpModule,也有时会使用自定 义的HttpModule。ASP.NET自带的HttpModul在以下目录中可以找到:C:\Windows\Microsoft.NET \Framework\v2.0.50727 \CONFIG/Web.config

ASP.NET应用程序生命周期趣谈(三) HttpModule

  而我们自己编写的自定义HttpModule则写在我们的应用程序的Web.config文件中,也是节点下,与系统自动配置的并无不同:

ASP.NET应用程序生命周期趣谈(三) HttpModule

  可以看到,节点是在system.web下面的,HibernateUtil就是我曾经写过的一个 HttpModule,非常典型,大家可以参考。对与系统自带的HttpModule有很多,这里我就随便挑了一个SessionStateModule 来给大家做一个大致的分析,以便大家了解HttpModule如何工作。

  简单说一下什么事 SessionState。SessionState就是ASP.net处理Session的一种机制,简单来说就是它通过管理Session的存储位 置,来优化Session的性能和安全性,避免浏览器禁用cookie时session丢失。ASP.NET允许Session存储在三个位 置:aspnet_wp.exe(它崩溃session就丢失);aspnet_state.exe(单独的 stateserver);sqlserver(存到数据库中)。关于SessionState的内容,请参阅其它相关文章,以后有机会我自己也会写写。

  书归正传,那么我们通过反编译SessionStateModule,我们得到两行有用的代码:

 

 public void Init(HttpApplication app)   {
  SessionStateSection sessionState = RuntimeConfig.GetAppConfig().SessionState;
  //从config文件中读取SessionState配置
  this.InitModuleFromConfig(app, sessionState);
  //初始化SessionStateModule需要处理的事件   //Other Code
  }

  第一行从config文件中读取了SessionState的配置(节点下面的内容,配置了怎么存储Session等信息),第二行则初始化了SessionStateModule需要处理的事件,我们再看看InitModuleFromModule干了什么:

 

 private void InitModuleFromConfig(HttpApplication app, SessionStateSection config)
  {   if (config.Mode != SessionStateMode.Off)   {
  app.AddOnAcquireRequestStateAsync(new BeginEventHandler(this.BeginAcquireState), new EndEventHandler(this.EndAcquireState));
  app.ReleaseRequestState += new EventHandler(this.OnReleaseState);
  app.EndRequest += new EventHandler(this.OnEndRequest);   }
  }

  我们可以看到,第一行代码中,HttpApplication添加了OnAcquireRequestState的若干事件的处理方法,第二行 添加了当 SessionState释放时的处理方法,第三行则添加了request接触时的处理方法。SessionStateModule内部如何处理我们这里 不做详述,但是我们可以清晰的看到,SessionStateModule处理了应用程序级别的时间,包括SessionState的获得,释放和 Request的结束。我们没有发现它处理开始Request的事件,但我们确信它是有能力去做的,只是此种情形下并不需要那么做。下面按照执行顺序列出 HttpApplication的事件列表以供参考:

 

   1.     BeginRequest   //开始   2.     AuthenticateRequest //验证   3.     AuthorizeRequest //授权   4.     AcquireRequestState //获取request state
  5.     ReleaseRequestState //释放request state   6.     UpdateRequestCache //更新cache   7.     LogRequest.   //这个事件只支持.net 3.0以上版本和IIS7的集成模式   8.     EndRequest //结束

  所有的HttpModule(包括自定义的和系统自带的)均有能力处理这些事件从而对应用程序产生影响,看来这个P_Module程序员果然很牛啊,项目经理信任它并授权也是有道理的。

  然后P_Module作为一个高级程序员,它自身知识积累固然很强大,它的学习能力也是不可忽视的。它可以自己学习(创建)一些新的能力(自定 义Module),经典的例子就是它网上盛传的它能在每个页面中都加入一些文字;这里我只简单的说明我用过的一个P_Module自建的在 EndRequest事件中关闭 NHibernateSession的例子:

  首先,我们创建一个类HibernateUtil,继承接口IHttpModule,并实现接口方法:

 

 public class HibernateUtil : IHttpModule   {
  public void Dispose()   {   }
  public void Init(HttpApplication context)   {   }
  }

  然后,注册EndRequest事件:

 

以下是代码片段:  public void Init(HttpApplication context)   {
  context.EndRequest+= new EventHandler(context_EndRequest);   }
  private void context_EndRequest(object sender, EventArgs e)   {
  CloseSession();   }

  最后,配置Web.config:

ASP.NET应用程序生命周期趣谈(三) HttpModule

  此时,我们就完成了一个自定义的HttpModule。这个小例子并不难,主要是说明了HttpModule的创建流程和方法,而本篇文章也难度也不是很高,希望对大家能有所帮助,欢迎拍砖,少扔鸡蛋,挺贵的,谢谢! ^_^

posted @ 2012-03-08 20:13  --------  阅读(256)  评论(1编辑  收藏  举报