ASP.NET 2.0 的內部變化
發表于:2007-06-30來源:作者:點擊數:
標簽:
Jayesh Patel、Bryan Acker 和 Robert McGovern Infusion Development 適用范圍: Microsoft ASP.NET 2.0 摘要:盡管 ASP.NET 2.0 與 ASP.NET 1.1 完全向后兼容,但還是為 ASP.NET 帶來了大量的內部變化,包括代碼模型、編譯、頁面生命周期等的變化。本文將概
Jayesh Patel、Bryan Acker 和 Robert McGovern
Infusion Development
適用范圍:
Microsoft ASP.NET 2.0
摘要:盡管 ASP.NET 2.0 與 ASP.NET 1.1 完全向后兼容,但還是為 ASP.NET 帶來了大量的內部變化,包括代碼模型、編譯、頁面生命周期等的變化。本文將概括介紹這些變化。
本頁內容
引言
代碼模型
編譯
完全運行時編譯(代碼目錄)
頁面生命周期
可擴展性
高級緩存技術
性能
結論
引言
對于專業的 ASP.NET 開發人員來說,與 ASP.NET 2.0 有關的重要問題是內部發生了哪些變化。盡管新功能很有趣而且學起來很有意思,但對于真正想掌握這一技術的開發人員來說,ASP.NET 核心結構發生的變化才是最吸引他們的地方。在本白皮書中,我們將介紹自版本 1.x 以來,ASP.NET 2.0 內部結構發生了什么樣的變化。
本白皮書介紹的主題對那些關注性能的開發人員以及尋求如何優化應用程序的技術設計師非常有用。具體來說,我們將介紹有關代碼模型、編譯、頁面生命周期、可擴展性、性能和緩存的主要問題。
本文中的許多示例要求您對 ASP.NET、Visual Basic .NET 和/或 C# 語法有相當程度的了解。本文還在適當的地方提供了參考文檔,就某些特定的主題展開深入的討論。
返回頁首
代碼模型
也許 ASP.NET 2.0 內部工作方式最明顯的變化是 ASP.NET Web 頁面的創建方式的變化。本節將介紹內含代碼模型發生的變化以及這些變化對 ASP.NET 開發的影響。
ASP.NET 1.x 中的代碼模型
在 ASP.NET 1.x 中,供開發人員開發 Web 窗體的主要選擇有兩個。首先,開發人員可以參照傳統的 ASP 模型并直接在 ASPX 頁面中編寫代碼。此過程稱為“內嵌代碼”,它非常適用于簡單的命令。然而,對于更復雜的代碼而言,編寫內嵌代碼將為讀取混合了表示 (HTML) 和功能(代碼)的 Web 頁面帶來困難。在 ASP.NET 中,為了幫助解決這個問題,已更改了默認的編碼方法。您可以在單獨的、只包含代碼的文件(稱為“內含代碼”文件)中編寫業務邏輯和事件處理代碼。內含代碼模型將只包含代碼的文件與包含表示標記的 ASPX 文件鏈接起來。通過將代碼與表示相分離,開發小組可以讓設計人員處理演示文件,而讓開發人員處理代碼文件,從而提高開發小組的工作效率。
圖1:ASP.NET 1.x 代碼模型
內含代碼模型面臨的主要困難在于如何將內含代碼文件與 ASPX 頁面保持同步。盡管從編程意義上來講 ASPX 頁面是從內含代碼文件繼承而來的,但實際上這兩個文件是通過更復雜的關系聯系在一起的。
有關 ASP.NET 1.x 中的內含代碼模型的詳細信息,請參見 MSDN Library 文章 Web Forms Code Model(英文)。
繼承的復雜性
ASP.NET 的設計模式就是讓開發人員使用 Microsoft Visual Studio .NET 將控件拖放到 ASPX 頁面中。Visual Studio 然后將在內含代碼文件中自動生成適當的支持代碼。如果控件已被添加到 ASPX 頁面中,則必須在內含代碼文件中添加新代碼。換句話說,盡管 ASPX 頁面繼承自內含代碼文件,但實際上 ASPX 頁面推動了內含代碼文件的設計。
編譯的復雜性
第二個同步問題就是如何編譯文件。所有的內含代碼文件以及所有的支持類都被編譯到一個程序集中,并存儲在 Web 應用程序的 /bin 目錄中。應用程序的編譯工作是在部署工作之前進行的。而另一方面,ASPX 頁面也是在第一次被請求時在運行時編譯的。ASP.NET 運行庫實際上將 ASPX 頁面編譯到該頁面自己的臨時程序集中。
此過程的問題在于,無需更新內含代碼程序集即可更改 ASPX 頁面。也就是說,開發人員可以在部署后更改某個屬性或更改 ASPX 頁面上某個控件的類型,而無需更新內含代碼文件,也不用重新編譯應用程序的程序集。出現這種情況時,由于內含代碼文件與所關聯的 ASPX 頁面不匹配,應用程序可能會遇到意外的錯誤。
ASP.NET 2.0 中的代碼模型
ASP.NET 2.0 繼續提供內嵌代碼和內含代碼模型。從內嵌代碼模型的角度來說,除了 Microsoft Visual Studio 2005 支持單文件開發的方式有所變化外,基本上沒做什么改動。有關 Visual Studio 2005 中的變化及其如何處理內嵌代碼的詳細信息,請參閱這篇文章(英文)。
ASP.NET 2.0 通過改變內含代碼文件的本質解決了內含代碼模型的繼承和編譯問題。在 ASP.NET 2.0 中,內含代碼文件不再是 System.Web.UI.Page 類的完整實現。相反,內含代碼文件是一個新的構造函數,稱為“局部類”。局部類包含所有用戶定義的代碼,但是不包含 Visual Studio .NET 在 ASP.NET 1.x 中自動生成的任何管線和連接代碼。請求包含新的內含代碼文件的 ASPX 頁面時,ASP.NET 2.0 運行庫實際上將把 ASPX 頁面和局部類合并成一個類,而不是兩個單獨的類。
圖 2:ASP.NET 2.0 中的內含代碼模型
局部類使用新的關鍵字(在 Visual Basic 中為 Expands,在 C# 中為 Partial)指示在運行時將該類中的代碼與另一個類中的代碼相合并。類似地,ASPX 頁面使用新的指令(稱為 compilewith)指示該頁面與內含代碼文件之間的關聯。
比較內含代碼文件
如果您熟悉傳統的 ASP.NET 1.x 內含代碼文件,您應該知道 Visual Studio 將插入自動生成的控件聲明和初始化代碼。這種自動生成的代碼是內含代碼文件與 ASPX 文件之間雙向同步的直接結果。帶有標簽的典型 ASPX 頁面具有一個對應的內含代碼文件,該文件由許多自動生成的文本行構成。
列表 1:ASP.NET 1.x 中的內含代碼文件
namespace WebApplication1
{
public class WebForm1 :System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label Label1;
private void Page_Load(object sender,
System.EventArgs e) { }
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
自動生成的代碼不僅定義標簽(以粗體顯示的行),還聲明新的事件(頁面加載)并自動將該事件綁定到自動生成的方法包裝程序 (Page_Load())。
比較而言,同一個 ASP.NET 頁面在 ASP.NET 2.0 中生成的內含代碼文件更簡潔。
列表 2:ASP.NET 2.0.x 中的內含代碼文件
namespace ASP {
public partial class Webform1_aspx
{
}
}
開發人員可以自動訪問 Label1,并根據需要添加事件。例如,可以添加 Page_Load 事件以初始化標簽。
列表 3:在新的內含代碼文件中添加事件
namespace ASP {
public partial class Webform1_aspx
{
void Page_Load(object sender, EventArgs e)
{
Label1.Text = "Hello ASP.NET 2.0";
}
}
}
事件語法可通過 Visual Studio .NET 生成。生成的內含代碼文件更短,而且不包含任何自動生成的代碼。ASP.NET 運行庫會自動將內含代碼文件中的事件綁定到 ASPX 頁面上的控件。換句話說,ASP.NET 運行庫現在可以自動執行代碼生成,而這原本是由 Visual Studio 執行的。
繼承的復雜性
新的內含代碼模型大大降低了繼承的復雜性。由于 ASPX 頁面不是直接繼承自內含代碼文件,因此內含代碼文件不再需要定義并支持 ASPX 頁面上定義的所有控件。類似地,內含代碼文件可以自動訪問 ASPX 頁面上的任何控件,而無需聲明代碼(聲明代碼在 ASP.NET 1.x 中是必需的)。這一切之所以能夠實現,是因為 ASP.NET 運行庫可以將所需的聲明代碼和事件綁定代碼自動插入到最終編譯的文件中。因為這些工作由運行庫來完成,所以代碼開發人員和 Web 開發人員都無需再擔心這個問題。
在設計期間,鏈接將由 Visual Studio 2005 來維護。Visual Studio 環境將利用 ASP.NET 運行庫編譯段來確保代碼開發人員和 Web 開發人員可以同步工作。
編譯的復雜性
由于新的內含代碼文件與 ASPX 頁面鏈接在一起并在運行時被編譯到一個完整的類中,因此編譯的復雜性不復存在。也就是說,內含代碼文件將自動與 ASPX 頁面保持同步。即使新的編譯模型也可能包含未同步的代碼,但由于產生的異常非常清楚,因此可以快速找到問題的根源。
返回頁首
編譯
自從在 ASP.NET 1.x 中引入頁面模型后,ASP.NET Web 頁面的編譯過程一直被分為兩個階段。首先,將內含代碼文件和其他支持類編譯到一個程序集中,然后在運行時編譯各個 ASPX 文件。盡管此模型有很多優點,但它還有幾個缺點。ASP.NET 2.0 為基本模型提供了幾種替代方案,從而擴大了編譯的選擇范圍,您可以根據特定需要進行選擇。
ASP.NET 1.x 中的編譯
ASP.NET 1.x 中的主要編譯模型生成了一個應用程序程序集(包含所有已編譯的內含代碼文件和其他源代碼)和一個臨時程序集(專門為請求的每個 ASPX 頁面而創建)。在某些情況下,編譯器優化(例如批處理)可能會導致臨時 ASPX 頁面被編譯到同一個程序集中。在任何情況下,都會將每個 ASPX 頁面編譯到一個臨時程序集中,因此該頁面可以加載到 ASP.NET 運行庫中。
圖 3:ASP.NET 1.x 中的編譯
盡管此模型有很多優點,但它還有兩個主要的缺點。首先,必須以用戶可以閱讀的格式將 ASPX 頁面部署到 Web 站點上。如果開發人員使用“內嵌代碼”模型,那么還需要將某些甚至所有業務邏輯部署到生產
服務器上。盡管 IIS 和 ASP.NET 被配置為不顯示原始 ASPX 頁面,但是狡猾的攻擊者仍然可以通過對 Web 服務器開放的任何入口訪問這些文件。其次,任何人首次請求 Web 頁面時,響應都會比正常情況下慢,因為 ASP.NET 運行庫必須編譯 ASPX 頁面。
在這一過程中,開發人員唯一能夠控制的就是是否對 ASPX 頁面進行批編譯。在 ASP.NET 1.x 中,您可以通過修改 web.config 文件中的 <compilation> 標記來配置批編譯。
列表 4:配置批編譯
<compilation
batch="true|false"
batchTimeout="number of seconds"
maxBatchSize="maximum number of pages per batched compilation"
maxBatchGeneratedFileSize="maximum combined size (in KB) of the
generated source file per batched compilation"
</compilation>
首次請求 Web 頁面時,批編譯將通過延長啟動時間來縮短加載時間。批編譯的另一個優點是將所有的 ASPX 文件編譯到一個臨時程序集中,而不是將每個頁面編譯到一個臨時程序集中。
ASP.NET 2.0 中的編譯
ASP.NET 2.0 為 Web 應用程序提供了四種不同的編譯模型:
• 普通 (ASP.NET 1.x) - 在普通的 ASP.NET Web 應用程序中,內含代碼文件被編譯到一個程序集中并存儲在 /bin 目錄中。Web 頁面 (ASPX) 按需進行編譯。此模型適用于大多數 Web 站點。但是,編譯過程將導致第一次請求 ASP.NET 頁面時的響應速度比后續請求慢。ASP.NET 2.0 繼續支持這種編譯模型。
• 批編譯 - 在 ASP.NET 2.0 中,您可以使用一個 URL 請求對任何應用程序進行批編譯。就像在 ASP.NET 1.x 中一樣,批編譯消除了首次請求頁面時的延遲,但延長了啟動時間。此外,批編譯仍然要求在部署之前編譯內含代碼文件。
• 部署預編譯 - 這是 ASP.NET 2.0 提供的一項新功能,允許在部署之前完整地編譯項目。在完整編譯中,根據應用程序的大小和編譯設置,可以將所有的內含代碼文件、ASPX 頁面、HTML、圖形資源和其他后端代碼編譯到一個或多個可執行的程序集中。這些程序集包含 Web 站點的所有已編譯代碼,并原封不動地復制了資源文件和配置文件。這種編譯方法提供了最好的性能和
安全性,但代價是您無法在部署后修改 Web 站點。如果您正在部署高度可見或高度安全的 Web 站點,那么此選項是最終部署的最佳選擇。但是,如果您正在構建在本地 Intranet 上運行的小站點,而且站點更改頻繁,那么完整的預編譯可能是多余的。
• 完整的運行時編譯 - 與部署預編譯相反的另一個極端情況是,ASP.NET 2.0 提供在運行時編譯整個應用程序的新機制。也就是說,您可以將未編譯的內含代碼文件和其他關聯的代碼放入新的代碼目錄中,在運行時根據這些文件生成程序集并讓 ASP.NET 2.0 創建并維護對這些程序集的引用。此選項為更改 Web 站點的內容提供了最大的靈活性,但代價是將未編譯的代碼存儲在服務器上。
您可以根據實際的情況和需要選擇最佳的編譯選項,但編譯模型仍然是靈活的。即使您選擇使用代碼目錄來存儲內含代碼文件,也仍然可以使用完整編譯這種方法來部署應用程序。
批編譯
web.config 批編譯設置在 ASP.NET 2.0 中仍然有效。批編譯的優點在于,頁面可以立即顯示給第一個用戶,并且可以在批編譯過程中檢測到 ASPX 頁面中的任何錯誤。但是,批編譯確實會延長應用程序的啟動時間,而且必須內置在 web.config 文件中。
部署預編譯
部署預編譯允許您創建一個或多個程序集,作為 Web 站點的可執行版本。生成的程序集包含 Web 站點的已編譯代碼。HTML 頁面、資源、配置文件和 ASPX 頁面將被分別復制。
部署預編譯需要使用 aspnet_compiler.exe 命令行實用程序,此實用程序將創建目標部署目錄,其中包含用于存儲程序集的 /bin 目錄以及各種 ASPX 頁面的 Stub 文件。還可以使用此實用程序執行在位預編譯,與調用“魔術頁面”的行為類似。Stub 文件使用 ASPX 頁面的名稱,但包含調用已編譯程序集的簡單代碼。換句話說,ASPX 頁面是簡單的空殼,而不是功能完善的頁面。
通過在部署之前預編譯 Web 站點,安全性將大大提高,因為如果不對程序集進行反編譯,將無法訪問任何代碼。為了增強保護,您可以打亂生成的程序集,使您的 Web 應用程序更安全。部署預編譯的主要缺點在于您必須在部署之前完成這些操作,而且不能在部署后更改 Web 站點。如果要進行更改,必須重新編譯 Web 站點并重新部署。
對于大多數主要的 Web 應用程序而言,部署預編譯選項是實現部署的首選機制,因為它可以減少在 Web 服務器上部署的原始代碼數量,并能提供最高的安全性??梢詫⒃黾拥倪M程內置在通常的開發/
測試/部署周期中,而不會嚴重降低工作效率。
返回頁首
完全運行時編譯(代碼目錄)
在上述三種編譯方法中,您必須在部署之前編譯所有的代碼文件(內含代碼和支持類)。ASP.NET 2.0 中提供了代碼目錄。
代碼目錄是一個特殊的目錄,用于存放未編譯的類。在運行時,ASP.NET 運行庫會將此目錄中的內容編譯到一個程序集中,該程序集將由應用程序中的 ASPX 頁面自動引用。換句話說,使用代碼目錄,就無需為支持代碼創建和引用單獨的程序集。代碼目錄的優點在于,您無需完整地編譯項目即可部署,從而降低了不匹配的可能性。但缺點是,您可能需要將未編譯的代碼存儲在服務器上。
此選項特別適用于不需要大量支持代碼(不管是以內含代碼文件還是外部對象的格式)的 ASP.NET 應用程序。對于簡單的應用程序而言,快速部署和測試系統的能力要比更穩健的編譯方法更具優勢。
返回頁首
頁面生命周期
ASP.NET 2.0 在 ASP.NET 頁面的生命周期方面有兩個主要的變化。首先,ASP.NET 2.0 提供了新的事件以支持新功能,這些功能包括母版頁、個性化和集成的移動設備支持。其次,ASP.NET 2.0 引入了跨頁發送 Web 窗體的技術。
新事件
與 ASP.NET 1.x 相比,ASP.NET 2.0 提供了更精確的頁面生命周期方法堆棧。這些新增的方法為 Web 開發人員提供了更高級別的控制??梢酝ㄟ^任何 ASP.NET 頁面上的“Page”對象訪問這些事件。
表 1 顯示了全面的方法列表?!胺椒ā绷酗@示了實際的事件方法名稱,“活動”列指示事件是始終處于活動狀態還是僅在 PostBack 操作期間處于活動狀態。例如,可以使用新方法 TestDeviceFilter 來確定哪個設備篩選器可用,并使用此信息決定如何顯示頁面。換句話說,新方法 LoadControlState 僅在回發期間調用??梢蕴娲朔椒ǎㄅc SaveControlState 結合使用),以創建用于在回發期間保存和恢復控件狀態的替換序列化方案。
表 1:頁面生命周期方法
方法 活動
Constructor
始終
Construct
始終
TestDeviceFilter
始終
AddParsedSubObject
始終
DeterminePostBackMode
始終
OnPreInit
始終
LoadPersonalizationData
始終
InitializeThemes
始終
OnInit
始終
ApplyControlSkin
始終
ApplyPersonalization
始終
OnInitComplete
始終
LoadPageStateFromPersistenceMedium
PostBack
LoadControlState
PostBack
LoadViewState
PostBack
ProcessPostData1
PostBack
OnPreLoad
始終
OnLoad
始終
ProcessPostData2
PostBack
RaiseChangedEvents
PostBack
RaisePostBackEvent
PostBack
OnLoadComplete
始終
OnPreRender
始終
OnPreRenderComplete
始終
SavePersonalizationData
始終
SaveControlState
始終
SaveViewState
始終
SavePageStateToPersistenceMedium
始終
Render
始終
OnUnload
始終
通過查看頁面生命周期的低級別詳細信息,我們可以發現在何處能夠自然地實現 ASP.NET 2.0 中的許多功能,例如主題和個性化。例如,可以在 IntializeThemes 事件中處理一個主題,在 LoadPersonalizationData 中加載個性化數據,并在以后應用于 ApplyPersonalization 方法。請注意,對于決定 Web 應用程序的最終外觀的 UI 元素而言,方法的順序極其重要。
跨頁發送
頁面生命周期的其他主要變化包括事件和 Web 窗體的回發。在 ASP.NET 1.x 中,Web 窗體是自動回發給其宿主頁面的。也就是說,當用戶提交窗體時,窗體數據將始終被提交回包含原始窗體的頁面。這種設計可以很容易地存儲控件狀態,但限制了開發人員執行更復雜操作的能力。
在 ASP.NET 2.0 中,Web 窗體控件有一個新屬性,使開發人員可以決定執行提交操作時將窗體數據發送到何處。大多數情況下都需要使用回發機制,因此該機制仍然是默認設置。但是,如果開發人員希望將數據發送到不同的窗體,現在這是可以實現的。
圖 4:回發和跨頁發送
例如,您可以創建一個多頁面向導,其中包含幾個不同的窗體。每個窗體按順序提交給下一個頁面,直到用戶到達可以執行最終驗證的摘要頁面??梢栽诋斍吧舷挛闹型ㄟ^ PreviousPage 對象訪問上一個頁面上的數據。PreviousPage 對象用于存儲上一個頁面上經驗證、可供在當前頁面上使用的數據。正是因為有了這個對象,跨頁發送才不會犧牲控件的持久性。如果用戶需要按順序備份一個窗體,可以立即訪問這些頁面數據,而不必重新輸入所有數據。
返回頁首
可擴展性
ASP.NET 最初被設計成一個開放式框架。也就是說,構成 ASP.NET 的許多模塊和組件都可以擴展、修改或替換以滿足您的特定需要。在 ASP.NET 2.0 中,通過新的 HTTPHandlers 和 HTTPModules(現在是框架的標準組成部分)清楚地說明了框架的可擴展本質。
請求管道
在 ASP.NET 中,請求通過 Internet 服務器應用程序編程接口 (ISAPI) 篩選器從 Web 服務器傳出,并傳遞給實際的 ASP.NET 運行庫。
圖 5:請求管道
當 IIS 接收到請求時,將根據 IIS 設置將擴展名映射到 ISAPI 篩選器。.aspx、.asmx、.asd 及其他擴展名被映射到 aspnet_isapi.dll,這只是一個用于啟動 ASP.NET 運行庫的 ISAPI 篩選器。當請求遇到 ASP.NET 運行庫后,它將在 HTTPApplication 對象(作為 ASP.NET Web 應用程序的主機)上啟動。HTTPApplication 對象:
1.
讀取計算機和應用程序級別的配置文件。
2.
將請求傳遞給一個或多個 HTTPModule 實例。每個 HTTPModule 提供一項服務,例如會話維護、驗證或配置文件維護。這些模塊將請求傳遞回 HTTPApplication。
3.
基于動詞和路徑將請求傳遞給 HTTPHandler。動詞是指請求中使用的 HTTP 動詞(GET、POST、FTP 等),路徑是指應用程序中的 URL。根據處理程序的配置方式,請求可能會被作為 ASP.NET 頁面(System.Web.UI.Page 是 IHTTPHandler 的實現)進行處理,也可能會觸發其他操作,例如對所有 Web 頁面進行批編譯(precomiplation.asd 將觸發 PrecompHandler)。
在 ASP.NET 2.0 中,此模型沒有任何變化,但添加了幾個新的模塊和處理程序以提供更多服務。就像在 ASP.NET 1.x 中一樣,您可以擴展、替換或重新配置任何模塊或處理程序類以提供自定義功能。
新模塊
顯然,新增的 HTTPModules 用于支持 ASP.NET 2.0 中提供的新服務。具體來說,具有默認模塊設置的 ASP.NET 應用程序包括為以下目的而添加的新模塊:
• SessionID - 會話標識機制已從 ASP.NET 1.x 會話模塊中拆分開來,目的是為了更好地控制 Cookie、URL 重寫以及生成會話 ID 的其他形式。
• 角色管理 - 這是一個新增的模塊,用于提供基于角色的服務,以支持新的用戶標識機制。此模塊有助于將 ASP.NET 應用程序鏈接到 .NET Framework 中內置的、基于角色的安全性。
• 匿名標識 - 支持匿名用戶的新的個性化功能。此模塊可以幫助跟蹤匿名用戶可以訪問的功能,以及跟蹤在請求之間維護這些功能的方式。
• 配置文件 - 配置文件模塊與新的配置文件服務相鏈接,可以幫助提供用戶特定的持久性數據存儲。
• 頁面計數器- ASP.NET 2.0 中增加的一個新模塊,用于鏈接頁面計數器并提高 Web 通信的統計分析。
除了這些新模塊以外,某些舊模塊的行為也發生了變化:例如,輸出緩存模塊現在支持本白皮書后面介紹的新的緩存技術。
新處理程序
除了新模塊以外,ASP.NET 2.0 還引入了新的處理程序,以支持應用程序配置工具和其他新功能,例如批編譯請求。最重要的新處理程序包括用來處理 Web 站點管理請求的“.axd”系列。這些處理程序將啟動允許開發人員配置 ASP.NET 用戶和其他設置的內部管理工具。這些管理處理程序包括:
• Web 管理 - WebAdminHandler 是管理 Web 站點的主頁。此處理程序為管理 ASP.NET 2.0 Web 應用程序提供了一個起點。
• 跟蹤 - ASP.NET 1.x TraceHandler 已得到改進,是 ASP.NET 1.x 中唯一可用的“axd”處理程序。
• Web 資源 - 借助新的管理工具和 WebResourcesHandler,現在可以將 Web 資源配置為后部署。
• 緩存的圖像 - CachedImageServiceHandler 支持緩存圖形組件。
• 計數器 - SiteCountersHandler 使用頁面計數器模塊來提供 ASP.NET 2.0 應用程序的訪問統計信息。
• 預編譯 - 如前文所述,可以使用 PrecompHandler 對 ASP.NET 應用程序中的所有 ASPX 頁面進行批編譯。
• Web 部件導出 - WebPartExportHandler 支持存儲和傳輸 Web 部件布局。Web 部件是一個新機制,用于個性化門戶樣式的 Web 應用程序的外觀和內容。
與以前一樣,HTTPForbiddenHandler 被鏈接到不應返回的任何文件類型。在 ASP.NET 2.0 中,被禁止的文件類型列表已被擴展,現在包括母版頁、外觀文件及其他新的開發人員組件。
返回頁首
高級緩存技術
提高 Web 應用程序性能的一種方法是在內存中緩存靜態內容。返回緩存的內容始終要比返回新渲染的內容快。但是,缺點是緩存的內容可能會過期。ASP.NET 1.x 支持幾種緩存,包括:
• 頁面級別 - 每個頁面可以作為一個整體進行緩存,或基于用來訪問該頁面的參數進行緩存。緩存的頁面將在指定時間后過期。
• 頁面片段 - 如果使用用戶控件(.ascx 文件)構建頁面,則可以獨立于頁面內容的其余部分單獨緩存用戶控件。
• 編程緩存 - 由于有了緩存 API,開發人員還可以緩存對象。緩存 API 具有一個顯著的優點,它使開發人員可以為何時應刷新緩存創建不同類型的依賴關系。
在 ASP.NET 2.0 中,頁面級別的緩存機制已得到擴展,以支持數據庫依賴關系。借助數據庫緩存依賴關系,可以將緩存的頁面綁定到 SQL Server 數據庫中的特定表。如果表發生變化,緩存將自動過期。此外,開發人員現在可以使用緩存后替換功能,用刷新的內容替換緩存的部分內容。緩存后替換功能允許應用程序使用頁面級別的緩存,即使頁面的部分內容應動態生成。
數據庫緩存過期
對大多數數據驅動的 Web 站點來說,緩存是一個復雜的主題,特別是在需要緩存且必須更新數據的情況下。在 ASP.NET 1.x 中,頁面可以緩存一段時間,并通過輸入參數(查詢字符串或 POST 參數)進行組織:
列表 5:ASP.NET 1.x 輸出緩存指令
<%@ outputcache duration="3600" varybyparam="ProdID" %>
例如,列表 5 中的代碼基于變量 ProdID 在內存中將頁面緩存一小時。以上示例中出現的問題是,如果相關業務數據在其他地方被更新,應該怎么辦?例如,假設按照產品 ID 緩存一個產品目錄頁面。如果從管理站點更新了此產品的相關信息(例如庫存數量或價格),那么緩存的數據將不正確,顯示給客戶的數據也不正確。在以前版本的 ASP.NET 中,要解決此問題,需要使用 Response.RemoveOutputCacheItem 手動從緩存中刪除該頁面,或等到 duration 時間過期后讓系統自動更新頁面。
ASP.NET 2.0 通過支持數據庫緩存依賴關系,從而解決了這一問題。使用 SQL Server 7 和 200 時可以使用表級別的通知,并且 Microsoft SQL Server 2005 將提供更精確級別的通知。例如,以下代碼最多可以將產品頁面緩存一小時,但添加了對數據庫表的第二層依賴關系。
列表 6:ASP.NET 2.0 數據庫緩存示例
<%@ outputcache duration="3600"
varybyparam="ProdID"
sqldependency="MyDatabase:Products" %>
使用新的 sqldependency 屬性時,只要對“Products”表進行更改,緩存的頁面就將過期。sqldependency 屬性必須引用在 web.config 文件中配置的 datasource。datasource 用于標識數據庫連接以及發出依賴關系通知所必需的參數。
自定義緩存依賴關系
ASP.NET 2.0 附帶了一個 CacheDependency 實現,即 SQLCacheDependency 類,它支持 Microsoft SQL Server。實現新的緩存依賴關系是一個復雜的過程,但由于 ASP.NET 2.0 具有可擴展性,因此這一過程是可以實現的。換句話說,您可以創建自己的 CacheDependency 類,以便為其他數據庫系統(如 Oracle 或 Sybase)提供類似的功能。
緩存后替換功能
對于幾個頁面元素保持動態更新,而頁面的大部分內容適于緩存的情況,可以利用 ASP.NET 2.0 提供的緩存后替換功能。緩存后替換功能用于通知 ASP.NET 運行庫是否應在向用戶顯示緩存的頁面之前重新評估該頁面上的某個特定元素。
使用此功能的方法有兩種:
• 調用新的 Response.writeSubstitution 方法,以傳遞對替換回調函數的引用。
• 將 <asp:substitution> 控件添加到 Web 頁中,并將 methodname 屬性設置為回調函數的名稱。
• 不管采用哪種方法,都需要在頁面中添加用來指定依賴關系的持續時間和位置的 @OutputCache 指令。
實現緩存后替換功能
可以創建支持緩存后替換功能的控件,以充分利用此功能。這類控件的一個示例就是 AdRotator。列表 7 展示了這樣一個頁面:
• 從“Pubs”數據庫的“authors”表中檢索數據。
• 將數據綁定到 GridView 控件。
• 顯示來自 AdRotator 的廣告。
• 在標簽控件上顯示創建頁面的時間。
該示例中還添加了 <asp:substitution> 控件(列表中以粗體顯示的行)。此控件將其 methodname 屬性設置為 uncachedUpdate(返回字符串輸出的方法,本例中為當前時間)。無論緩存了什么內容,替換控件都將返回正確的時間。
列表 7:PostCache.ASPX 源代碼
<%@ Page language="c#" Codebehind="PostCache.ASPX.cs"
AutoEventWireup="true" Inherits="WebApplication1.PostCache" %>
<%@ outputcache duration="30" varybyparam="none" %>
<!DOCTYPE HTML PUBLIC "-//W3C//D
TD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<DIV style="DISPLAY:inline;
Z-INDEX:101; LEFT:32px; WIDTH:160px;
POSITION:absolute; TOP:24px; HEIGHT:8px"
align="right" ms_positioning="FlowLayout">
this page was created at:
</DIV>
<asp:Label id="CreatedTime"
style="Z-INDEX:102; LEFT:200px; POSITION:absolute;
TOP:24px" runat="server" Width="120px" Height="16px">
</asp:Label>
<asp:substitution id="UpdatedTime" methodname="uncachedUpdate"
style="Z-INDEX:103; LEFT:200px; POSITION:absolute;
TOP:48px" runat="server" Width="112px" Height="11px">
</asp:substitution>
<DIV style="DISPLAY:inline; Z-INDEX:104; LEFT:32px;
WIDTH:160px; POSITION:absolute; TOP:48px;
HEIGHT:16px" align="right" ms_positioning="FlowLayout">
and last updated at:
</DIV>
<asp:AdRotator id="Ads" style="Z-INDEX:105; LEFT:312px;
POSITION:absolute; TOP:16px" runat="server"
Width="80px" Height="60px" AdvertisementFile="img/Ads.xml">
</asp:AdRotator>
</form>
</body>
</HTML>
此頁面的內含代碼文件包含支持 uncachedUpdate 方法的緩存后替換功能所必需的事件。請注意,Page_Load 方法將報告加載頁面的時間,因此我們可以確定緩存發生的時間。
列表 8:PostCache.ASPX.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace WebApplication1 {
public class PostCache :System.Web.UI.Page {
protected System.Web.UI.WebControls.Label CreatedTime;
protected System.Web.UI.WebControls.Label UpdatedTime;
protected System.Web.UI.WebControls.AdRotator Ads;
private void InitializeComponent() {
this.Load += new System.EventHandler(this.Page_Load);
}
private void Page_Load(object sender, System.EventArgs e) {
CreatedTime.Text = DateTime.Now.ToShortTimeString();
}
protected String uncachedUpdate() {
return DateTime.Now.ToShortTimeString();
}
}
}
當前使用的緩存后替換功能
圖 6 顯示了 PostCache 頁面的輸出。首次運行該應用程序時,我們可以看到“page created”和“last updated”時間是相同的。
圖 6:PostCache.ASPX 的輸出
以后調用同一頁面時,我們將看到使用緩存后替換功能的效果。盡管創建頁面的時間和圖像仍然相同,但上次更新時間是不同的。
圖 7:第二次請求時的 PostCache 輸出
由于使用了緩存指令,因此創建時間和 adRotator 圖像仍然保持不變。該頁面將緩存 30 秒。30 秒過后,創建時間和 adRotator 都將在下次請求時更新。但是,<asp:substitution> 控件(調用 uncachedUpdate() 方法)將在每次請求頁面時更新,而不管其緩存狀態。
通過正確使用緩存后替換功能,開發人員只需更新頁面上的動態內容,從而可以顯著提高其 Web 應用程序的性能。將使用 ASP.NET 2.0 開發的 Web 應用程序與數據庫緩存過期和異步頁面更新相集成,可以消除傳統的 Web 請求和響應體系結構暴露出來的許多局限性。
返回頁首
性能
盡管 ASP.NET 2.0 中的基礎結構發生了變化而且增加了一些功能,但仍然存在一個問題,那就是 ASP.NET 2.0 的執行速度有多快?因為 ASP.NET 2.0 仍在開發過程中,所以性能方面的數據還無法獲得。盡管如此,我們已經付出了很大的努力,以確保 ASP.NET 2.0 框架能夠在各方面保持現有的性能或有所改進。
改進的請求管道
所有開發人員都能看到請求管道的性能有所改進。盡管添加了許多新的事件連接,但基本的 ASP.NET 請求堆棧速度要比在 ASP.NET 1.1 中快出高達 30%。您可以通過創建顯示“Hello World”的簡單頁面來感受一下改進的性能。因為該頁面不包含高級功能,所以您可以直接測試 HTTPHandler 和 HTTPModule 管道以及連接 ASP.NET 2.0 和 IIS 的 ISAPI 插件。不管使用哪個版本的 IIS,您都能看到性能方面的改進,因為此代碼已被優化以加快處理速度。
使用 IIS 6.0 改進的內存管理
ASP.NET 2.0 中的某些性能改進完全是因為使用了 IIS 6.0。例如,如果使用 IIS 6.0,在使用 100 個并發用戶請求一個包含幾個控件的頁面的加載測試中,輔助進程的工作集減少了大約 50%。這意味著,對于給定服務器,操作系統使用的資源大約是以前必須使用的資源的一半。
在專門模擬中等復雜程度的 ASP.NET 頁面的測試中,與在 IIS 5.0 上運行的同一頁面相比,系統負載(內存和 CPU 使用量)已顯著降低。這種特定的性能改進是通過將響應緩沖區從托管內存移至本機內存來完成的。由于不再需要將托管內存固定到特定的響應,因此 ASP.NET 2.0 不僅消除了資源瓶頸,還能夠更快地響應每個請求。
其他的性能改進是通過緊密集成 IIS 6.0 與 Windows 操作系統內核而實現的。IIS 6.0 在內核級別執行某些緩存和緩沖操作,從而提高了所有 Web 應用程序(包括 ASP.NET)的性能。
其他改進
作為一名開發人員,您肯定希望 ASP.NET 2.0 與 ASP.NET 1.x 的操作速度相同或更快?,F在,核心功能已經具備,您一定能夠從最終版本的 ASP.NET 2.0 中看到所期待的其他性能改進。
返回頁首
結論
為了提高開發人員的工作效率,ASP.NET 2.0 進行了許多體系結構方面的改進。不僅改進了代碼模型以減少沖突,還擴展了編譯進程,從而為編譯和部署 Web 應用程序提供了多種選擇。ASP.NET 框架的可擴展性再次通過新的 HTTPModules 和 HTTPHandlers(支持 ASP.NET 中的許多新功能,包括個性化、母版頁和管理站點)顯示出來。緩存功能得到改進,允許使用數據庫依賴關系和緩存后替換功能。從內部來看,ASP.NET 2.0 與以前的版本相比具有很大的改進;新的實現并入了開發人員驅動的許多改進功能,同時沿用了行業最佳做法。ASP.NET 2.0 提供了世界一流的 Web 開發平臺,可以處理復雜的企業 Web 應用程序開發。
參考資料
• CodeNotes for ASP.NET
• A First Look at ASP.NET V. 2.0
• ASP.NET 2.0 Revealed
關于作者
Jayesh Patel - Jay Patel 是擅長 .NET 和 Java 技術的開發人員。Jay 主要研究基于模式的編程和靈活的方法。
Bryan Acker - Bryan Acker 是 Infusion Development 的技術撰稿人。Bryan 在 ASP 和 ASP.NET Web 開發及 Web 托管技術方面有著很強的專業背景。
Robert McGovern - Rob McGovern 是 Infusion Development 的高級撰稿人、開發人員兼項目經理。Rob 曾參與幾個不同的 ASP.NET 項目,包括“CodeNotes for ASP.NET”和“JSP to ASP.NET migration guide”。
Infusion Development Corporation 是通過 Microsoft 認證的
解決方案提供商,為世界 1000 強企業提供量身定做的軟件開發、
培訓和咨詢服務,主要服務于
金融服務行業。Infusion Development 在紐約和多倫多設有辦事處,已建立一定的國際客戶基礎,包括金融服務、證券經紀和軟件開發行業中的一些世界最大的公司。Infusion Development 的員工也是 CodeNotes 系列叢書的作者和創始人。
原文轉自:http://www.kjueaiud.com