当一个客户端页面访问IIS试图获取一些信息的时候
发生了什么事情?一个请求在通过了HTTP管道后又发生了什么?本文主要是描述这两个过程
即IIS处理请求和的页面生命周期
欢迎大家积极拍砖
共同学习
共同进步
首先我们要弄清楚两个非常重要的概念 worker process(wwpexe) worker process管理所有的来自客户端的请求并给出响应它是IIS下应用程序的核心
application pool 它是worker process的容器IIS及之前的IIS版本均没有application pool的概念每一个application pool对应着一个worker process在IIS Metabase中维护着Application Pool和worker process的Mapping这就避免了IIS中出现的worker process(IIS中是aspnet_wpexe同一时间只能运行一个该进程)崩溃application全崩溃的局面
客户端向IIS发出一个资源请求后发生了如下事情 server接受该请求
IIS通过内核模式(Kernel mode)中的HTTPSYS来分发各个Request到application pool 这并不是随机的过程在application pool创建的时候就已经注册到了HTTPSYS所以当请求来到时HTTPSYS会直接发送到相应的application pool 接下来在IIS的用户模式(User mode)中Web Admin Services (WAS) 做了从HTTPSYS中得到Request并分发到application pool的工作application pool直接把request传递给worker process
请求传递到worker process后worker process初始化加载ASPNET ISAPI(Internet Server Application Program Interface)ASPNET ISAPI进而加载CLR创建托管环境
(注ISAPI只是一个接口起到一个代理的作用主要能力就是根据Request URL的后缀来寻找该后缀的处理程序)
ASPNET ISAPI定义在aspnet_isapidll中它本身运行在一个非托管的环境中ASPNET ISAPI开始一个HttpRuntime HttpRuntime调用ProcessRequest方法来开始处理请求ProcessRequest根据ISAPI传进来的iWRType 来创建不同的HttpWorkerRequest从而屏蔽了不同IIS的差异接下来ProcessRequest方法创建了HttpContext我们使用HTTPContextCurrent来访问它在HttpRuntime使用HttpApplicationFactory创建了HttpApplication对象(IHttpHandler)以后所有的请求都会在通过httpmodule后找到相应的Httphandler进行处理在HttpApplicationFactory创建HttpApplication之前会查找config(nfig和nfig)文件中注册的所有的HttpModule并根据配置信息加载相应的Assembly通过Reflection创建对应的HttpModule并将这些Module加到HttpApplication 的_moduleCollection Filed中我们对一个Application的请求最终会落到一个HttpApplication对象上当一个请求到来时ASPNET会在Httplication Pool中查找未被使用的HttpApplication对象
请求通过HTTP管道后每个请求都发向相关的各自的httphandlerIIS请求处理过程结束
HttpHandler是HTTP管道的终点它为每个request生成输出SystemWebUIPage就是这样一个典型的Httphandler当我们请求一个aspx页面这个HttpHandler就生成html发送回客户端看Page类的签名
public class Page : TemplateControl IHttpHandler
{
}
可以看到Page类就是一个HttpHandler
综上整个过程就是当客户端向服务器发送资源请求时请求首先到达IIS的HTTPSYS然后HTTPSYS发送请求道对应的Application Pool 然后Application Pool发送请求到Worker Process(WWPexe)中加载ISAPI ExtensionISAPI创建一个HttpRuntime对象来通过HttpModule和HttpHandler处理请求 然后页面生命周期就开始了
页面生命周期开始 页面生命周期的主要阶段包括
页面初始化(Init): 服务器创建服务器控件的实例
加载(load): 控件实例被加载到它定义的页面对象中
预输出:(PreRender) 对控件的更改被更新准备输出
保存(SaveViewState): 控件的状态信息被保存
输出页面(Render):服务器为控件创建html标记
处理(Dispose): 主要做的工作就是dispose 关闭数据库连接文件资源的释放等
卸载(Unload)销毁服务器控件的实例
页面生命周期的主要事件 PreInit:
检查IsPostBack 属性
动态设置Master Page
动态设置Theme
设置控件的默认值(UniqueId等)
重新创建动态控件(初始化控件)初始化控件的值
Init: 这个事件发生在所有的控件被初始化所有的皮肤设置被应用以后它用来读取或者初始化控件属性它能够用来注册一些aspx页面中没有指出的控件的事件
InitComplete: Use this event for processing tasks that require all initialization to be complete
PreLoad: 加载页面的ViewState和所有的控件然后处理所有的包含在Request实例中的postback数据
Load: 这个事件可能是大家最熟悉的了需要注意的是Page对象会递归的调用子控件的onload事件直到页面和所有的子控件被加载完成这个事件主要用来设置控件属性的值建立数据库连接(通常不这么做)
Control events: 这个就不多说了主要是处理控件的事件例如click这也就让我们明白了每次我们click一个Button的时候实际上是要先去执行load事件然后才执行click事件的一般我们用!IsPostBack来判断一下从而避免执行不必要的加载逻辑
LoadComplete: 页面所有的控件都被加载以后执行暂时没有想到用来干什么
PreRender: 在HTML被生成之前这是最后一个事件每一个页面中的控件都有PreRender的过程在这里对将要输出的HTML结果进行最后一次修改
SaveStateComplete: 在这个时间发生之前已经保存了所有控件和页面的任何对page或者控件的改动都不会产生左右暂时没想到用来干啥
Render: 它不是一个事件而是一个方法工作就是把HTML写回客户端浏览器
UnLoad: 页面中的每一个控件都会发生这件事在控件中使用这个事件来做清理工作例如关闭数据库连接等对与页面本身也是做清理工作例如关闭打开的文件和数据库连接或者结束日志或者其它指定的工作
需要说明的是每次Request都会创建一个全新的Page类的实例所以在页面中的自己定义的字段是不能在两次request中传递值的需要使用viewstate来存储
HttpHandler根据页面生命周期中事件的处理把结果发回IISIIS再把结果发回客户端浏览器 值得注意的是在这个过程中请求会再次通过HttpModule(注册一个EndRequest事件)
至此整个Request结束