web 应用程序文件对于每个web 应用程序来说是可选唯一的,用来处理asp.net应用程序一级的事件,并将被预编译为一个system.web.httpapplication类的子类; web 页面文件是普通的asp.net页面,处理特定页面的事件,将被预编译为一个system.web.ui.page类的子类; 用户自定义控件文件是特殊的asp.net页面,处理控件自身的事件,将被预编译为一个system.web.ui.usercontrol类的子类; web 服务程序文件则是与前三者不太相同的一种特殊页面文件,暂时不予讨论。
然后,前三种asp.net文件的编译时机也不完全相同。web 应用程序文件在此 web 应用程序文件第一次被使用时自动编译;web 页面文件在此web页面第一次被使用时自动编译,实际上是调用 httpruntime.processrequest 函数触发预编译;用户自定义控件文件则在其第一次被 web 页面使用的时候自动编译,实际上是调用 page.loadcontrol 函数触发预编译。
httpruntime.processrequestinternal函数中,涉及到文件预编译的有两部分:一是获取当前 web 应用程序实例时,会根据情况自动判断是否预编译web 应用程序文件;二是在完成实际页面请求时,会在第一次使用某个页面时触发预编译行为。
首先来看看对 web 应用程序文件的处理。
httpruntime.processrequestinternal函数中调用了httpapplicationfactory.getapplicationinstance函数获取当前 web 应用程序实例。system.web.httpapplicationfactory是一个内部类,用以实现对多个web应用程序实例的管理和缓存。getapplicationinstance函数返回的是一个ihttphandler接口,提供ihttphandler.processrequest函数用于其后对web页面文件的处理。伪代码如下:
至此一个 web 应用程序实例就被完整构造出来,再经过initinternal函数的初始化,就可以开始实际页面处理工作了。而httpapplicationfactory实例的_theapplicationtype类型,则是结果预编译后的global.asax类。实际的预编译工作在httpapplicationfactory.init函数中完成,伪代码如下:
public control loadcontrol(string virtualpath) { virtualpath = urlpath.combine(base.templatesourcedirectory, virtualpath); type type = usercontrolparser.getcompiledusercontroltype(virtualpath, null, base.context); return this.loadcontrol(type1); }