程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> 深入講解 ASP+ 驗證

深入講解 ASP+ 驗證

編輯:關於C#
 

這篇文章詳細講解了 ASP+ 驗證控件的工作方式。如果要生成其中包含驗證控件的復雜頁面,或是要擴展驗證框架,建議您閱讀本文。如果要學習使用驗證控件,或是要決定是否使用驗證控件,請參見“ASP+ 中的用戶輸入驗證(英文)”。


入門

我們知道,在整個 ASP+ 開發過程中,了解驗證非常重要。看看如今的大多數商業 Web 站點,您會發現,這些站點中有許多表單,這些表單明顯是通過執行大量手寫的代碼來執行驗證。編寫驗證代碼並不是一件有趣的工作。如果要通過編寫代碼來顯示數據表或動態生成圖表,可能會很吸引人,但是沒有人可以向他的同事證實這種很“酷”的方法能夠禁止在姓名字段中輸入空值。

因為其它一些原因,Web 應用程序的驗證也是非常麻煩的。HTML 3.2 對您可以控制的內容或可以從用戶處得到的反饋的限制很多,因此無法應用在功能更全的客戶機上可以使用的技巧,例如禁止用戶輸入某些字符,或發出嘀聲。使用浏覽器腳本可能會產生更強大的驗證。但是這種方法很難得以證實,因為客戶浏覽器中並非一定有腳本,並且惡意的用戶可以繞過。因此,為了保證站點安全,有必要對服務器進行同樣的檢查。

在開發 ASP+ 時,我們的初衷是只使用一個控件來處理驗證,可能本該是一個能夠顯示錯誤的 TextBox 控件。可是到了設計該控件時,卻發現無法實現這種願望。我們研究了大量的數據輸入表單,試圖找到可以適用於盡可能多的表單的一種解決方案。我們發現,數據輸入表單具有許多有趣的特性:

  • 盡管錯誤信息或圖標經常與輸入元素相鄰,但是它們幾乎總是位於表的不同單元格中。
  • 頁面中經常會有一個區域來匯總所有錯誤。
  • 許多站點包含客戶端腳本,以便提供更快捷的反饋,同時防止白白地在與服務器之間往返。
  • 許多包含客戶端腳本的站點在出現錯誤時會顯示信息框。
  • 不僅會驗證文本輸入,還會驗證下拉列表和單選按鈕。
  • 如果某個字段為空,站點通常會顯示與該條目無效時不同的信息或圖標。
  • 許多有效性檢查可以很好地代替常用的表達式。
  • 驗證通常是基於兩個輸入之間的比較結果。
  • 90% 或 90% 以上的驗證任務是一些常見的操作,例如檢查姓名或郵政編碼。大多數站點似乎仍在重復進行這些工作。
  • 因為站點之間的差別通常太大,無法獲得一種完美的解決方案來處理每個站點的所有驗證任務。

考慮了上述所有情況,最終獲得的解決方案包括五個驗證器控件、ValidationSummary 控件以及與 Page 對象的集成。同時很明顯,該解決方案需要擴展,在客戶機和服務器上均需要有一個 API 來配合。

我們在研究進行的各種驗證時發現,我們似乎需要一個更大的工具箱。在大多數組件環境中,例如 Microsoft® ActiveX®,我們可能本來試圖將所有驗證控件的功能集成到一個控件中,處理不同模式下的不同屬性。不過,幸好 Microsoft® .NET 框架中有神奇的繼承性,可以提供一套控件來對特定的屬性進行特定的驗證,因為派生每個新控件所需的額外工作量非常小。

這些控件所完成的大多數工作均在其公用的父級 BaseValidator 中實現。您也可以從 BaseValidator 或其它控件派生來完成各項工作。實際上,即使 BaseValidator 都懶得實現其自己的 Text 屬性,而是從 Label 屬性繼承。


何時發生何事?

在處理包含驗證 Web 控件的頁面時,了解事件序列非常有效。如果某個驗證條件是可選的,您需要准確了解客戶機和服務器上何時進行驗證。如果要自己編寫驗證例程,可能會非常耗時,或者有副作用。同時,了解調用驗證例程的時機也很重要。

首先,讓我們看一下服務器。


服務器端的驗證序列

了解頁面的有效期非常重要。如果習慣於在 Visual Basic 或類似功能齊全的客戶機工具中處理表單,則需要花一定的時間來了解。頁面和頁面上的所有對象並非在與用戶交互時一直有效,盡管有時表面上是這樣。

以下是在第一次訪問某個頁面時一個簡化的事件序列:

  1. 基於 ASPX 文件創建頁面及其控件。
  2. 觸發 Page_Load 事件。
  3. 頁面和控件屬性保存在一個隱藏字段中。
  4. 頁面和控件轉換到 HTML。
  5. 丟棄所有內容。

現在,當用戶單擊某個按鈕或類似控件時,將返回服務器,然後執行一個類似的事件序列。該序列稱為返回序列:

  1. 基於 ASPX 文件創建頁面及其控件。
  2. 從隱藏字段恢復頁面和控件屬性。
  3. 根據用戶輸入更新頁面控件。
  4. 觸發 Page_Load 事件。
  5. 觸發更改通知事件。
  6. 頁面和控件屬性保存在一個隱藏字段中。
  7. 頁面和控件轉換到 HTML。
  8. 再次丟棄所有內容。

我們為什麼不將所有對象保留在內存中呢?因為使用 ASP+ 建立的 Web 站點無法處理數量非常大的用戶。因此,服務器的內存中只保留馬上要處理的內容。

何時進行服務器端驗證?在第一次獲取頁面信息時,根本不會進行服務器端驗證。大多數最終用戶都非常認真,我們允許用戶自己確認在表單中填寫的信息是否正確,然後我們再使用紅色的文字通知用戶填錯的信息。

在返回事件序列中,第 3 步和第 4 步之間會進行驗證。也就是說,進行驗證是在來自用戶的數據裝回控件屬性後,但在大多數代碼執行之前。這意味著在編寫用戶事件代碼時,通常可以利用已經進行的驗證。一般情況下,您都會希望這樣做。

在該時刻進行驗證的缺點是:如果您要通過編程來修改某些影響該驗證的屬性,該時刻就太遲了。例如,您會發現,如果通過編寫代碼來啟用或禁用驗證控件或更改驗證控件的屬性,在下一次處理該頁之前,不會看到任何影響。通過以下兩種方法可以避免這個問題:

  • 在進行驗證之前修改屬性。
  • 在屬性更改之後重新驗證控件。

這兩種方法均需要使用在 Page 對象上有效的驗證屬性和方法。

頁面 API

Page 對象包含一些與服務器端驗證有關的重要屬性和方法。表 1 中總結了這些屬性和方法:

表 1. Page 對象的屬性和方法

屬性或方法 說明 IsValid 屬性 這是最有用的屬性。該屬性可以檢查整個表單是否有效。通常在更新數據庫之前進行該檢查。只有 Validators 集中的所有對象全部有效,該屬性才為真,並且不將該值存入緩存。 Validators 屬性 該頁所有驗證對象的集合。這是實現 IValidator 界面的對象的集合。 Validate 方法 在驗證時調用的一種方法。在 Page 對象上默認的執行方式是轉至每個驗證器,並要求各驗證器自行評估。
 

Validators 集合對於許多任務都非常有用。該集合是實現 IValidator 界面的對象的集合。我之所以使用對象這個詞,而不是使用控件,是因為 Page 對象只關注 IValidator 界面。既然所有的驗證器通常都是用來實現 IValidator 的一些可視化控件,那麼任何人都應能夠使用任意的驗證對象,並將驗證對象加入頁面中。

IValidator 界面包含以下屬性和方法:

表 2. IValidator 界面的屬性和方法

屬性或方法 說明 IsValid 屬性 指出單獨的驗證對象進行的有效性檢查是否已經通過。您可以在驗證後手工更改該值。 ErrorMessage 屬性 介紹驗證對象要驗證的錯誤以及可能會向用戶顯示的錯誤。 Validate 方法 對驗證對象執行有效性檢查,以更新其 IsValid 值。
 

您可以使用該界面執行一些有趣的任務。例如,要將頁面重置為有效的狀態,請使用以下代碼(如 C# 中的示例所示):

    IValidator val;
    foreach(val in Validators) {
        Val.IsValid = true;
    }

要重新執行整個驗證序列,請使用以下代碼:

    IValidator val;
    foreach(val in Validators) {
        Val.Validate();
    }

如果有 Beta 1 版或更高版本,也可以只對 Page 對象調用 Validate 方法,這樣可以完成相同的任務。要在驗證前進行某些更改,可以覆蓋 Validate 方法。本例顯示一個包含驗證器的頁面,其中的驗證器根據復選框的值開或關:

    public class Conditional : Page {
        public HtmlInputCheckBox chkSameAs;
        public RequiredFieldValidator rfvalShipAddress;

        protected override void Validate() {
            //只檢查到貨地址(如果與付款地址不同)
            bool enableShip = !chkSameAs.Checked;
            rfvalShipAddress.Enabled = enableShip;
            //現在執行驗證
            base.Validate();
        }
    }


客戶端的驗證

如果您的頁面啟用了客戶端驗證,則在往返過程中會發生完全不同的事件序列。客戶端的驗證使用客戶端 JScript® 實現。實現該驗證不需要任何二進制組件。

盡管 JScript 語言的標准化做得很好,但是用於與浏覽器中的 HTML 文檔交互的文檔對象模型 (Document Object Model, DOM) 沒有廣泛采用的標准。因此,客戶端的驗證只在 Internet Explorer 4.0 和更高版本中進行,因為該驗證的對象是 Internet Explorer DOM。

從服務器的角度來說,客戶端的驗證只意味著驗證控件將不同的內容發送到 HTML 中。除此之外,其事件序列完全相同。服務器端的檢查仍然執行。盡管看起來似乎多余,但是卻十分重要,因為:

  • 某些驗證控件可能不支持客戶端腳本。有一個很好的例子:如果要同時使用 CustomValidator 和服務器驗證函數,但是沒有客戶機驗證函數。
  • 安全性注意事項。某些人可以很容易得到一個包含腳本的頁面,然後禁用或更改該頁面。您不應利用腳本來阻止壞數據進入您的系統,而只應是為了用戶得到更快的反饋。因此,如果要使用 CustomValidator,則不應提供沒有相應服務器驗證函數的客戶機驗證函數。

每個驗證控件都可以確保將一個標准的客戶端腳本塊發送到頁面中。實際上,這只是一小部分代碼,其中包含對腳本庫 WebUIValidation.js 中的代碼的引用。這個腳本庫文件包含客戶端驗證的所有邏輯,該文件需單獨下載,並且可以存儲在浏覽器的緩存中。

關於腳本庫

因為驗證 Web 控件腳本在腳本庫中,所以不必將所有客戶端驗證的代碼直接發送到頁面中,盡管表面上似乎是這樣做的。主要的腳本文件引用類似如下所示:

<script language="javascript"      
src="/_aspx/1.0.9999/script/WebUIValidation.js"></script>

默認情況下,腳本文件將安裝在 "_aspx" 目錄中默認的根目錄下,並使用相對於根的腳本 include 指令調用,該指令以正斜線開頭。該引用表明每個單獨的對象不必包含腳本庫,同一台計算機上的所有頁面可以引用同一個文件。您會注意到,該路徑中還有一個公用的語言運行時版本號,以便不同的運行時版本可以在同一台計算機上運行。

如果查看一下您默認的虛擬根目錄,您會找到該文件並查看其中的內容。這些文件的位置在 config.web 文件中指定。config.web 文件是一個用於大多數 ASP+ 設置的 XML 文件。以下是該文件中位置的定義:

    <webcontrols
        clientscriptslocation="/_aspx/{0}/script/"
    />        

鼓勵您閱讀該腳本,以便深入了解發生的事件。不過,建議您不要修改這些腳本,因為它們的功能與特定的運行時版本緊密相連。在運行時版本更新時,這些腳本可能也需要相應的更新,您將或者放棄更改,或者面臨腳本不工作的問題。如果特定項目必須更改這些腳本,先備份這些腳本,然後將您的項目指向備份文件,方法是使用私有的 config.web 文件替代這些文件的位置。如果字符串中包含格式指令 "{0}",運行時版本號將替換該指令。最好將該位置更改為一個相對引用或絕對引用。

禁用客戶端的驗證

有時您可能不希望進行客戶端驗證。如果輸入字段的數目很少,客戶端驗證可能用處不大。您畢竟每次都要有一個需要往返服務器一次的邏輯。您會發現客戶機上動態出現的信息對您的布局會有負面影響。

要禁用客戶端驗證,應使用 Page 指令 "clienttarget=downlevel"。該指令類似以下 ASPX 文件的開頭:

<%@ Page Language="c#" clienttarget=downlevel %>

該指令的默認值為 "auto",表示您只對 Microsoft Internet Explorer 4.0 或更高版本進行客戶端驗證。

注意:   不幸的是,在 Beta 1 中,該指令並非僅僅是禁用驗證,同時還會使所有 Web 控件使用 HTML 3.2 標記來處理,這可能會產生意想不到的結果。最終版本提供了更好的方法來控制這個問題。

客戶端事件序列

該序列是在運行包含客戶端驗證的頁面時發生的事件序列:

  1. 在頁面載入浏覽器時,需要對每個驗證控件進行一些初始化。這些控件作為 <span> 標記發送,其 HTML 特性與服務器上的特性最接近。最重要的是,此時會將驗證器引用的所有輸入元素“掛接”。被引用的輸入元素將修改其客戶端事件,以便在每次輸入更改時調用驗證例程。
  2. 腳本庫中的代碼將在用戶使用 tab 鍵在各字段之間切換時執行。某個獨立的字段更改時,將重新評估驗證條件,根據需要使驗證器可見或不可見。
  3. 當用戶嘗試提交表單時,將重新評估所有驗證器。如果這些驗證器全部有效,表單將提交給服務器。如果存在一處或多處錯誤,則會出現下述情況:
    • 提交被取消。表單並不提交給服務器。
    • 所有無效的驗證器均可見。
    • 如果某個驗證摘要包含 ShowSummary=true,則將收集來自驗證控件的所有錯誤,並使用這些錯誤更新其內容。
    • 如果某個驗證摘要包含 ShowMessageBox=true,則將收集錯誤,並在客戶機的信息框中顯示這些錯誤。

因為在每次輸入更改時或提交時會執行客戶端驗證控件,所以在客戶機上通常會評估這些驗證控件兩次或兩次以上。請注意,提交後,仍將會在服務器上對這些驗證控件進行重新評估。

客戶端 API

有一個可以在客戶機上使用的小型 API,以便在您自己的客戶端代碼中實現各種效果。因為某些例程不可能隱藏,所以理論上講,您可以利用客戶端驗證腳本所定義的所有變量、特性和函數。不過,其中許多都是可以更改的實施細節。以下總結了我們鼓勵您使用的客戶端對象。

表 3. 客戶端對象

名稱 類型 說明 Page_IsValid Boolean 變量 指出頁面當前是否有效。驗證腳本總是保持該變量為最新。 Page_Validators 元素數組 這是包含頁面上所有驗證器的數組。 Page_ValidationActive Boolean 變量 指出是否應進行驗證。將此變量設置為 False 可以通過編程關閉驗證。 isvalid Boolean 屬性 每個客戶端驗證器均具有該屬性,指出驗證器當前是否有效。請注意,在 PDC 版本中,該屬性混用大小寫 ("IsValid")。  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved