驗證 ASP.NET 網頁 (Razor) 網站中的使用者輸入
演講者:Tom FitzMacken
本文討論如何驗證從使用者獲得的資訊,即確保使用者在 ASP.NET 網頁 (Razor) 網站中以 HTML 表單形式輸入有效資訊。
您將學到什麼:
- 如何檢查使用者的輸入是否符合您定義的驗證標準。
- 如何確定是否所有驗證測試都已通過。
- 如何顯示驗證錯誤 (以及如何格式化它們)。
- 如何驗證並非直接來自使用者的資料。
這些就是本文介紹的 ASP.NET 程式設計概念:
Validation
協助程式。Html.ValidationSummary
和Html.ValidationMessage
方法。教學中使用的軟體版本
- ASP.NET 網頁 (Razor) 3
本教學也適用於 ASP.NET 網頁 2。
本文包含下列章節:
使用者輸入驗證概述
如果您要求使用者在頁面中輸入資訊 (例如在表單中),確保他們輸入的值有效非常重要。 例如,您不想處理缺少關鍵資訊的表單。
當使用者在 HTML 表單中輸入值時,他們輸入的值是字串。 在許多情況下,您需要的值是其他一些資料類型,例如整數或日期。 因此,您還必須確保使用者輸入的值可以正確轉換為適當的資料類型。
您可能也對值有某些限制。 例如,即使使用者正確輸入了一個整數,您也可能需要確保該值落在某個範圍內。
注意
重要驗證使用者輸入對於安全性也很重要。 當您限制使用者可以在表單中輸入的值時,您可以減少有人輸入可能危及您網站安全的值的機會。
驗證使用者輸入
在 ASP.NET 網頁 2 中,您可以使用 Validator
協助程式來測試使用者輸入。 基本方法是執行以下操作:
確定您要驗證哪些輸入元素 (欄位)。
您通常會驗證表單中
<input>
元素中的值。 但是,驗證所有輸入是一個很好的做法,甚至是來自<select>
列表等受約束元素的輸入。 這有助於確保使用者不會繞過頁面上的控制項並提交表單。在頁面程式碼中,使用
Validation
協助程式的方法為每個輸入元素新增單獨的驗證檢查。若要檢查必填欄位,請使用
Validation.RequireField(field, [error message])
(對於單一欄位) 或Validation.RequireFields(field1, field2, ...))
(對於欄位列表)。 對於其他類型的驗證,請使用Validation.Add(field, ValidationType)
。 對於ValidationType
,您可以使用以下選項:Validator.DateTime ([error message])
Validator.Decimal([error message])
Validator.EqualsTo(otherField [, error message])
Validator.Float([error message])
Validator.Integer([error message])
Validator.Range(min, max [, error message])
Validator.RegEx(pattern [, error message])
Validator.Required([error message])
Validator.StringLength(length)
Validator.Url([error message])
頁面提交後,檢查
Validation.IsValid
驗證是否通過:if(IsPost && Validation.IsValid()){ // Process form submit }
如果有任何驗證錯誤,您將跳過正常的頁面處理。 例如,如果頁面的目的是更新程式庫,則在修復所有驗證錯誤之前不要執行此操作。
如果存在驗證錯誤,請使用
Html.ValidationSummary
或Html.ValidationMessage
或兩者在頁面標記中顯示錯誤訊息。
以下範例顯示了一個說明這些步驟的頁面。
@{
var message="";
// Specify validation requirements for different fields.
Validation.RequireField("coursename", "Class name is required");
Validation.RequireField("credits", "Credits is required");
Validation.Add("coursename", Validator.StringLength(5));
Validation.Add("credits", Validator.Integer("Credits must be an integer"));
Validation.Add("credits", Validator.Range(1, 5, "Credits must be between 1 and 5"));
Validation.Add("startDate", Validator.DateTime("Start date must be a date"));
if (IsPost) {
// Before processing anything, make sure that all user input is valid.
if (Validation.IsValid()) {
var coursename = Request["coursename"];
var credits = Request["credits"].AsInt();
var startDate = Request["startDate"].AsDateTime();
message += @"For Class, you entered " + coursename;
message += @"<br/>For Credits, you entered " + credits.ToString();
message += @"<br/>For Start Date, you entered " + startDate.ToString("dd-MMM-yyyy");
// Further processing here
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Validation Example</title>
<style>
body {margin: 1in; font-family: 'Segoe UI'; font-size: 11pt; }
</style>
</head>
<body>
<h1>Validation Example</h1>
<p>This example page asks the user to enter information about some classes at school.</p>
<form method="post">
@Html.ValidationSummary()
<div>
<label for="coursename">Course name: </label>
<input type="text"
name="coursename"
value="@Request["coursename"]"
/>
@Html.ValidationMessage("coursename")
</div>
<div>
<label for="credits">Credits: </label>
<input type="text"
name="credits"
value="@Request["credits"]"
/>
@Html.ValidationMessage("credits")
</div>
<div>
<label for="startDate">Start date: </label>
<input type="text"
name="startDate"
value="@Request["startDate"]"
/>
@Html.ValidationMessage("startDate")
</div>
<div>
<input type="submit" value="Submit" class="submit" />
</div>
<div>
@if(IsPost){
<p>@Html.Raw(message)</p>
}
</div>
</form>
</body>
</html>
要了解驗證的工作原理,請執行此頁面並故意犯錯。 例如,如果您忘記輸入課程名稱、輸入 an 以及輸入無效日期,則頁面如下所示:
新增用戶端驗證
預設情況下,使用者輸入在使用者提交頁面後進行驗證——也就是說,驗證是在伺服器程式碼中執行的。 這種方法的缺點是使用者直到提交頁面後才知道自己犯了錯誤。 如果表單很長或很複雜,則僅在提交頁面後報告錯誤可能會對使用者造成不便。
您可以新增支援以在用戶端程式碼中執行驗證。 在這種情況下,驗證是在使用者在瀏覽器中工作時執行的。 例如,假設您指定一個值應該是整數。 如果使用者輸入非整數值,則一旦使用者離開輸入欄位,就會報告錯誤。 用戶可以獲得即時回饋,這對他們來說很方便。 基於用戶端的驗證還可以減少使用者必須提交表單以更正多個錯誤的次數。
注意
即使您使用用戶端驗證,驗證也始終在伺服器程式碼中執行。 在伺服器程式碼中執行驗證是一種安全措施,以防使用者繞過基於用戶端的驗證。
在頁面中註冊以下 JavaScript 程式庫:
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js"> </script> <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.8.1/jquery.validate.js"> </script> <script src="~/Scripts/jquery.validate.unobtrusive.js"> </script>
其中兩個庫可從內容交付網路 (CDN) 加載,因此您不必將它們放在電腦或伺服器上。 但是,您必須擁有 jquery.validate.unobtrusive.js 的本機副本。 如果您尚未使用包含該程式庫的 WebMatrix 範本 (例如 Starter Site),請建立一個基於 Starter Site 的網頁網站。 然後將 .js 檔案複製到您目前的網站。
在標記中,對於您要驗證的每個元素,請新增對
Validation.For(field)
的呼叫。 此方法發出用戶端驗證使用的屬性。 (該方法不是發出實際的 JavaScript 程式碼,而是發出諸如data-val-...
之類的屬性。這些屬性支援使用 jQuery 完成工作的不顯眼的用戶端驗證。)
下頁顯示如何將用戶端驗證功能新增至前面顯示的範例。
@{
// Note that client validation as implemented here will work only with
// ASP.NET Web Pages 2.
var message="";
// Specify validation requirements for different fields.
Validation.RequireField("coursename", "Class name is required");
Validation.RequireField("credits", "Credits is required");
Validation.Add("coursename", Validator.StringLength(5));
Validation.Add("credits", Validator.Integer("Credits must be an integer"));
Validation.Add("credits", Validator.Range(1, 5, "Credits must be between 1 and 5"));
Validation.Add("startDate", Validator.DateTime("Start date must be a date"));
if (IsPost) {
// Before processing anything, make sure that all user input is valid.
if (Validation.IsValid()) {
var coursename = Request["coursename"];
var credits = Request["credits"].AsInt();
var startDate = Request["startDate"].AsDateTime();
message += @"For Class, you entered " + coursename;
message += @"<br/>For Credits, you entered " + credits.ToString();
message += @"<br/>For Start Date, you entered " + startDate.ToString("dd-MMM-yyyy");
// Further processing here
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Validation Example with Client Validation</title>
<style>
body {margin: 1in; font-family: 'Segoe UI'; font-size: 11pt; }
</style>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js"></script>
<script
src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.8.1/jquery.validate.js">
</script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
</head>
<body>
<h1>Validation Example with Client Validation</h1>
<p>This example page asks the user to enter information about some classes at school.</p>
<form method="post">
@Html.ValidationSummary()
<div>
<label for="coursename">Course name: </label>
<input type="text"
name="coursename"
value="@Request["coursename"]"
@Validation.For("coursename")
/>
@Html.ValidationMessage("coursename")
</div>
<div>
<label for="credits">Credits: </label>
<input type="text"
name="credits"
value="@Request["credits"]"
@Validation.For("credits")
/>
@Html.ValidationMessage("credits")
</div>
<div>
<label for="startDate">Start date: </label>
<input type="text"
name="startDate"
value="@Request["startDate"]"
@Validation.For("startDate")
/>
@Html.ValidationMessage("startDate")
</div>
<div>
<input type="submit" value="Submit" class="submit" />
</div>
<div>
@if(IsPost){
<p>@Html.Raw(message)</p>
}
</div>
</form>
</body>
</html>
並非所有驗證檢查都在用戶端上執行。 特別是,資料類型驗證 (整數和日期等) 不在用戶端上執行。 以下檢查在用戶端和伺服器上均有效:
Required
Range(minValue, maxValue)
StringLength(maxLength[, minLength])
Regex(pattern)
EqualsTo(otherField)
在此範例中,有效日期的測試在用戶端程式碼中不起作用。 但是,測試將在伺服器程式碼中執行。
格式驗證錯誤
您可以透過定義具有以下保留名稱的 CSS 類別來控制驗證錯誤的顯示方式:
field-validation-error
. 定義Html.ValidationMessage
方法顯示錯誤時的輸出。field-validation-valid
. 定義沒有錯誤時Html.ValidationMessage
方法的輸出。input-validation-error
. 定義出現錯誤時<input>
元素的呈現方式。 (例如,如果<輸入>元素的值無效,您可以使用此類將其背景顏色設定為不同的顏色。) 此 CSS 類別僅在用戶端驗證期間使用 (在 ASP.NET 網頁 2 中)。input-validation-valid
. 定義沒有錯誤時<input>
元素的外觀。validation-summary-errors
. 定義顯示錯誤清單的Html.ValidationSummary
方法的輸出。validation-summary-valid
. 定義沒有錯誤時Html.ValidationSummary
方法的輸出。
以下 <style>
區塊顯示了錯誤條件的規則。
<style>
.validation-summary-errors {
border:2px solid red;
color:red;
font-weight:bold;
margin:6px;
width:30%;
}
.field-validation-error{
color:red;
font-weight:bold;
background-color:yellow;
}
.input-validation-error{
color:red;
font-weight:bold;
background-color:pink;
}
</style>
如果您在本文前面的範例頁面中包含此樣式區塊,則錯誤顯示將如下圖所示:
注意
如果您未在 ASP.NET Web Pages 2 中使用用戶端驗證,則<input>
元素 (input-validation-error
和 input-validation-valid
) 的 CSS 類別不會產生任何效果。
靜態和動態錯誤顯示
CSS 規則成對出現,例如 validation-summary-errors
和 validation-summary-valid
。 這些對允許您定義兩種條件的規則:錯誤條件和「正常」(非錯誤) 條件。 重要的是要理解,即使沒有錯誤,錯誤顯示的標記也始終會呈現。 例如,如果頁面的標記中有 Html.ValidationSummary
方法,則即使第一次要求該頁面,頁面來源也將包含以下標記:
<div class="validation-summary-valid" data-valmsg-summary="true"><ul></ul></div>
換句話說,即使錯誤列表為空,Html.ValidationSummary
方法也始終呈現一個 <div>
元素和一個列表。 同樣,即使沒有錯誤,Html.ValidationMessage
方法也始終將 <span>
元素呈現為單一欄位錯誤的佔位符。
在某些情況下,顯示錯誤訊息可能會導致頁面回流並導致頁面上的元素四處移動。 以 -valid
結尾的 CSS 規則可讓您定義有助於防止此問題的佈局。 例如,您可以定義 field-validation-error
和 field-validation-valid
使其具有相同的固定大小。 這樣,欄位的顯示區域是靜態的,如果顯示錯誤訊息,也不會變更頁面流程。
驗證不直接來自使用者的資料
有時您必須驗證並非直接來自 HTML 表單的資訊。 一個典型的範例是在查詢字串中傳遞值的頁面,如下例所示:
http://server/myapp/EditClassInformation?classid=1022
在本例中,您需要確保傳遞到頁面的值 (此處 classid
的值是 1022) 有效。 您無法直接使用 Validation
協助程式來執行此驗證。 但是,您可以使用驗證系統的其他功能,例如顯示驗證錯誤訊息的功能。
注意
重要始終驗證從 任何來源取得的值,包括表單欄位值、查詢字串值和 cookie 值。 人們很容易改變這些值 (可能是出於惡意目的)。 因此,您必須檢查這些值以保護您的應用程式。
以下範例顯示如何驗證在查詢字串中傳遞的值。 該程式碼測試該值是否不為空並且它是一個整數。
if(!IsPost){
if(!Request.QueryString["classid"].IsEmpty() && Request.QueryString["classid"].IsInt()) {
// Process the value
}
else{
Validation.AddFormError("No class was selected.");
}
}
請注意,測試是在請求不是表單提交 (if(!IsPost)
) 時執行的。 該測試將在第一次請求頁面時通過,但當請求是表單提交時則不會通過。
若要顯示此錯誤,您可以透過呼叫 Validation.AddFormError("message")
將錯誤新增至驗證錯誤清單中。 如果頁麵包含對 Html.ValidationSummary
方法的調用,則會在那裡顯示錯誤,就像使用者輸入驗證錯誤一樣。