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); }