14.3 ASP.NET網(wǎng)站的預(yù)編譯和編譯
ASP.NET在將整個站點提供給用戶之前,可以預(yù)編譯該站點。這為用戶提供了更快的響應(yīng)時間,提供了在向用戶顯示站點之前標(biāo)識編譯時bug的方法,提供了避免部署源代碼的方法,并提供了有效的將站點部署到成品服務(wù)器的方法??梢栽诰W(wǎng)站的當(dāng)前位置預(yù)編譯網(wǎng)站,也可以預(yù)編譯網(wǎng)站并將其部署到其他計算機(jī)。
在正式部署網(wǎng)站前,ASP.NET還要將代碼編譯成一個或多個程序集。
14.3.1 ASP.NET網(wǎng)站的預(yù)編譯
默認(rèn)情況下,在用戶首次請求資源(如網(wǎng)站的一個頁)時,將動態(tài)編譯ASP.NET網(wǎng)頁和代碼文件。第一次編譯頁和代碼文件之后,會緩存編譯后的資源,這樣將大大提高隨后對同一頁提出的請求的效率。
ASP.NET還可以預(yù)編譯整個站點,然后再提供給用戶使用。這樣做有很多好處:
— 可以加快用戶的響應(yīng)時間,因為頁和代碼文件在第一次被請求時無須編譯。這對于經(jīng)常更新的大型站點尤其有用。
— 可以在用戶看到站點之前識別編譯時bug。
— 可以創(chuàng)建站點的已編譯版本,并將該版本部署到成品服務(wù)器,而無須使用源代碼。
ASP.NET提供了兩個預(yù)編譯站點選項。
(1)預(yù)編譯現(xiàn)有站點。
如果希望提高現(xiàn)有站點的性能并對站點執(zhí)行錯誤檢查,那么此選項十分有用??梢酝ㄟ^預(yù)編譯網(wǎng)站來稍稍提高網(wǎng)站的性能。對于經(jīng)常更改和補充ASP.NET網(wǎng)頁及代碼文件的站點則更是如此。在這種內(nèi)容不固定的網(wǎng)站中,動態(tài)編譯新增頁和更改頁所需的額外時間會影響用戶對站點質(zhì)量的感受。在執(zhí)行就地預(yù)編譯時,將編譯所有的ASP.NET文件類型(HTML文件、圖形和其他非ASP.NET靜態(tài)文件將保持原狀)。預(yù)編譯過程的邏輯與ASP.NET進(jìn)行動態(tài)編譯時所用的邏輯相同,這說明了文件之間的依賴關(guān)系。在預(yù)編譯過程中,編譯器將為所有可執(zhí)行輸出創(chuàng)建程序集,并將程序集放在%SystemRoot%\Microsoft. NET\Framework\version\Temporary ASP.NET Files文件夾下的特殊文件夾中。隨后,ASP.NET將通過此文件夾中的程序集來完成頁請求。如果再次預(yù)編譯站點,那么將只編譯新文件或更改過的文件(或那些與新文件或更改過的文件具有依賴關(guān)系的文件)。編譯器的這一優(yōu)化,用戶即使是在細(xì)微的更新之后,也可以編譯站點。
(2)針對部署預(yù)編譯站點。
此選項將創(chuàng)建一個特殊的輸出,可以將該輸出部署到成品服務(wù)器。預(yù)編譯站點的另一個用處是生成可部署到成品服務(wù)器的站點的可執(zhí)行版本。針對部署進(jìn)行預(yù)編譯將以布局形式創(chuàng)建輸出,其中包含程序集、配置信息、有關(guān)站點文件夾的信息,以及靜態(tài)文件(如 HTML 文件和圖形)。
編譯站點之后,可以使用 Windows XCopy 命令、FTP、Windows 安裝等工具將布局部署到成品服務(wù)器。布局在部署完之后將作為站點運行,且 ASP.NET 將通過布局中的程序集來完成頁請求。
針對部署預(yù)編譯又可以按照以下兩種方式來針對部署進(jìn)行預(yù)編譯:僅針對部署進(jìn)行預(yù)編譯,或者針對部署和更新進(jìn)行預(yù)編譯。
— 僅針對部署進(jìn)行預(yù)編譯。
當(dāng)僅針對部署進(jìn)行預(yù)編譯時,編譯器實質(zhì)上將基于正常情況下在運行時編譯的所有ASP.NET源文件來生成程序集。其中包括頁中的程序代碼、.cs和.vb類文件,以及其他代碼文件和資源文件。編譯器將從輸出中移除所有源代碼和標(biāo)記。在生成的布局中,為每個.aspx文件生成編譯后的文件(擴(kuò)展名為.compiled),該文件包含指向該頁相應(yīng)程序集的指針。
要更改網(wǎng)站(包括頁的布局),必須更改原始文件,重新編譯站點并重新部署布局。唯一的例外是站點配置,可以更改成品服務(wù)器上的 Web.config 文件,而無須重新編譯站點。此選項不僅為頁提供了最大程度的保護(hù),還提供了最佳啟動性能。
— 針對部署和更新進(jìn)行預(yù)編譯。
當(dāng)針對部署和更新進(jìn)行預(yù)編譯時,編譯器將基于所有源代碼(單文件頁中的頁代碼除外)及正常情況下用來生成程序集的其他文件(如資源文件)來生成程序集。編譯器將.aspx文件轉(zhuǎn)換成使用編譯后的代碼隱藏模型的單個文件,并將它們復(fù)制到布局中。
使用此選項,可以在編譯站點中的ASP.NET網(wǎng)頁之后對它們進(jìn)行有限的更改。例如,可以更改控件的排列、頁的顏色、字體和其他外觀元素。還可以添加不需要事件處理程序或其他代碼的控件。
預(yù)編譯過程對ASP.NET Web應(yīng)用程序中各種類型的文件執(zhí)行操作。文件的處理方式各不相同,這取決于應(yīng)用程序預(yù)編譯只是用于部署還是用于部署和更新。表14-16描述了不同的文件類型,以及應(yīng)用程序預(yù)編譯只是用于部署時對這些文件類型所執(zhí)行的操作。
表14-16 部署時不同文件類型對應(yīng)的預(yù)編譯操作和輸出位置
文件類型 |
預(yù)編譯操作 |
輸出位置 |
.aspx、ascx、.master |
生成程序集和一個指向該程序集的.compiled文件。原始文件保留在原位置,作為完成請求的占位符 |
程序集和.compiled文件寫入Bin文件夾中。頁(去除內(nèi)容的.aspx文件)保留在其原始位置 |
.asmx、.ashx |
生成程序集。原始文件保留在原位置,作為完成請求的占位符 |
Bin文件夾 |
App_Code文件夾中的文件 |
生成一個或多個程序集(取決于Web.config設(shè)置) |
Bin文件夾 |
未包含在App_Code文件夾中的.cs或.vb文件 |
與依賴于這些文件的頁或資源一起編譯 |
Bin文件夾 |
Bin文件夾中的現(xiàn)有.dll文件 |
按原樣復(fù)制文件 |
Bin文件夾 |
資源(.resx)文件 |
對于App_LocalResources或App_GlobalResources文件夾中找到的.resx文件,生成一個或多個程序集以及一個區(qū)域性結(jié)構(gòu) |
Bin文件夾 |
App_Themes文件夾及子文件夾中的文件 |
在目標(biāo)位置生成程序集并生成指向這些程序集的.compiled文件 |
Bin文件夾 |
靜態(tài)文件(.htm、.html、圖形文件等) |
按原樣復(fù)制文件 |
與源中結(jié)構(gòu)相同 |
瀏覽器定義文件 |
按原樣復(fù)制文件 |
App_Browsers |
依賴項目 |
將依賴項目的輸出生成到程序集中 |
Bin文件夾 |
Web.config文件 |
按原樣復(fù)制文件 |
與源中結(jié)構(gòu)相同 |
Global.asax文件 |
編譯到程序集中 |
Bin文件夾 |
表14-17描述了不同的文件類型,以及應(yīng)用程序預(yù)編譯用于部署和更新時對這些文件類型所執(zhí)行的操作。
表14-17 部署和更新時不同文件類型對應(yīng)的預(yù)編譯操作和輸出位置
文件類型 |
預(yù)編譯操作 |
輸出位置 |
.aspx、ascx、.master |
對于具有代碼隱藏類文件的文件,生成程序集和一個指向該程序集的.compiled文件。將這些文件的單文件版本原封不動地復(fù)制到目標(biāo)位置 |
程序集和.compiled文件寫入Bin文件夾中 |
.asmx、.ashx |
按原樣復(fù)制文件,但不編譯 |
與源中結(jié)構(gòu)相同 |
App_Code文件夾中的文件 |
生成一個或多個程序集(取決于Web.config設(shè)置) |
Bin文件夾 |
未包含在App_Code文件夾中的.cs或.vb文件 |
與依賴于這些文件的頁或資源一起編譯 |
Bin文件夾 |
續(xù)表
文件類型 |
預(yù)編譯操作 |
輸出位置 |
Bin文件夾中的現(xiàn)有.dll文件 |
按原樣復(fù)制文件 |
Bin文件夾 |
資源(.resx)文件 |
對于App_GlobalResources文件夾中的.resx文件,生成一個或多個程序集,以及一個區(qū)域性結(jié)構(gòu)
對于App_LocalResources文件夾中的.resx文件,將它們按原樣復(fù)制到輸出位置的App_LocalResources文件夾中 |
程序集放置在Bin文件夾中 |
App_Themes文件夾及子文件夾中的文件 |
按原樣復(fù)制文件 |
與源中結(jié)構(gòu)相同 |
靜態(tài)文件(.htm、.html、圖形文件等) |
按原樣復(fù)制文件 |
與源中結(jié)構(gòu)相同 |
瀏覽器定義文件 |
按原樣復(fù)制文件 |
App_Browsers |
依賴項目 |
將依賴項目的輸出生成到程序集中 |
Bin文件夾 |
Web.config文件 |
文件被復(fù)制 |
與源中結(jié)構(gòu)相同 |
Global.asax文件 |
編譯到程序集中 |
Bin文件夾 |
在部署預(yù)編譯的網(wǎng)站之后,可以對站點中的文件進(jìn)行一定更改。表14-18描述了不同類型的更改所造成的影響。
表14-18 對文件進(jìn)行更改后對網(wǎng)站的影響
文件類型 |
允許的更改(僅部署) |
允許的更改(部署和更新) |
靜態(tài)文件(.htm、.html、圖形文件等) |
可以更改、移除或添加靜態(tài)文件。如果ASP.NET網(wǎng)頁引用的頁或頁元素已被更改或移除,可能會發(fā)生錯誤 |
可以更改、移除或添加靜態(tài)文件。如果ASP.NET網(wǎng)頁引用的頁或頁元素已被更改或移除,可能會發(fā)生錯誤 |
.aspx文件 |
不允許更改現(xiàn)有的頁。不允許添加新的.aspx文件 |
可以更改 .aspx 文件的布局和添加不需要代碼的元素,例如,HTML元素和不帶有事件處理程序的ASP.NET服務(wù)器控件。還可以添加新的.aspx文件,該文件通常在首次請求時進(jìn)行編譯 |
.skin文件 |
忽略更改和新增的.skin文件 |
允許更改和新增的.skin文件 |
Web.config文件 |
允許更改,這些更改將影響.aspx文件的編譯。忽略調(diào)試或批處理編譯選項。
不允許更改配置文件屬性或提供程序元素 |
如果所做的更改不會影響站點或頁的編譯(包括編譯器設(shè)置、信任級別和全球化),則允許進(jìn)行更改。忽略影響編譯或使已編譯頁中的行為發(fā)生變化的更改,否則在一些實例中可能會生成錯誤。允許其他更改 |
瀏覽器定義 |
允許更改和新增文件 |
允許更改和新增文件 |
從資源(.resx)文件編譯的程序集 |
可以為全局和局部資源添加新的資源程序集文件 |
可以為全局和局部資源添加新的資源程序集文件 |
對于ASP.NET Web應(yīng)用程序中的可執(zhí)行文件,編譯器程序集,以及文件擴(kuò)展名為.compiled的文件。程序集名稱由編譯器生成。.compiled文件不包含可執(zhí)行代碼。它只包含ASP.NET查找相應(yīng)的程序集所需的信息。
在部署預(yù)編譯的應(yīng)用程序之后,ASP.NET使用Bin文件夾中的程序集來處理請求。預(yù)編譯輸出包含.aspx或.asmx文件作為頁占位符。占位符文件不包含任何代碼。使用它們只是為了提供一種針對特定頁請求調(diào)用ASP.NET的方式,以便可以設(shè)置文件權(quán)限來限制對頁的訪問。
14.3.2 ASP.NET網(wǎng)站的編譯
為了使用應(yīng)用程序代碼為用戶提出的請求提供服務(wù),ASP.NET必須首先將代碼編譯成一個或多個程序集。程序集是文件擴(kuò)展名為.dll的文件。可以采用多種不同的語言來編寫ASP.NET代碼,如Visual Basic、C#、J#和其他語言。當(dāng)在編譯代碼時,會將代碼翻譯成一種名為Microsoft中間語言(MSIL)的與語言和CPU無關(guān)的表示形式。運行時,MSIL將運行在.NET Framework的上下文中,.NET Framework會將MSIL翻譯成CPU特定的指令,以便計算機(jī)上的處理器運行應(yīng)用程序。
編譯應(yīng)用程序代碼具有許多好處,其中包括:
— 性能。編譯后的代碼的執(zhí)行速度要比諸如ECMAScript或VBScript的腳本語言快得多,因為它是一種更接近于機(jī)器代碼的表示形式,并且不需要進(jìn)行其他分析。
— 安全性。編譯后的代碼要比非編譯的源代碼更難進(jìn)行反向工程處理,因為編譯后的代碼缺乏高級別語言所具有的可讀性和抽象性。此外,模糊處理工具增強了編譯后的代碼對抗反向工程處理的能力。
— 穩(wěn)定性。在編譯時檢查代碼是否有語法錯誤、類型安全問題,以及其他問題。通過在生成時捕獲這些錯誤,可以消除代碼中的許多錯誤。
— 互操作性。由于MSIL代碼支持任何.NET語言,因此可以在代碼中使用最初用其他語言編寫的程序集。例如,如果正在用C#編寫ASP.NET網(wǎng)頁,可以添加對使用Visual Basic編寫的.dll文件的引用。
ASP.NET編譯結(jié)構(gòu)包括許多功能,其中包括:
— 多語言支持;
— 自動編譯;
— 靈活部署;
— 可擴(kuò)展生成系統(tǒng)。
(1)多語言支持。
在ASP.NET 2.0中,可以在同一個應(yīng)用程序中使用不同的語言(如Visual Basic和C#),這是因為ASP.NET將為每一種語言分別創(chuàng)建一個程序集。對于存儲在App_Code文件夾中的代碼,可以為每種語言指定一個子文件夾。
(2)自動編譯。
當(dāng)用戶首次請求網(wǎng)站的資源時,ASP.NET將自動編譯應(yīng)用程序代碼和任何依賴資源。通常,ASP.NET為每個應(yīng)用程序目錄(如App_Code)創(chuàng)建一個程序集,并為主目錄創(chuàng)建一個程序集(如果一個目錄中的文件是用不同編程語言編寫的,將為每種語言分別創(chuàng)建程序集),可以在Web.config文件的Compilation節(jié)指定將哪些目錄編譯成單個程序集。
(3)靈活部署。
因為ASP.NET在首次用戶請求時編譯網(wǎng)站,所以只需要將應(yīng)用程序源代碼復(fù)制到成品Web服務(wù)器上即可。不過,ASP.NET還提供了預(yù)編譯選項,通過這些選項,可以在部署網(wǎng)站之前先進(jìn)行編譯,或者在部署網(wǎng)站之后、用戶請求該網(wǎng)站之前進(jìn)行編譯。預(yù)編譯有若干優(yōu)點。由于ASP.NET編譯網(wǎng)站時不存在延遲時間,因而預(yù)編譯可以改進(jìn)首次請求時網(wǎng)站的性能。預(yù)編譯還能幫用戶找到不然只有當(dāng)用戶請求頁時才能找到的錯誤。最后,如果在部署網(wǎng)站之前預(yù)編譯網(wǎng)站,則可以部署程序集,而不必部署源代碼。
可以使用ASP.NET編譯器工具(ASPNET_Compiler.exe)預(yù)編譯網(wǎng)站。該工具提供下列預(yù)編譯選項:
— 就地編譯。此選項執(zhí)行與動態(tài)編譯期間發(fā)生的相同編譯過程。可以使用此選項編譯已經(jīng)部署到成品服務(wù)器的網(wǎng)站。
— 不可更新完全預(yù)編譯??梢允褂么诉x項來編譯應(yīng)用程序,然后將編譯后的輸出復(fù)制到成品服務(wù)器。所有應(yīng)用程序代碼、標(biāo)記和用戶界面代碼都將編譯為程序集。占位符文件(如.aspx頁)仍存在,因此可以執(zhí)行某些文件特定的任務(wù)(如設(shè)置權(quán)限),但文件中不包含可更新的代碼。為了更新任何頁或任何代碼,必須再次預(yù)編譯并再次部署網(wǎng)站。
— 可更新的預(yù)編譯。該選項類似于“不可更新完全預(yù)編譯”,不同之處在于用戶界面元素(如.aspx頁和.ascx控件)保留其所有標(biāo)記、用戶界面代碼和內(nèi)聯(lián)代碼(如果有的話)??梢栽诓渴鹬蟾挛募械拇a;ASP.NET將檢測對文件所做的這些更改并重新進(jìn)行編譯。請注意,預(yù)編譯期間代碼隱藏文件(.vb或.cs文件)中的代碼都將內(nèi)置到程序集中,因此如果不重新執(zhí)行預(yù)編譯和部署步驟,將無法更改這些代碼。
(4)可擴(kuò)展生成系統(tǒng)。
ASP.NET使用BuildProvider類來生成項,如.aspx頁、.ascx文件和全局資源??梢酝ㄟ^創(chuàng)建從BuildProvider類繼承的類來擴(kuò)展和自定義ASP.NET生成系統(tǒng),以編譯自定義資源。例如,可以添加新的文件類型,然后編寫生成該特定類型的BuildProvider。