詳解ASP.NET動態(tài)編譯
1.動態(tài)編譯的過程
我們先來介紹在ASP.NET動態(tài)編譯下的大體的執(zhí)行流程:當ASP.NET收到一個基于某個page的request的時候,先判斷該Page和相關(guān)的Source code是否編譯過,如果沒有就將其編譯,如果已經(jīng)編譯,就是用已經(jīng)Load的Assembly直接生成Page對象。
在這里有下面幾點需要注意:
1). ASP.NET動態(tài)編譯是按需編譯的,ASP.NET只會編譯和當前Request相關(guān)的aspx和code。
2). ASP.NET動態(tài)編譯是基于某個目錄的,也就是說ASP.NET會把被請求的page所在的目錄的所有需要編譯的文件進行編譯,并生成一個Assembly。
3). 除了編譯生成的Assembly外,動態(tài)編譯還會生成一系列的輔助文件。
4). 對相關(guān)文件的修改,會導(dǎo)致重新編譯,但是修改對當前的Request不起作用。也就是說如果你對某個aspx進行修改,那么對于修改后抵達的Request,會導(dǎo)致重新編譯,但是對于之前的Request使用的依然是原來編譯好的Assembly。
5). 編譯生成的文件被放在一個臨時目錄中,這個目錄的地址為Windows Directory\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files。其具體的目錄結(jié)構(gòu)如下圖所示:
在Temporary ASP.NET Files下的Artech.ASPNETDeployment是IIS中Virtual Directory的名稱,以下兩級目錄的名稱由Hash value構(gòu)成,所以編譯生成的文件就保存在c6f16246目錄下。這個目錄你可以通過HttpRuntime.CodegenDir獲得。
Directory\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files只是一個默認的臨時目錄,你可以在web config中的compilation section中設(shè)置你需要的臨時目錄。
- <compilation tempDirectory="d:\MyTempFiles" />
2.Sample
現(xiàn)在我用一個Sample來一探ASP.NET是如何進行動態(tài)編譯的。
在這個Sample中,我建立了一個Website,在根目錄下創(chuàng)建了兩個Page:Default和Default2。
在兩個子目錄Part I和Part II下分別創(chuàng)建了兩個Web page:Page1和Page2。在App_Code目錄中創(chuàng)建了一個Utility的static class。下面是它的定義:
- publicstaticclassUtility
- {
- publicstaticstringReflectAllAssmebly()
- {
- StringBuilderrefllectionResult=newStringBuilder();
- foreach(AssemblyassemblyinAppDomain.CurrentDomain.GetAssemblies())
- {
- if(!assembly.FullName.Contains("App_Web"))
- {
- continue;
- }
- refllectionResult.Append(assembly.FullName+"<br/>");
- Type[]allType=assembly.GetTypes();
- foreach(TypetypeInfoinallType)
- {
- refllectionResult.Append(" "+typeInfo.Name+"<br/>");
- }
- }
- returnrefllectionResult.ToString();
- }
- }
內(nèi)容很簡單,對當前加載的所有相關(guān)的Assembly(這些Assembly的Fullname以App_Web打頭)進行Reflection,列出所有的Type。這個ReflectAllAssmebly將在5個Web page(Default Page和兩隊Page1&Page2)的Page_Load事件中被調(diào)用。
- protected void Page_Load(object sender, EventArgs e)
- {
- this.Response.Write(Utility.ReflectAllAssmebly());
- }
Default是列出所有4Page對應(yīng)的Link以便我們訪問它們,在我們再進行編譯的情況下在IE中輸入對應(yīng)的URL來訪問Default Page。(其他Page的Html中不具有真正的內(nèi)容,是一個空的page.)
通過上面的顯示,我們可以看到現(xiàn)在有一個Assembly:App_Web_wh7-uda5。該Asssembly定一個的Type有5個, _Default和 default_aspx分別對應(yīng)Default Page,而Default2和 default2_aspxDefault2 Page的。FastObjectFactory_app_web_wh7_uda5是很重要的Type,我將會在后面對其進行深入介紹。正如我們在上面說過的,動態(tài)編譯是按需編譯,現(xiàn)在我們對Default Page進行訪問,由于這次對該Website的***次訪問,所有需要的Source Code,包括aspx,code behind都要進行編譯。在這個Sample中,雖然我們并沒有訪問Default2 page,但是我們說過,ASP.NET動態(tài)編譯是基于目錄的,由于Default Page和Default2 Page都直接置于根目錄下,所以ASP.NET會把根目錄下的所有文件編譯到一個Assembly中。由于Page1和Page2位于子目錄Part I和Part II之下,所以不會參與編譯。除非我們下載對它進行Request。
我們現(xiàn)在來訪問Part I下的Page1和Page2看看會有什么結(jié)果。我們會發(fā)現(xiàn),兩次Request獲得的輸出是一樣的:
通過上面的輸出我們發(fā)現(xiàn),當前AppDomain中被加載的Assembly多了一個:App_Web_n1mhegpg。我們可以通過定義在該Assembly中的Type的命名可以猜出該Assembly是對Part I 目錄進行編譯產(chǎn)生的。Page1和Page2的編譯后的Type name變成了part_i_page1_aspx& Page1和part_i_page2_aspx& Page2。此外我們看到,該Assembly中依然有一個FastObjectFactory的Type:FastObjectFactory_app_web_n1mhegpg。在這里我需要特別指出的是,名稱的后綴都是通過 Hash算法得到的。
有了上面的理論和實驗結(jié)果,我想這個時候,你肯定已經(jīng)想到,如果我現(xiàn)在對Part II的Page1和Page2進行訪問,輸出結(jié)果會是什么樣子了。
如果這個時候,你查看臨時目錄(Directory\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files)中該Website對應(yīng)的子目錄,已將會看到生成了一些列的文件。
【編輯推薦】