C# 問題解決思路--《數組bytes未定義》,ASP.NET頁面加載順序

很久沒寫博客了,廢話很少說,直接說問題。javascript

問題發生狀況,首先這個是老項目,而後我是第一次修改。當我解決了各類引用,數據庫配置以後等相似的問題,我啓動的項目的時候,無任何問題,可是當我點擊頁面的按鈕的時候,就報類型的錯誤。java

所以,我按照我我的的經驗,作出排查。web

一、首先是代碼問題,我根據按鈕找到對應的後臺事件,而後加上斷點,發現根本就不進對應的斷點。(說明不是按鈕的後臺代碼的錯誤)數據庫

二、有多是整個頁面的後臺代碼的其餘的錯誤,所以我搜索了該後臺代碼  看是否哪裏出現了 bytes這個數組,結果沒有找到。(說明不是該頁面的後臺代碼的錯誤)編程

三、該頁面是集成另外一個公共頁面  basePage,因而我在basePage初始化的pageLoad事件裏面加上了斷點,結果發現,也不進頁面,因此排除了繼承的初始頁面的問題。數組

四、按理說報的錯誤實際上是不該該爲前臺代碼的錯誤的,可是爲了保險起見,我仍是搜索了一下對應的前臺代碼,發現也沒有任何地方是用到bytes這個數組變量的(所以排除了是後臺代碼的錯誤)瀏覽器

五、最後,我以爲多是頁面上某些特殊控件的緣由,最後我將頁面上的fck編輯器等幾個特殊空間的和javascript的引用都註釋了,後臺代碼也跟着註釋了,發現也沒有解決對應的問題。緩存

六、上述我都檢查過了,可是仍是不知道是哪裏出的問題,最終在項目經理永哥的幫助下,才知道配置文件中,在應用程序中配置了 HTTP 模塊服務器

<httpModules>
<add name="WebbHttpModule" type="Means.Component.WebUpload.WebbHttpModule, Means.Component"/>
</httpModules>
<httpHandlers>
<add verb="*" path="progress.ashx" type="Means.Component.WebUpload.WebbUploadStatusHandler, Means.Component" />
</httpHandlers>框架

問題就處在了這幾個模塊裏面,講這兩行配置給註釋掉以後,就不會出現問題了。實在是經驗不足的問題。

 

 

ASP.NET 母版頁和內容頁中的事件
母版頁和內容頁均可以包含控件的事件處理程序。對於控件而言,事件是在本地處理的,即內容頁中的控件在內容頁中引起事件,母版頁中的控件在母版頁中引起事件。控件事件不會從內容頁發送到母版頁。一樣,也不能在內容頁中處理來自母版頁控件的事件。
在某些狀況下,內容頁和母版頁中會引起相同的事件。例如,二者都引起 Init 和 Load 事件。引起事件的通常規則是初始化事件從最裏面的控件向最外面的控件引起,全部其餘事件則從最外面的控件向最裏面的控件引起。請記住,母版頁會合併到內容頁中並被視爲內容頁中的一個控件,這一點十分有用。

下面是母版頁與內容頁合併後事件的發生順序:

母版頁控件 Init 事件。
內容控件 Init 事件。
母版頁 Init 事件。
內容頁 Init 事件。
內容頁 Load 事件。
母版頁 Load 事件。
內容控件 Load 事件。
內容頁 PreRender 事件。
母版頁 PreRender 事件。
母版頁控件 PreRender 事件。
內容控件 PreRender 事件。

母版頁和內容頁中的事件順序對於頁面開發人員並不重要。可是,若是您建立的事件處理程序取決於某些事件的可用性,那麼您將發現,瞭解母版頁和內容頁中的事件順序頗有幫助。

 

是,若是您建立的事件處理程序取決於某些事件的可用性,那麼您將發現,瞭解母版頁和內容頁中的事件順序頗有幫助。

 

關於asp.net中頁面事件加載的前後順序

 

Page 執行中將按照以下順序激活事件:

Page.PreInit
Page.Init
Page.InitComplite
Page.PreLoad
Page.Load
Page.LoadComplete
Page.PreRender
Page.PreRenderComplete

若是頁面從另外一個頁面繼承,如BasePage:System.Web.UI.Page,在BasePage中作了一些擴展,如權限檢查,而其餘頁面從BasePage繼承,則BasePage和最終Page的事件激活順序是:

UI.PreInit
Page.PreInit
UI.Init
Page.Init
UI.InitComplite
Page.InitComplite
UI.PreLoad
Page.PreLoad
UI.Load
Page.Load
UI.LoadComplete
Page.LoadComplete
UI.PreRender
Page.PreRender
UI.PreRenderComplete
Page.PreRenderComplete

若是使用了MasterPage,則MasterPage中的事件和ContentPage中的事件按照下面順序激活:

ContentPage.PreInit
Master.Init
ContentPage.Init
ContentPage.InitComplite
ContentPage.PreLoad
ContentPage.Load
Master.Load
ContentPage.LoadComplete
ContentPage.PreRender
Master.PreRender
ContentPage.PreRenderComplete

更進一步,若是ContentPage繼承BasePage,那麼,各事件的執行順序將變成:

UI.PreInit
ContentPage.PreInit
Master.Init
UI.Init
ContentPage.Init
UI.InitComplite
ContentPage.InitComplite
UI.PreLoad
ContentPage.PreLoad
UI.Load
ContentPage.Load
Master.Load
UI.LoadComplete
ContentPage.LoadComplete
UI.PreRender
ContentPage.PreRender
Master.PreRender
UI.PreRenderComplete
ContentPage.PreRenderComplete

瀏覽下來發現並非我如今所學的asp.net 1.1,估計應該是asp.net 2.0,

不過也沒有關係,這讓我知道了他們有繼承時加載的順序。

即:先加載繼承頁的,在加載本身的,若是繼承頁有繼承則先加載繼承頁的繼承。

實際上是個很簡單的內容。順便寫下Page事件(不知道1.1是否是就這些)

 

 

 事件處理器名稱

 發生時間

 Page_Init

在Web窗體的視圖狀態加載服務器控件並對其初始化。

這是web窗體生命週期的第一步 

 Page_Load

在Page對象上載入服務器控件。因爲此時視圖狀態信息是可使用的,

所以載這裏能夠用代碼來改變空間的設置或者載頁面上顯示文本。 

Page_PreRender  應用程序將要呈現Page對象 
Page_Unload  頁面從內存中卸載 
 Page_Error  發生未處理的異常
Page_AbortTransaction  事務處理被終止 
Page_CommitTransaction  事務處理被接受 
Page_DataBinding  把頁面上的服務器空間和數據源綁定載一塊兒 
 Page_Disposed Page對象從內存中釋放掉。這是Page對象生命週期中的最後一個事件 

Init,Load,PreRender事件執行順序:
1)控件的Init事件
2)控件所在頁面的Init事件
3)控件所在頁面的Load事件
4)控件的Load事件
5)控件所在頁面的PreRender事件
6)控件的PreRender事件

規律:
1)Init事件從最裏面的控件(包括用戶控件及普通控件)向最外面的控件(頁面)引起,Load及PreRender等其餘事件從最外面的控件向最裏面的控件引起;
2)控件之間相同事件的執行順序依控件在頁面的位置按從左到右,從上到下的前後順序執行。

注意:
1)切記用戶控件也被視爲頁面中的一個控件;
2)把用戶控件做爲單獨的一個特殊頁面來看,它自己及其所包含的控件一樣遵照相同的規律;
3)有時在客戶端程序(如javascript)中會用到客戶端body對像的onload事件,注意這個客戶端事件是最後執行,即在服務器端全部事件執行完後才執行。

===================================================================================

轉載一篇關於頁面對象模型的文章,說得比較詳細,有助理解。沒事的時候就多看兩遍,慢慢體會:)。
ASP.NET 頁面對象模型
Dino Esposito
Wintellect

2003 年 8 月 

適用於:
    Microsoft® ASP.NET

摘要:瞭解爲 ASP.NET Web 頁面創建的事件模型,以及 Web 頁面轉變爲 HTML 過程當中的各個階段。ASP.NET HTTP 運行時負責管理對象管道,這些對象首先將請求的 URL 轉換成 Page 類的具體實例,而後再將這些實例轉換成純 HTML 文本。本文將探討那些做爲頁面生命週期標誌的事件,以及控件和頁面編寫者如何幹預並改變標準行爲。(本文包含一些指向英文站點的連接。)

目錄

簡介
真正的 Page 類
頁面的生命週期
執行的各個階段
小結

簡介

對由 Microsoft® Internet 信息服務 (IIS) 處理的 Microsoft® ASP.NET 頁面的每一個請求都會被移交到 ASP.NET HTTP 管道。HTTP 管道由一系列託管對象組成,這些託管對象按順序處理請求,並將 URL 轉換爲純 HTML 文本。HTTP 管道的入口是 HttpRuntime 類。ASP.NET 結構爲輔助進程中的每一個 AppDomain 建立一個此類的實例。(請注意,輔助進程爲每一個當前正在運行的 ASP.NET 應用程序維護一個特定的 AppDomain。)

HttpRuntime 類從內部池中獲取 HttpApplication 對象,並安排此對象來處理請求。HTTP 應用程序管理器完成的主要任務就是找到將真正處理請求的類。當請求 .aspx 資源時,處理程序就是頁面處理程序,即從 Page 繼承的類的實例。資源類型和處理程序類型之間的關聯關係存儲在應用程序的配置文件中。更確切地說,默認的映射集是在 machine.config 文件的 <httpHandlers> 部分定義的。可是,應用程序能夠在本地的 web.config 文件中自定義本身的 HTTP 處理程序列表。如下這一行代碼就是用來爲 .aspx 資源定義 HTTP 處理程序的。

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
                        

擴展名能夠與處理程序類相關聯,而且更可能是與處理程序工廠類相關聯。在全部狀況下,負責處理請求的 HttpApplication 對象都會得到一個實現 IHttpHandler 接口的對象。若是根據 HTTP 處理程序來解析關聯的資源/類,則返回的類將直接實現接口。若是資源被綁定處處理程序工廠,則還須要額外的步驟。處理程序工廠類實現 IHttpHandlerFactory 接口,此接口的 GetHandler 方法將返回一個基於 IHttpHandler 的對象。

HTTP 運行時是如何結束這個循環並處理頁面請求的?ProcessRequest 方法在 IHttpHandler 接口中很是重要。經過對錶明被請求頁面的對象調用此方法,ASP.NET 結構會啓動將生成瀏覽器輸出的進程。

真正的 Page 類

特定頁面的 HTTP 處理程序類型取決於 URL。首次調用 URL 時,將構建一個新的類,這個類被動態編譯爲一個程序集。檢查 .aspx 資源的分析進程的結果是類的源代碼。該類被定義爲命名空間 ASP 的組成部分,而且被賦予了一個模擬原始 URL 的名稱。例如,若是 URL 的終點是 page.aspx,則類的名稱就是 ASP.Page_aspx。不過,類的名稱能夠經過編程方式來控制,方法是在 @Page 指令中設置 ClassName 屬性。

HTTP 處理程序的基類是 Page。這個類定義了由全部頁面處理程序共享的方法和屬性的最小集合。Page 類實現 IHttpHandler 接口。

在不少狀況下,實際處理程序的基類並非 Page,而是其餘的類。例如,若是使用了代碼分離,就會出現這種狀況。代碼分離是一項開發技術,它能夠將頁面所需的代碼隔離到單獨的 C# 和 Microsoft Visual Basic® .NET 類中。頁面的代碼是一組事件處理程序和輔助方法,這些處理程序和方法真正決定了頁面的行爲。可使用 <script runat=server> 標記對此代碼進行內聯定義,或者將其放置在外部類(代碼分離類)中。代碼分離類是從 Page 繼承並使用額外的方法的類,被指定用做 HTTP 處理程序的基類。

還有一種狀況,HTTP 處理程序也不是基於 Page 的,即在應用程序配置文件的 <pages> 部分中,包含了 PageBaseType 屬性的從新定義。

<pages PageBaseType="Classes.MyPage, mypage" />
                        

PageBaseType 屬性指明包含頁面處理程序的基類的類型和程序集。從 Page 導出的這個類能夠自動賦予處理程序擴展的自定義方法和屬性集。

頁面的生命週期

徹底識別 HTTP 頁面處理程序類後,ASP.NET 運行時將調用處理程序的 ProcessRequest 方法來處理請求。一般狀況下,無需更改此方法的實現,由於它是由 Page 類提供的。

此實現將從調用爲頁面構建控件樹的 FrameworkInitialize 方法開始。FrameworkInitialize 方法是 TemplateControl 類(Page 自己今後類導出)的一個受保護的虛擬成員。全部爲 .aspx 資源動態生成的處理程序都將覆蓋 FrameworkInitialize。在此方法中,構建了頁面的整個控件樹。

接下來,ProcessRequest 使頁面經歷了各個階段:初始化、加載視圖狀態信息和回發數據、加載頁面的用戶代碼以及執行回發服務器端事件。以後,頁面進入顯示模式:收集更新的視圖狀態,生成 HTML 代碼並隨後將代碼發送到輸出控制檯。最後,卸載頁面,並認爲請求處理完畢。

在各個階段中,頁面會觸發少數幾個事件,這些事件能夠由 Web 控件和用戶定義的代碼截取並進行處理。其中的一些事件是嵌入式控件專用的,所以沒法在 .aspx 代碼級進行處理。

要處理特定事件的頁面應該明確註冊一個適合的處理程序。不過,爲了向後兼容早期的 Visual Basic 編程風格,ASP.NET 也支持隱式事件掛鉤的形式。默認狀況下,頁面會嘗試將特定的方法名稱與事件相匹配,若是實現匹配,則認爲此方法就是匹配事件的處理程序。ASP.NET 提供了六種方法名稱的特定識別,它們是 Page_InitPage_LoadPage_DataBindPage_PreRender 和 Page_Unload。這些方法被認爲是由 Page 類提供的相應事件的處理程序。HTTP 運行時會自動將這些方法綁定到頁面事件,這樣,開發人員就沒必要再編寫所需的粘接代碼了。例如,若是命名爲 Page_Load 的方法綁定到頁面的 Load 事件,則可省去如下代碼。

this.Load += new EventHandler(this.Page_Load);
                        

對特定名稱的自動識別是由 @Page 指令的 AutoEventWireup 屬性控制的。若是該屬性設置爲 false,則要處理事件的全部應用程序都須要明確鏈接到頁面事件。不使用自動綁定事件的頁面性能會稍好一些,由於不須要額外匹配名稱與事件。請注意,全部 Microsoft Visual Studio® .NET 項目都是在禁用 AutoEventWireup 屬性的狀況下建立的。可是,該屬性的默認設置是 true,即 Page_Load等方法會被識別,並被綁定到相關聯的事件。

下表中按順序列出了頁面的執行包括的幾個階段,執行的標誌是一些應用程序級的事件和/或受保護並可覆蓋的方法。

表 1:ASP.NET 頁面生命中的關鍵事件

階段 頁面事件 可覆蓋的方法
頁面初始化 Init  
加載視圖狀態   LoadViewState
處理回發數據   任意實現 IPostBackDataHandler 接口的控件中的 LoadPostData 方法
加載頁面 Load  
回發更改通知   任意實現 IPostBackDataHandler 接口的控件中的 RaisePostDataChangedEvent 方法
處理回發事件 由控件定義的任意回發事件 任意實現 IPostBackDataHandler 接口的控件中的 RaisePostBackEvent 方法
頁面顯示前階段 PreRender  
保存視圖狀態   SaveViewState
顯示頁面   Render
卸載頁面 Unload  

以上所列的階段中有些在頁面級是不可見的,而且僅對服務器控件的編寫者和要建立從 Page 導出的類的開發人員有意義。InitLoadPreRenderUnload,再加上由嵌入式控件定義的全部回發事件,就構成了向外發送頁面的各個階段標記。

執行的各個階段

頁面生命週期中的第一個階段是初始化。這個階段的標誌是 Init 事件。在成功建立頁面的控件樹後,將對應用程序觸發此事件。換句話說,當 Init 事件發生時,.aspx 源文件中靜態聲明的全部控件都已實例化並採用各自的默認值。控件能夠截取 Init 事件以初始化在傳入的 Web 請求的生命週期內所需的全部設置。例如,這時控件能夠加載外部模板文件或設置事件的處理程序。請注意,這時視圖狀態信息尚不可用。

初始化以後,頁面框架將加載頁面的視圖狀態。視圖狀態是名稱/值對的集合,在此集合中,控件和頁面自己存儲了對全部 Web 請求都必須始終有效的所有信息。視圖狀態表明瞭頁面的調用上下文。一般,它包含上次在服務器上處理頁面時控件的狀態。首次在會話中請求頁面時,視圖狀態爲空。默認狀況下,視圖狀態存儲在靜默添加到頁面的隱藏字段中,該字段的名稱是 __VIEWSTATE。經過覆蓋 LoadViewState 方法(Control 類的受保護、可覆蓋方法),組件開發人員能夠控制視圖狀態的存儲方式以及視圖狀態的內容映射到內部狀態的方式。

有些方法(如 LoadPageStateFromPersistenceMedium 以及其對應的 SavePageStateToPersistenceMedium),能夠用來將視圖狀態加載並保存到其餘存儲介質(例如會話、數據庫或服務器端文件)中。與 LoadViewState 不一樣,上述方法只能在從 Page 導出的類中使用。

存儲視圖狀態以後,頁面樹中控件的狀態與頁面最後一次顯示在瀏覽器中的狀態相同。下一步是更新它們的狀態以加入客戶端的更改。處理回發數據階段使控件有機會更新其狀態,從而準確反映客戶端相應的 HTML 元素的狀態。例如,服務器的 TextBox 控件對應的 HTML 元素是 <input type=text>。在回發數據階段,TextBox 控件將檢索 <input> 標記的當前值,並使用該值來刷新本身內部的狀態。每一個控件都要從回發的數據中提取值並更新本身的部分屬性。TextBox 控件將更新它的 Text 屬性,而 CheckBox 控件將刷新它的 Checked 屬性。服務器控件和 HTML 元素的對應關係能夠經過兩者的 ID 找到。

在處理回發數據階段的最後,頁面中的全部控件的狀態都將使用客戶端輸入的更改來更新前一狀態。這時,將對頁面觸發 Load 事件。

頁面中可能會有一些控件,當其某個敏感屬性在兩個不一樣的請求中被修改時,須要完成特定的任務。例如,若是 TextBox 控件的文本在客戶端被修改,則此控件將觸發 TextChanged 事件。每一個控件在其一個或多個屬性被修改成客戶端輸入的值時均可以決定觸發相應的事件。對於這些更改對其很是關鍵的控件,控件實現 IPostBackDataHandler 接口,此接口的 LoadPostData 方法是在 Load 事件後當即調用的。經過對 LoadPostData 方法進行編碼,控件將驗證自上次請求後是否發生了關鍵更改,並觸發本身的更改事件。

頁面生命週期中的關鍵事件是被調用以執行服務器端代碼的事件,此代碼與客戶端觸發的事件相關聯。當用戶單擊按鈕時,將回發頁面。回發值的集合中包括啓動整個操做的按鈕的 ID。若是控件實現 IPostBackEventHandler 接口(如按鈕和連接按鈕),頁面框架將調用 RaisePostBackEvent 方法。此方法的行爲取決於控件的類型。就按鈕和連接按鈕而言,此方法將查找 Click 事件處理程序並運行相關的委託。

處理完回發事件以後,頁面就能夠顯示了。這個階段的標誌是 PreRender 事件。控件能夠利用這段時間來執行那些須要在保存視圖狀態和顯示輸出的前一刻執行的更新操做。下一個狀態是 SaveViewState,在此狀態中,全部控件和頁面自己都將更新本身 ViewState 集合的內容。而後,將獲得序列化、散列、Base64 編碼的視圖狀態,並且此視圖狀態與隱藏字段 __VIEWSTATE 相關聯。

經過覆蓋 Render 方法能夠改變各個控件的顯示機制。此方法接受 HTML 書寫器對象,並使用此對象來積累全部要爲控件生成的 HTML 文本。Page 類的 Render 方法的默認實現包括對全部成員控件的遞歸調用。對於每一個控件,頁面都將調用 Render 方法,並緩存 HTML 輸出。

頁面生命中的最後一個標誌是 Unload 事件,在頁面對象消除以前發生。在此事件中,您應該釋放全部可能佔用的關鍵資源(例如文件、圖形對象、數據庫鏈接等)。

在此事件以後,也就是最後,瀏覽器接收 HTTP 響應數據包並顯示頁面。

小結

ASP.NET 頁面對象模型因其事件機制而顯得格外新穎獨特。Web 頁面由控件組成,這些控件既能夠產生豐富的基於 HTML 的用戶界面,又能夠經過事件與用戶交互。之前,在 Web 應用程序的上下文中設置事件模型是件有挑戰性的工做。可咱們驚奇的看到,客戶端生成的事件能夠由服務器端的代碼來解決,並且只進行一些相應的修改後,此過程仍能夠輸出相同的 HTML 頁面。

掌握這個模型對於瞭解頁面生命週期的各個階段,以及頁面對象如何被 HTTP 運行時實例化並使用是很是重要的。

關於做者

Dino Esposito 是一位來自意大利羅馬的培訓教師和顧問。做爲 Wintellect 團隊的成員,Dino 專門研究 ASP.NET 和 ADO.NET,主要在歐洲和美國從事教學和諮詢工做。此外,Dino 還負責管理 Wintellect 的 ADO.NET 課件,併爲 MSDN 期刊的「Cutting Edge」專欄撰寫文章。要與他聯繫,請向 dinoe@wintellect.com 發送電子郵件。

相關文章
相關標籤/搜索