深入講解 ASP+ 驗證 (轉自ms 一)
2024-05-04 11:06:24
供稿:網(wǎng)友
深入講解 asp+ 驗證
anthony moore
microsoft corporation
2000年10月
摘要:有關使用 asp+ 驗證 web 控件的詳細講解。
目錄
簡介
入門
何時發(fā)生何事?
服務器端的驗證序列
客戶端的驗證
有效性規(guī)則和有用的錯誤信息
enabled、visible 和 display 屬性的作用
customvalidator 控件
哪些控件可以被驗證?
到此為止
--------------------------------------------------------------------------------
簡介
這篇文章詳細講解了 asp+ 驗證控件的工作方式。如果要生成其中包含驗證控件的復雜頁面,或是要擴展驗證框架,建議您閱讀本文。如果要學習使用驗證控件,或是要決定是否使用驗證控件,請參見“asp+ 中的用戶輸入驗證(英文)”。
入門
我們知道,在整個 asp+ 開發(fā)過程中,了解驗證非常重要。看看如今的大多數(shù)商業(yè) web 站點,您會發(fā)現(xiàn),這些站點中有許多表單,這些表單明顯是通過執(zhí)行大量手寫的代碼來執(zhí)行驗證。編寫驗證代碼并不是一件有趣的工作。如果要通過編寫代碼來顯示數(shù)據(jù)表或動態(tài)生成圖表,可能會很吸引人,但是沒有人可以向他的同事證實這種很“酷”的方法能夠禁止在姓名字段中輸入空值。
因為其它一些原因,web 應用程序的驗證也是非常麻煩的。html 3.2 對您可以控制的內容或可以從用戶處得到的反饋的限制很多,因此無法應用在功能更全的客戶機上可以使用的技巧,例如禁止用戶輸入某些字符,或發(fā)出嘀聲。使用瀏覽器腳本可能會產生更強大的驗證。但是這種方法很難得以證實,因為客戶瀏覽器中并非一定有腳本,并且惡意的用戶可以繞過。因此,為了保證站點安全,有必要對服務器進行同樣的檢查。
在開發(fā) asp+ 時,我們的初衷是只使用一個控件來處理驗證,可能本該是一個能夠顯示錯誤的 textbox 控件。可是到了設計該控件時,卻發(fā)現(xiàn)無法實現(xiàn)這種愿望。我們研究了大量的數(shù)據(jù)輸入表單,試圖找到可以適用于盡可能多的表單的一種解決方案。我們發(fā)現(xiàn),數(shù)據(jù)輸入表單具有許多有趣的特性:
盡管錯誤信息或圖標經(jīng)常與輸入元素相鄰,但是它們幾乎總是位于表的不同單元格中。
頁面中經(jīng)常會有一個區(qū)域來匯總所有錯誤。
許多站點包含客戶端腳本,以便提供更快捷的反饋,同時防止白白地在與服務器之間往返。
許多包含客戶端腳本的站點在出現(xiàn)錯誤時會顯示信息框。
不僅會驗證文本輸入,還會驗證下拉列表和單選按鈕。
如果某個字段為空,站點通常會顯示與該條目無效時不同的信息或圖標。
許多有效性檢查可以很好地代替常用的表達式。
驗證通常是基于兩個輸入之間的比較結果。
90% 或 90% 以上的驗證任務是一些常見的操作,例如檢查姓名或郵政編碼。大多數(shù)站點似乎仍在重復進行這些工作。
因為站點之間的差別通常太大,無法獲得一種完美的解決方案來處理每個站點的所有驗證任務。
考慮了上述所有情況,最終獲得的解決方案包括五個驗證器控件、validationsummary 控件以及與 page 對象的集成。同時很明顯,該解決方案需要擴展,在客戶機和服務器上均需要有一個 api 來配合。
我們在研究進行的各種驗證時發(fā)現(xiàn),我們似乎需要一個更大的工具箱。在大多數(shù)組件環(huán)境中,例如 microsoft® activex®,我們可能本來試圖將所有驗證控件的功能集成到一個控件中,處理不同模式下的不同屬性。不過,幸好 microsoft® .net 框架中有神奇的繼承性,可以提供一套控件來對特定的屬性進行特定的驗證,因為派生每個新控件所需的額外工作量非常小。
這些控件所完成的大多數(shù)工作均在其公用的父級 basevalidator 中實現(xiàn)。您也可以從 basevalidator 或其它控件派生來完成各項工作。實際上,即使 basevalidator 都懶得實現(xiàn)其自己的 text 屬性,而是從 label 屬性繼承。
何時發(fā)生何事?
在處理包含驗證 web 控件的頁面時,了解事件序列非常有效。如果某個驗證條件是可選的,您需要準確了解客戶機和服務器上何時進行驗證。如果要自己編寫驗證例程,可能會非常耗時,或者有副作用。同時,了解調用驗證例程的時機也很重要。
首先,讓我們看一下服務器。
服務器端的驗證序列
了解頁面的有效期非常重要。如果習慣于在 visual basic 或類似功能齊全的客戶機工具中處理表單,則需要花一定的時間來了解。頁面和頁面上的所有對象并非在與用戶交互時一直有效,盡管有時表面上是這樣。
以下是在第一次訪問某個頁面時一個簡化的事件序列:
基于 aspx 文件創(chuàng)建頁面及其控件。
觸發(fā) page_load 事件。
頁面和控件屬性保存在一個隱藏字段中。
頁面和控件轉換到 html。
丟棄所有內容。
現(xiàn)在,當用戶單擊某個按鈕或類似控件時,將返回服務器,然后執(zhí)行一個類似的事件序列。該序列稱為返回序列:
基于 aspx 文件創(chuàng)建頁面及其控件。
從隱藏字段恢復頁面和控件屬性。
根據(jù)用戶輸入更新頁面控件。
觸發(fā) page_load 事件。
觸發(fā)更改通知事件。
頁面和控件屬性保存在一個隱藏字段中。
頁面和控件轉換到 html。
再次丟棄所有內容。
我們?yōu)槭裁床粚⑺袑ο蟊A粼趦却嬷心兀恳驗槭褂?asp+ 建立的 web 站點無法處理數(shù)量非常大的用戶。因此,服務器的內存中只保留馬上要處理的內容。
何時進行服務器端驗證?在第一次獲取頁面信息時,根本不會進行服務器端驗證。大多數(shù)最終用戶都非常認真,我們允許用戶自己確認在表單中填寫的信息是否正確,然后我們再使用紅色的文字通知用戶填錯的信息。
在返回事件序列中,第 3 步和第 4 步之間會進行驗證。也就是說,進行驗證是在來自用戶的數(shù)據(jù)裝回控件屬性后,但在大多數(shù)代碼執(zhí)行之前。這意味著在編寫用戶事件代碼時,通常可以利用已經(jīng)進行的驗證。一般情況下,您都會希望這樣做。
在該時刻進行驗證的缺點是:如果您要通過編程來修改某些影響該驗證的屬性,該時刻就太遲了。例如,您會發(fā)現(xiàn),如果通過編寫代碼來啟用或禁用驗證控件或更改驗證控件的屬性,在下一次處理該頁之前,不會看到任何影響。通過以下兩種方法可以避免這個問題:
在進行驗證之前修改屬性。
在屬性更改之后重新驗證控件。
這兩種方法均需要使用在 page 對象上有效的驗證屬性和方法。
頁面 api
page 對象包含一些與服務器端驗證有關的重要屬性和方法。表 1 中總結了這些屬性和方法:
表 1. page 對象的屬性和方法
屬性或方法 說明
isvalid 屬性 這是最有用的屬性。該屬性可以檢查整個表單是否有效。通常在更新數(shù)據(jù)庫之前進行該檢查。只有 validators 集中的所有對象全部有效,該屬性才為真,并且不將該值存入緩存。
validators 屬性 該頁所有驗證對象的集合。這是實現(xiàn) ivalidator 界面的對象的集合。
validate 方法 在驗證時調用的一種方法。在 page 對象上默認的執(zhí)行方式是轉至每個驗證器,并要求各驗證器自行評估。
validators 集合對于許多任務都非常有用。該集合是實現(xiàn) ivalidator 界面的對象的集合。我之所以使用對象這個詞,而不是使用控件,是因為 page 對象只關注 ivalidator 界面。既然所有的驗證器通常都是用來實現(xiàn) ivalidator 的一些可視化控件,那么任何人都應能夠使用任意的驗證對象,并將驗證對象加入頁面中。
ivalidator 界面包含以下屬性和方法:
表 2. ivalidator 界面的屬性和方法
屬性或方法 說明
isvalid 屬性 指出單獨的驗證對象進行的有效性檢查是否已經(jīng)通過。您可以在驗證后手工更改該值。
errormessage 屬性 介紹驗證對象要驗證的錯誤以及可能會向用戶顯示的錯誤。
validate 方法 對驗證對象執(zhí)行有效性檢查,以更新其 isvalid 值。
您可以使用該界面執(zhí)行一些有趣的任務。例如,要將頁面重置為有效的狀態(tài),請使用以下代碼(如 c# 中的示例所示):
ivalidator val;
foreach(val in validators) {
val.isvalid = true;
}
要重新執(zhí)行整個驗證序列,請使用以下代碼:
ivalidator val;
foreach(val in validators) {
val.validate();
}
如果有 beta 1 版或更高版本,也可以只對 page 對象調用 validate 方法,這樣可以完成相同的任務。要在驗證前進行某些更改,可以覆蓋 validate 方法。本例顯示一個包含驗證器的頁面,其中的驗證器根據(jù)復選框的值開或關:
public class conditional : page {
public htmlinputcheckbox chksameas;
public requiredfieldvalidator rfvalshipaddress;
protected override void validate() {
//只檢查到貨地址(如果與付款地址不同)
bool enableship = !chksameas.checked;
rfvalshipaddress.enabled = enableship;
//現(xiàn)在執(zhí)行驗證
base.validate();
}
}
客戶端的驗證
如果您的頁面啟用了客戶端驗證,則在往返過程中會發(fā)生完全不同的事件序列。客戶端的驗證使用客戶端 jscript® 實現(xiàn)。實現(xiàn)該驗證不需要任何二進制組件。
盡管 jscript 語言的標準化做得很好,但是用于與瀏覽器中的 html 文檔交互的文檔對象模型 (document object model, dom) 沒有廣泛采用的標準。因此,客戶端的驗證只在 internet explorer 4.0 和更高版本中進行,因為該驗證的對象是 internet explorer dom。
從服務器的角度來說,客戶端的驗證只意味著驗證控件將不同的內容發(fā)送到 html 中。除此之外,其事件序列完全相同。服務器端的檢查仍然執(zhí)行。盡管看起來似乎多余,但是卻十分重要,因為:
某些驗證控件可能不支持客戶端腳本。有一個很好的例子:如果要同時使用 customvalidator 和服務器驗證函數(shù),但是沒有客戶機驗證函數(shù)。
安全性注意事項。某些人可以很容易得到一個包含腳本的頁面,然后禁用或更改該頁面。您不應利用腳本來阻止壞數(shù)據(jù)進入您的系統(tǒng),而只應是為了用戶得到更快的反饋。因此,如果要使用 customvalidator,則不應提供沒有相應服務器驗證函數(shù)的客戶機驗證函數(shù)。
每個驗證控件都可以確保將一個標準的客戶端腳本塊發(fā)送到頁面中。實際上,這只是一小部分代碼,其中包含對腳本庫 webuivalidation.js 中的代碼的引用。這個腳本庫文件包含客戶端驗證的所有邏輯,該文件需單獨下載,并且可以存儲在瀏覽器的緩存中。
關于腳本庫
因為驗證 web 控件腳本在腳本庫中,所以不必將所有客戶端驗證的代碼直接發(fā)送到頁面中,盡管表面上似乎是這樣做的。主要的腳本文件引用類似如下所示:
<script language="javascript"
src="/_aspx/1.0.9999/script/webuivalidation.js"></script>
默認情況下,腳本文件將安裝在 "_aspx" 目錄中默認的根目錄下,并使用相對于根的腳本 include 指令調用,該指令以正斜線開頭。該引用表明每個單獨的對象不必包含腳本庫,同一臺計算機上的所有頁面可以引用同一個文件。您會注意到,該路徑中還有一個公用的語言運行時版本號,以便不同的運行時版本可以在同一臺計算機上運行。
如果查看一下您默認的虛擬根目錄,您會找到該文件并查看其中的內容。這些文件的位置在 config.web 文件中指定。config.web 文件是一個用于大多數(shù) asp+ 設置的 xml 文件。以下是該文件中位置的定義:
<webcontrols
clientscriptslocation="/_aspx/{0}/script/"
/>
鼓勵您閱讀該腳本,以便深入了解發(fā)生的事件。不過,建議您不要修改這些腳本,因為它們的功能與特定的運行時版本緊密相連。在運行時版本更新時,這些腳本可能也需要相應的更新,您將或者放棄更改,或者面臨腳本不工作的問題。如果特定項目必須更改這些腳本,先備份這些腳本,然后將您的項目指向備份文件,方法是使用私有的 config.web 文件替代這些文件的位置。如果字符串中包含格式指令 "{0}",運行時版本號將替換該指令。最好將該位置更改為一個相對引用或絕對引用。
禁用客戶端的驗證
有時您可能不希望進行客戶端驗證。如果輸入字段的數(shù)目很少,客戶端驗證可能用處不大。您畢竟每次都要有一個需要往返服務器一次的邏輯。您會發(fā)現(xiàn)客戶機上動態(tài)出現(xiàn)的信息對您的布局會有負面影響。
要禁用客戶端驗證,應使用 page 指令 "clienttarget=downlevel"。該指令類似以下 aspx 文件的開頭:
<%@ page language="c#" clienttarget=downlevel %>
該指令的默認值為 "auto",表示您只對 microsoft internet explorer 4.0 或更高版本進行客戶端驗證。
注意: 不幸的是,在 beta 1 中,該指令并非僅僅是禁用驗證,同時還會使所有 web 控件使用 html 3.2 標記來處理,這可能會產生意想不到的結果。最終版本提供了更好的方法來控制這個問題。
客戶端事件序列
該序列是在運行包含客戶端驗證的頁面時發(fā)生的事件序列:
在頁面載入瀏覽器時,需要對每個驗證控件進行一些初始化。這些控件作為 <span> 標記發(fā)送,其 html 特性與服務器上的特性最接近。最重要的是,此時會將驗證器引用的所有輸入元素“掛接”。被引用的輸入元素將修改其客戶端事件,以便在每次輸入更改時調用驗證例程。
腳本庫中的代碼將在用戶使用 tab 鍵在各字段之間切換時執(zhí)行。某個獨立的字段更改時,將重新評估驗證條件,根據(jù)需要使驗證器可見或不可見。
當用戶嘗試提交表單時,將重新評估所有驗證器。如果這些驗證器全部有效,表單將提交給服務器。如果存在一處或多處錯誤,則會出現(xiàn)下述情況:
提交被取消。表單并不提交給服務器。
所有無效的驗證器均可見。
如果某個驗證摘要包含 showsummary=true,則將收集來自驗證控件的所有錯誤,并使用這些錯誤更新其內容。
如果某個驗證摘要包含 showmessagebox=true,則將收集錯誤,并在客戶機的信息框中顯示這些錯誤。
因為在每次輸入更改時或提交時會執(zhí)行客戶端驗證控件,所以在客戶機上通常會評估這些驗證控件兩次或兩次以上。請注意,提交后,仍將會在服務器上對這些驗證控件進行重新評估。