| global.asax是一個文本文件,它提供全局可用代碼。這些代碼包括應用程序的事件處理程序以及會話事件、方法和靜態變量。有時該文件也被稱為應用程序文件。 global.asax 文件中的任何代碼都是它所在的應用程序的一部分。每個應用程序在其根目錄下只能有一個global.asax文件。然而,這個文件是可選的。如果沒有global.asax文件,應用程序將對所有事件應用由 HttpApplication類提供的默認行為。 提示:經典ASP有一個與global.asax類似格式和構造的,名為global.asa的文件。實際上,如果將一個正在運行的global.asa文件代碼復制到global.asax中,應用程序同樣可以運行。 當應用程序運行的時候,global.asax的內容被編譯到一個繼承自HttpApplication類的類中。因此,HttpApplication類中所有的方法、類和對象對於應用程序都是可用的。 CLR 監控着global.asax的變化。如果它察覺到這個文件發生了改變,那么將自動啟動一個新的應用程序復本,同時創建一個新的應用程序域。原應用程序域當前正在處理的請求被允許結束,而任何新的請求都交由新應用程序域來處理。當原應用程序域的最后一個請求處理完成時,這個應用程序域即被清除。這有效的保證了應用程序可以重新啟動,而不被任何用戶察覺。 為防止應用程序用戶下載應用程序而看到源代碼,ASP.NET缺省配置為阻止用戶查看global.asax的內容。如果有人在瀏覽器輸入以下URL: http://localhost/progaspnet/Global.asax 這將會收到一個403(禁止訪問)錯誤信息或者類似的信息如: This type of page is not served。 提示:簡單而言,web.config文件與global.asax有些類似的地方。如果這個文件被更改,應用程序將自動“重啟”。同樣,也不可能在瀏覽器中查看web.config文件。 Global.asax文件從外觀和結構上與頁面文件(.aspx)相似。它可以有一個或多個部分,簡要描述如下: l 指令 l 腳本塊 l Object聲明 正如Web頁和Web服務能夠使用代碼隱藏功能,global.asax同樣也可以。然而,與Web頁和Web服務的條件有所不同,VS2005默認狀態下不對global.asax使用代碼隱藏功能。 提示:Visual Studio 2005預覽版默認對global.asax使用代碼隱藏模型。目前仍然支持代碼隱藏,但不是默認使用。 為了對global.asax使用代碼隱藏技術,可使用位於該文件頭部的Application指令(類似於頁面文件的Page指令,下一節將詳細介紹)的Inherits屬性,該屬性指向global.asax.cs中的代碼隱藏類。 同時,也有一個CodeBehind屬性用來指向代碼隱藏文件。然而,如果它指向的是一個位於App_Code文件夾以外的位置,那么必須對這個類文件進行手動編輯。 通過右鍵單擊解決方案資源管理器中的網站或者單擊網站菜單,然后選擇“Add New Item...”,接着選擇全局應用程序類,可以為Web應用程序添加一個global.asax文件。保留默認名稱global.asax。 VS2005將創建一個如示例18-1所列的文件。模板中包括對以下5個事件的空白聲明:Application_Start、Application_End、Session_Start、Session_End和Applica- tion_Error。 示例18-1:global.asax模板 <%@ Application Language="C#" %> 在示例18-2所列舉的global.asax文件中,為應用程序狀態設置了一些值,同時,在每次應用程序啟動的時候向日志文件寫一個條目。為了使用這個示例,需要保證ASP.NET帳戶對根目錄c:\具有寫入權限(在產品系統中不推薦)。 示例18-2:global.asax示例 <%@ Application Language="C#"%> 指令 與Web頁和Web服務文件相比,global.asax可以以多個指令作為開始。這些指令在處理ASP.NET文件時指定應用程序編譯的設置。與Page指令相比,Application指令可 接受一個或者多個具有字典結構的屬性/值對。此處支持三個指令:Application、Import和Assembly。 Application Application指令設置編譯器的應用程序專用屬性。以下是一個Application指令示例: <%@ Application Language="C#" Inherits="WebServiceConsumer.Global" Description="A sample application" %> Language 屬性可以設置為任何一種標准語言名稱:VB、C#、JS、或VJ#,它們分別對應VB2005、C#、JScript.NET或J#。(可以使用任何一種支持.NET平台的第三方語言)默認值為C#。此處的Language設置的是語言專門用於global.asax文件,而非其他應用程序代碼文件。例如,可以完全合法地在global.asax文件中使用C#,在.aspx文件中使用VB2005,相反亦然。 Inherits屬性指定所繼承類名,具有代表性的如代碼隱藏文件中的類。 Description屬性接受對應用程序的文本描述,而分析器和編譯器將會忽略它。 CodeBehind屬性在Visual Studio .NET(非VS2005)中用來指定包含的代碼隱藏文件。 Import Import指令僅包括一個Namespace屬性。所指定名字空間被明確地導入應用程序中,使其所有的類和接口都可用。導入的名字空間可以是.NET Framework的一部分或者用戶自定義的名字空間。 以下是一個典型的Import指令: <%@ Import Namespace="System.Data" %> 只能有一個Namespace屬性。如果需要導入多個名字空間,那么需要使用多個Import指令。 下列名字空間自動導入到所有的Web應用程序中,所以沒必要使用Import指令。 l System l System.Collections l System.Collections.Specialized l System.Configuration l System.IO l System.Text l System.Text.RegularExpressions l System.Web l System.Web.Caching l System.Web.Security l System.Web.SessionState l System.Web.UI l System.Web.UI.HtmlControls l System.Web.UI.WebControls Assembly Assembly指令用於在編譯過程中將一個程序集鏈接到當前應用程序。這樣可以使所有程序集的類與接口對應用程序都是可用的。 提示:典型的程序集是.dll或.exe文件,這將在下一章中詳細講解。 由於在編譯時引用程序集,所以可以使用Assembly指令綁定程序集,然后在運行時將其加載到應用程序池中。 位於應用程序集緩存(也就是位於bin目錄和App_Code目錄中的代碼文件)中的程序集可自動連接到應用程序。因此,任何位於bin目錄的程序集,或者由App_Code目錄中的代碼編譯而來的任何程序集,都不需要使用Assembly指令實現連接。 Assembly指令包括兩個屬性:Name和Src。Name屬性是一個字符串,表示連接到應用程序的程序集名字,它不能包含路徑。Src屬性則是指向源文件的路徑(只能為相對路徑),這些文件將被動態編譯和連接。 每個程序集指令只能有一個屬性。如果需要連接多個程序集,則應使用多個Assembly指令。 Assembly指令類似於: <%@ Assembly %> <%@ Assembly Src="sources/SomeSourceFile.cs" %> 腳本塊 典型的global.asax文件中包含大量代碼,這些代碼包含在以script標簽起止的腳本塊中: 如果使用代碼隱藏,雖然代碼隱藏文件中的代碼本身沒有附加script標簽,但包含在代碼隱藏文件中的代碼與腳本塊中的代碼是等效的。 腳本塊中的代碼可以包含事件處理程序或者方法,下文將對此進行講解。 事件 如同Web頁和控件可以公開事件一樣,應用程序中的Application對象和 Session對象也能夠公開事件。這些事件能被global.asax文件或指定的文件中的事件處理程序處理。例如,當應用程序開始執行時,觸發 Application_Start事件;當應用程序結束時,觸發Application_End事件。Application的某些事件是每當頁面請求時觸發,而其他一些事件,例如Application_Error,則僅在特定情況下觸發。 示例18-2中的global.asax文件代碼說明了Application_Start 和Application_End事件。示例18-2中的Application_Start事件設置了兩個Application屬性:一個是名為 strConnectionString的字符串,一個是名為arBooks的字符串數組。事件處理程序方法調用一個名為WriteFile的輔助方法,它包含在global.asax文件中。該輔助方法將一個字符串寫入日志文件中。以下是示例18-2中的WriteFile方法代碼: void WriteFile(string strText) { System.IO.StreamWriter writer = new System.IO.StreamWriter(@"C:\test.txt",true); string str; str = DateTime.Now.ToString( ) + " " + strText; writer.WriteLine(str); writer.Close( ); } WriteFile 是一個簡單的記錄日志的方法。該方法初始化一個基於文本文件的 StreamWriter對象,並對c:\test.txt進行硬編碼。它在文件中添加了一個時間戳,並寫入通過方法傳遞的字符串。 StreamWriter方法的布爾值參數為true,其表示如果文件已經存在,那么將文本行追加到文件中。如果文件不存在,則創建一個文件。 Application_End事件處理方法調用了另一個WriteFile方法,它添加了一個日志條目以記錄應用程序結束。 為了查看這兩個事件處理程序的結果,可對global.asax進行一些無意義的編輯,並保存文件。此時將強制結束應用程序。然后請求虛擬目錄中的任意URL地址。例如,使用上一章中的一個網頁——實際上無論哪一個——或者一個自己創建的網頁。示例18-3顯示了日志文件內容。 示例18-3:Test.txt摘錄 8/26/2006 5:46:23 PM Application Starting 8/26/2006 6:13:35 PM Application Ending 8/27/2006 10:17:39 PM Application Starting 8/27/2006 10:18:23 PM Application Ending 8/27/2006 10:18:36 PM Application Starting 如同Application對象的Start和End事件一樣,Session對象也擁有Session_ Start和Session_End事件。這將允許應用程序每次啟動和結束過程中為每個會話都運行代碼。 如示例18-4中高亮顯示的方法名所示,其包括了global.asax文件中所有可能的應用程序事件處理程序。在頁面請求被接受、處理和呈現過程中,可以容易地查看應用程序生命周期。 示例18-4:Global.asax事件說明 <%@ Application Language="C#" %> 以下是頁面請求觸發的所有事件,以觸發順序排序: Application_BeginRequest 當ASP.NET開始處理每個請求時觸發。在這個事件處理中的代碼將在頁面或者服務處理請求之前執行。 Application_AuthenticateRequest 在驗證請求之前觸發。(正如第12章介紹的,驗證是確認用戶就是他所說的那個人的過程)在這個事件處理程序的代碼中允許實現自定義安全管道。 Application_AuthorizeRequest 在為請求授權之前觸發。(授權是確定是否請求用戶具有訪問資源的權限的過程,在 第12章已經介紹過)在這個事件處理程序的代碼中允許實現自定義安全管道。 Application_ResolveRequestCache 在ASP.NET確定是否應該生成新的輸出,或者由緩存填充前觸發。無論何種情況,都將執行該事件處理程序中的代碼。 Application_AcquireRequestState 在獲取會話狀態之前執行。 Application_PreRequestHandlerExecute 在將請求發送到服務於請求的處理程序對象之前觸發。當事件觸發后,頁面將由HTTP處理程序處理請求。 Application_PostRequestHandlerExecute 當HTTP處理程序與頁面請求一起完成時觸發。此時,Response對象將獲得由客戶端返回的數據。 Application_ReleaseRequestState 當釋放和更新試圖狀態時觸發。 Application_UpdateRequestCache 如果輸出被緩存,那么緩存更新時將觸發。 Application_EndRequest 當請求結束時執行。 Application_PreSendRequestHeaders 在向客戶端發送HTTP頭之前觸發。如果啟用響應緩存,這意味着直到所有數據都准備好(默認條件),都不會發送任何數據。該事件總是在Application_EndRequest事件之后。如果禁用響應緩存,那么無論何時將數據發送給客戶端,都將觸發該事件。響應控制由Page指令的一個屬性,或者Web服務的WebMethod屬性控制。 Application_PreSendRequestContent 向客戶端發送HTTP內容之前觸發。和Application_PreSendRequestHeaders事件一樣,Application_PreSendRequestContent事件能否被觸發取決於響應緩存是否可用。 以下列舉應用程序事件,它們在特定條件下觸發: Application_Start 當應用程序啟動時觸發。當首次請求應用程序虛擬目錄中的任何頁面時,將啟動應用程序,同時如果應用程序已經運行,則不觸發該事件。 Application_End 應用程序結束時觸發。無論何時修改了配置文件(global.asax、global.asax.cs、 global.asax.vb或者web.config),或者服務器崩潰或者重啟,應用程序都將結束。通常在該事件處理程序中執行清除功能的代碼,例如關閉數據庫連接。 Session_Start 每個會話開始時觸發,這是放置具體會話代碼的地方。 Session_End 會話結束時觸發。它為保存存儲在會話中的任何數據提供了機會。 Application_Disposed 當CLR從內存中移除應用程序時觸發。 Application_Error 無論在應用程序中何時何處發生未處理的錯誤都將觸發。它提供了一個實現通用應用程序錯誤處理的好機會。 使用try...catch語句塊能夠在代碼中處理特定錯誤,也可以使用Page指令的ErrorPage屬性來捕獲頁面級錯誤。使用這些方式處理任何錯誤都不會觸發Application_Error事件。 為了測試新版的global.asax,在示例18-5中創建一個網頁。查看GlobalEvents站點。當該網頁運行時,將看到如圖18-4所示的頁面。 示例18-5:GlobalEvents網站的default.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> Global Events Text="End Session" OnClick="btnEndSession_Click" /> Text="Generate Error" OnClick="btnError_Click" /> ![]() 圖18-4:GlobalEvents 如圖18-4所示,可看到觸發了一系列應用程序事件。在這些事件執行的中途,呈現了.aspx頁面自身,接着是另一些應用程序事件。 警告:示例GlobalEvents必須在一個真實的IIS虛擬路徑下才能良好運行。 頁面第一次顯示時觸發Session_Start事件,而在隨后的顯示中則不再觸發該事件。 這是因為請求是相同的會話。單擊“End Session”按鈕,調用Session.Abandon方法,這將結束當前會話。下一次頁面被提交到服務器時,將再次觸發Session_Start 事件。 Post按鈕提供了一個簡單的再次提交頁面的方法。 示例18-4中大部分的應用程序事件處理程序都使用了Response.Write方法,以便顯示觸發的事件。然而,Application_Start和Application_End方法調用了WriteFile方法。如果在這些事件處理程序中試圖使用Response.Write方法,那么在頁面中將不會 顯示。因為那時用於呈現的頁面會話還沒有運行。但是,當檢查日志文件c:\test.txt時,將看到應用程序啟動和結束所顯示的條目。 示例18-4所示的global.asax文件說明了一種使用Application_Error事件的方法。以下列舉了這些代碼: protected void Application_Error(Object sender, EventArgs e) { string strError; strError = Server.GetLastError( ).ToString( ); if (Context!= null) Context.ClearError( ); Response.Write("Application_Error" + " "); Response.Write("Error Msg: " + strError + " " + "End Error Msg "); } 該事件處理程序使用HttpServerUtility對象的GetLastError方法,以報告最后出現的錯誤。這個錯誤被轉換為一個字符串,並被指定給一個字符串變量: strError = Server.GetLastError( ).ToString( ) 接下來調用HttpContext對象的ClearError方法來清除目前HTTP請求中的所有錯誤: Context.ClearError( ) 如果沒有將錯誤清除,那么錯誤將顯示在客戶端瀏覽器,並且還是無法看見Respons- e.Write方法的顯示結果。 最后,Response.Write方法顯示一個信息,當前的錯誤將顯示在客戶端。 另一種向用戶報告錯誤的方式是顯示自定義錯誤處理頁面。為此,需要使用以下代碼行替代Application_Error事件處理程序中的Response.Write方法: Response.Redirect("CustomErrorPage.aspx?Msg=" + Server.UrlEncode(strError)); 以上代碼行調用HttpServerUtility對象的UrlEncode方法,其將錯誤信息作為一個QueryString參數傳遞給CustomErrorPage.aspx頁面中的自定義錯誤處理代碼。 CustomErrorPage.aspx頁面有一個名為lblMessage的Label控件。以下是頁面中的Page_Load方法代碼: void Page_Load(Object Source, EventArgs E) { lblMessage.Text = Request.QueryString["Msg"]; } Default.aspx中的Generate Error按鈕故意觸發一個錯誤,以便查看錯誤處理。該按鈕的單擊事件處理程序的代碼如下所示,它將除零異常: protected void btnError_Click(object sender, EventArgs e) { int a = 5; int b = 0; int c; c = a / b; } 服務器端包括 使用服務器端包括能夠實現在應用程序中包含外部源代碼文件。在編譯之前,包括文件中的代碼將被添加到global.asax文件中。盡管應用程序的語言可能與包括文件的語言不同,但是用於包括文件的語言必須與global.asax文件所使用的語言匹配。 下面是用於服務器端的語法: 在這個句法中,PathType類型可以是表18-1所示之一。 表18-1 PathType屬性
查看示例18-4所示的global.asax文件,將下面的代碼添加到第二行中: 創建一個新的名為IncludeFile.cs的文本文件,將該文件和global.asax存儲在同一目錄下。這個文件需要與global.asax文件一樣的一對腳本標簽。 將global.asax頁面中的WriteFile方法復制到包括文件中,然后注釋(或者刪除)global.asax頁面中的WriteFile方法。這樣包括文件應類似於示例18-6。 示例18-6:具有包括文件的global.asax 如果運行任意一個網頁,那么將不會與先前有什么區別,因為您所做的只是把一個文件中的代碼轉移到另外一個文件中。 如果CLR監視global.asax文件的變化,並和重新啟動應用程序一樣,CLR也監視包括文件的變化。如果包括文件發生變化,那么應用程序也會重新啟動。 對於在多個應用程序中所包括的相同標准代碼而言,包括文件非常有用。這些通用代碼可能包括數據庫訪問方法、寫入日志記錄、錯誤處理管道、登錄或者每個應用程序的基礎類型代碼片段。 對象聲明 在global.asax文件中包括代碼的另一個方法是是聲明object標簽。這些聲明的靜態對象要么是Application,或者是Session對象。這樣就可以在應用程序或者每個會話過程中使用。 |

