ASP.NET Web ページ (Razor) サイトでのユーザー入力の検証
作成者: Tom FitzMacken
この記事では、ユーザーから取得した情報の検証 — つまり、ユーザーが ASP.NET Web ページ (Razor) サイトで HTML フォームに有効な情報を入力していることを、確認する方法について説明します。
ここでは、次の内容について学習します。
- ユーザーの入力が、定義した検証基準と一致していることを確認する方法。
- すべての検証テストに合格したかどうかを確認する方法。
- 検証エラーを表示する方法 (および、それらの書式を設定する方法)。
- ユーザーから直接入力されていないデータを検証する方法。
これらの ASP.NET プログラミングの概念は、次の記事で紹介されています。
Validation
ヘルパー。Html.ValidationSummary
メソッドとHtml.ValidationMessage
メソッド。チュートリアルで使用するソフトウェアのバージョン
- ASP.NET Web ページ (Razor) 3
このチュートリアルは、ASP.NET Web ページ 2 にも適用できます。
この記事は、次のセクションで構成されています。
ユーザーによる入力の検証の概要
ユーザーにページへの情報の入力 (たとえば、フォームへの入力) を要求する場合は、入力された値が有効であることを確認することが重要です。 たとえば、重要な情報が不足しているフォームを処理することは避けたいでしょう。
ユーザーが HTML フォームに値を入力する場合、そこで入力される値は文字列です。 多くの場合、必要とされている値は、整数や日付などの他のデータ型です。 そのため、ユーザーが入力した値が適切なデータ型に正しく変換されるようにする必要もあります。
また、値に特定の制限があることもあります。 たとえユーザーが正しく整数を入力した場合であっても、その値が特定の範囲内にあることを確認する必要はあるでしょう。
Note
重要 ユーザー入力の検証は、セキュリティにとっても重要です。 ユーザーがフォームに入力できる値を制限すると、サイトのセキュリティを損なう可能性のある値を、誰かが入力できてしまうという可能性を低くできます。
ユーザー入力の検証
ASP.NET Web ページ 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>
検証のしくみを確認するには、このページを実行し、意図的に間違いを発生させます。 たとえば、コース名の入力を忘れた場合、サポートされないクレジット番号および無効な日付を入力した場合には、このページの外観は次のようになります。
クライアント側の検証の追加
既定では、ユーザーによる入力は、ユーザーがページを送信した後に検証されます。つまり、検証はサーバー コードで実行されます。 このアプローチの欠点は、ユーザーが、ページを送信するまでエラーが発生したことを認識できないということです。 フォームが長い場合や複雑な場合、ページが送信された後にのみエラーを報告することは、ユーザーの利便性を損なうことになり得ます。
クライアント スクリプトの中に、検証を実行するためのサポートを追加できます。 その場合、検証は、ユーザーがブラウザーを操作しているときに実行されます。 たとえば、値に整数を想定している場合を考えます。 ユーザーが整数以外の値を入力すると、ユーザーがその入力フィールドを離れるとすぐにエラーが報告されます。 ユーザーは即座にフィードバックを受け取れるので便利です。 クライアント ベースの検証は、複数のエラーを修正するためにユーザーに要求される、フォームの送信回数を減らすこともできます。
Note
クライアント側の検証を使用する場合も、検証はサーバー コードで常に実行されます。 サーバー コードでの検証の実行は、ユーザーがクライアント ベースの検証をバイパスする場合のセキュリティ対策です。
ページに次の 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>
この 2 つのライブラリは、コンテンツ配信ネットワーク (CDN) から読み込みが可能であるため、必ずしもコンピューターまたはサーバーにライブラリを置く必要はありません。 ただし、jquery.validate.unobtrusive.js のローカル コピーが必要です。 ライブラリを含む WebMatrix テンプレート (Starter Site など ) をまだ使用していない場合は、Starter Site をベースにして Web ページ サイトを作成します。 その後、.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 Web ページ 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>
この記事の前の方で、このスタイル ブロックをページ例の中に含めている場合には、エラー表示は次の図のようになります。
Note
ASP.NET Web ページ 2 でクライアント検証を使用していない場合は、<input>
要素の CSS クラス (input-validation-error
および input-validation-valid
) の効果はありません。
静的および動的なエラー表示
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
ヘルパーを直接使用することはできません。 ただし、検証エラー メッセージを表示する機能など、検証システムの他の機能が使用できます。
Note
重要 フォーム フィールド値、クエリ文字列値、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
メソッドの呼び出しが含まれている場合は、ユーザーによる入力の検証エラーと同様にエラーが表示されます。