回到之前,当服务器在处理如aspx.ashx,等等动态文件的时候,IIS服务器将Request请求,交
给aspnet_isapi.dll文件来处理。
ISAPI是第一个也是性能最高Request请求报文最原始的Web请求切入点
aspnet_isapi.dll是一个非常底层,并且是非托管的win32API,这个dll非常简单,非常高效,并且还被微软优化过性能。它用来处理最底层的 指令以及函数回调,并为高层程序提供了应用程序级别服务的功能和接口。
当aspnet_isapi.dll接收到Request请求的时候,aspnet_isapi.dll就会去调动Web服务器中的.Net Framework,最终加载CLR运行环境,并创建一个ISAPIRuntime对象,然后调用ISAPIRuntime对象的
PRocessRequest()方法。
ISAPIRuntme.ProcessRequest()方法是进入ASP.Net的第一个入口
ISAPIRuntime.ProcessRequest()方法调用之后主要做了一件事情,就是将Request的原始请求信息封装成HttpWorkRequest类,由于HttpWorkRequest类封装的请求报文很原始,很复杂,所以微软没有将其公开出来。接着执行StartProcessing()方法,来创建HttpRuntime对象并调用其静态方法ProcessRequest()。
图三 : 如何开始ASP.Net
在HttpRuntime对象调用其静态方法ProcessRequest()之后,我们的Web请求开始慢慢进入应用层级别,why?
ProcessRequest()这个方法做了很多事情,具体可以通过Reflector工具查看,但是大致分为四个部分:
1.为请求创建了一个新的HttpContext实例(这个对象就是我们常用的HttpContext上下文对象),并将HttpWorkRequest中最原始的请求
报文封装到HttpContext对象的HttpRequest对象中。
2.通过HttpApplicationFactory(应用程序工厂)得到一个具体的HttpApplication 实例。
3.调用HttpApplication.Init()方法来建立事件请求管道。
4.Init()方法触发了HttpApplication.ResumeProcessing()方法来开始执行Asp.Net事件请求管道。
图四 : HttpRuntime,HttpApplication和HttpContext的关系
Asp.Net事件请求管道详解
前面说Asp.Net是一个Aop框架,而Asp.Net事件请求管道就是一点。
Asp.Net事件请求管道,是微软帮程序员提供来处理Web请求的一些列事件,这些事件是依次执行,我们可以通过在这些事件上注册或移除我们自己写的方法,来修改Web请求执行的逻辑。
图五 : ASP.Net事件请求管道
在第八个事件的时候,会创建请求的页面对象,并转换为IHttpHandler接口。
在第九个事件到第十一个事件之间,会接收到浏览器发过来的
sessionId。并先会将IHttpHandler接口尝试转换为IRequiresSessionState接口,如果转换成功,Asp.Net会根据这个SessionId到服务器的Session池中去查找所对应的Session对象,并将这个Session对象赋值到HttpContext对象的Session属性。如果尝试转换为IRequiresSessionState接口不成功,则不加载Session。
在第十一个事件到第十二个事件之间,会调用在第八个事件创建的页面对象的ProcessRequest方法。
当我们直接使用*.ashx页面的时候,就直接调用了一个FrameworkInitialize(),并最终生成响应报文,发送回客户端。
当我们在使用*.aspx页面的时候,它继承自Page类,而Page类实现了IHttpHandler接口。
由于Page类实现了IHttpHandler接口,在ProcessRequest方法中,调用了FrameworkInitialize()方法。
在FrameworkInitialize()这个方法内部就开始打造Asp.Net的页面控件树(打造html树),在其中就调用了ProcessRequestMain方法,在这个方法里面就执行了整个Asp.Net页面生命周期。
IHttpModules
请求通过事件管道,一些列的事件被触发了,我们可以通过在Global.asax全局配置文件中看到这些事件。
但是由于这是由程序分配的事件,可能就不是我们想要的。如果我们想要创建一个能够复用的HttpApplication事件管道来处理Web请求,
我们又想将这些代码复用,或者开发成插件的形式。那么我们就可以使用IHttpModules。
IHttpModules配置很简单,我们只需要在Web.config里面配置一下就可以了。而具体的HttpModules只需要实现IHttpModules接口,并注册自己的方法就行了。
<?xml version="1.0"?>
<system.web>
<httpModules>
<add name="VEVbHttpModules" type="VEVb.VEVbHttpModules"/>
</httpModules>
</system.web>
</configuration>
Web.config文件的配置
publicclass VEVbHttpModules : IHttpModule
{
public void MyBeginRequest(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
application.Context.Response.Write("这个IHttpModule具体类的写法哟!");
}
}
具体的HttpModules类写法
Asp.Net页面生命周期详解
Asp.Net是一个Aop框架,而Asp.Net事件请求管道体现了Aop思想,而现在我们要说的Asp.Net页面生命周期也体现Aop思想。
Asp.Net页面生命周期的本质就是微软提供给我们程序员修改页面控件树代码的一些列事件,我们可以通过实现页面生命周期的事件方法来修改控件树代码。
图六 : ASP.Net页面生命周期
当ASP.Net执行完我们注册的生命周期事件方法的时候,最后会调用Render方法,Render方法要求传入一个TextWriter文本写出器对象,并遍历所有控件树,调用每个控件的Render方法。
所以每一个控件调用Render方法之后产生的Html字符串都依次写入到TextWriter对象。最后ASP.Net将TextWriter中的Html字符串封装成响应报文,然后发送回客户端。
结束语
在这里,我介绍了一下ASP.Net的整个处理请求的过程。但有很多底层的信息,我还没有仔细去观察过,因此很多细节可能还是没有注意到。这篇文章可能还是有很多错误的地方,希望博客园的兄弟姐妹们纠错,谢谢。