モデルに検証を追加する (VB)
作成者: Rick Anderson
このチュートリアルでは、Microsoft Visual Web Developer 2010 Express Service Pack 1 (Microsoft Visual Studio の無料バージョン) を使用した ASP.NET MVC Web アプリケーション構築の基本事項を説明します。 開始する前に、以下に示す前提条件がインストールされていることを確認してください。 次のリンクをクリックすると、これらをすべてインストールできます: Web Platform Installer。 また、次のリンクを使用して前提条件となるソフトウェアを個別にインストールすることもできます。
- Visual Studio Web Developer Express SP1 の前提条件
- ASP.NET MVC 3 Tools Update
- SQL Server Compact 4.0 (ランタイム + ツールのサポート)
Visual Web Developer 2010 ではなく Visual Studio 2010 を使用する場合は、Visual Studio 2010 の前提条件のリンクをクリックして、前提条件をインストールします。
このトピックを学習する際に、VB.NET ソース コードを含む Visual Web Developer プロジェクトを使用できます。 VB.NET バージョンをダウンロードします。 C# を使用する場合は、このチュートリアルの C# バージョンに切り替えてください。
このセクションでは、Movie
モデルに検証ロジックを追加します。また、ユーザーがアプリケーションを使って映画を作成または編集しようとするたびに検証規則が確実に適用されるようにします。
DRY 原則を維持する
ASP.NET MVC の中心となる設計思想の 1 つは、DRY ("Don't Repeat Yourself") です。 ASP.NET MVC では、機能や動作を 1 回だけ指定し、それをアプリケーション内のすべての場所に反映することが奨励されます。 そうすることで、記述が必要になるコードの量が減り、記述するコードの保守はとても簡単になります。
ASP.NET MVC と Entity Framework Code First に用意されている検証サポートは、DRY 原則の実施を示す好例といえます。 検証規則を 1 つの場所 (モデル クラス内) で宣言的に指定すると、その規則はアプリケーション内のすべての場所で適用されます。
映画アプリケーションでこの検証サポートを利用する方法を見てみましょう。
Movie モデルに検証規則を追加する
まず、Movie
クラスにいくつかの検証ロジックを追加します。
Movie.vb ファイルを開きます。 ファイルの上部に、System.ComponentModel.DataAnnotations
名前空間を参照する Imports
ステートメントを追加します。
Imports System.ComponentModel.DataAnnotations
この名前空間は、.NET Framework の一部です。 これにより、任意のクラスまたはプロパティに宣言的に適用できる組み込みの検証属性のセットが提供されます。
次に、組み込みの Required
、StringLength
、Range
検証属性を利用するように Movie
クラスを更新します。 属性を適用する場所の例として、次のコードを使用してください。
Public Class Movie
Public Property ID() As Integer
<Required(ErrorMessage:="Title is required")>
Public Property Title() As String
<Required(ErrorMessage:="Date is required")>
Public Property ReleaseDate() As Date
<Required(ErrorMessage:="Genre must be specified")>
Public Property Genre() As String
<Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
Public Property Price() As Decimal
<StringLength(5)>
Public Property Rating() As String
End Class
検証属性では、適用対象のモデル プロパティに適用する動作を指定します。 Required
属性は、そのプロパティに値を指定する必要があることを示します。このサンプルの場合、ある映画が有効とみなされるためには Title
、ReleaseDate
、Genre
、Price
プロパティの値を指定する必要があります。 Range
属性は、指定した範囲内に値を制限します。 StringLength
属性では、文字列プロパティの最大長を設定でき、オプションとして最小長も設定できます。
アプリケーションが変更をデータベースに保存する前に、Code First によってモデル クラスに対して指定した検証規則が適用されます。 たとえば、次のコードでは、SaveChanges
メソッドが呼び出されたときに例外がスローされます。いくつかの必須の Movie
プロパティ値が指定されておらず、料金が 0 (有効な範囲外) であるためです。
Dim db As New MovieDBContext()
Dim movie As New Movie()
movie.Title = "Gone with the Wind"
movie.Price = 0.0D
db.Movies.Add(movie)
db.SaveChanges() ' <= Will throw validation exception
.NET Framework によって検証規則が自動的に適用されることで、アプリケーションがより堅牢になります。 また、ユーザーが何かを検証することを忘れてしまい、データベースに不適切なデータが誤って格納されることもなくなります。
更新された Movie.vb ファイルの完全なコード リストを次に示します:
Imports System.Data.Entity
Imports System.ComponentModel.DataAnnotations
Public Class Movie
Public Property ID() As Integer
<Required(ErrorMessage:="Title is required")>
Public Property Title() As String
<Required(ErrorMessage:="Date is required")>
Public Property ReleaseDate() As Date
<Required(ErrorMessage:="Genre must be specified")>
Public Property Genre() As String
<Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
Public Property Price() As Decimal
<StringLength(5)>
Public Property Rating() As String
End Class
Public Class MovieDBContext
Inherits DbContext
Public Property Movies() As DbSet(Of Movie)
End Class
ASP.NET MVC の検証エラー UI
アプリケーションを再実行し、/Movies の URL に移動します。
[Create Movie] リンクをクリックして、新しいムービーを追加します。 フォームにいくつかの無効な値を入力し、[Create] ボタンをクリックします。
フォームが自動的に無効なデータを含むテキスト ボックスを背景色によって強調表示し、それぞれの横に適切な検証エラー メッセージを出力していることに注目してください。 エラー メッセージは、Movie
クラスに注釈を付けたときに指定したエラー文字列と一致しています。 エラーは、(JavaScript を使用している) クライアント側とサーバー側 (ユーザーが JavaScript を無効にしている場合) の両方に適用されます。
真の利点は、この検証 UI を有効にするために MoviesController
クラスや Create.vbhtml ビューのコードを 1 行も変更する必要がないということです。 このチュートリアルで前に作成したコントローラーとビューにより、Movie
モデル クラスの属性を使用して指定した検証規則が自動的に採用されます。
Create ビューと Create アクション メソッドで検証が発生するしくみ
コントローラーまたはビューのコードを更新しなくても検証 UI が生成する仕組みが気になるかもしれません。 次のリストは、MovieController
クラス内の Create
メソッドの外観を示しています。 これは、このチュートリアルで前に作成したときから変わっていません。
'
' GET: /Movies/Create
Function Create() As ViewResult
Return View()
End Function
'
' POST: /Movies/Create
<HttpPost()>
Function Create(movie As Movie) As ActionResult
If ModelState.IsValid Then
db.Movies.Add(movie)
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(movie)
End Function
最初のアクション メソッドは、初期の Create フォームを表示します。 2 番目は、フォームの送信を処理します。 2 番目の Create
メソッドは ModelState.IsValid
を呼び出してムービーに検証エラーがあるかどうかを確認します。 このメソッドを呼び出すと、オブジェクトに適用されているすべての検証属性が評価されます。 オブジェクトに検証エラーがある場合、Create
メソッドはフォームを再表示します。 エラーがない場合、メソッドはデータベースに新しいムービーを保存します。
次に示すのは、このチュートリアルで前にスキャフォールディングした Create.vbhtml ビュー テンプレートです。 これは、前に示した両方のアクション メソッドで、初期フォームの表示と、エラー発生時のフォームの再表示に使われます。
@ModelType MvcMovie.Movie
@Code
ViewData("Title") = "Create"
End Code
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@Using Html.BeginForm()
@Html.ValidationSummary(True)
@<fieldset>
<legend>Movie</legend>
<div class="editor-label">
@Html.LabelFor(Function(model) model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Title)
@Html.ValidationMessageFor(Function(model) model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.ReleaseDate)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.ReleaseDate)
@Html.ValidationMessageFor(Function(model) model.ReleaseDate)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.Genre)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Genre)
@Html.ValidationMessageFor(Function(model) model.Genre)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Price)
@Html.ValidationMessageFor(Function(model) model.Price)
</div>
<div class="editor-label">
@Html.LabelFor(Function(model) model.Rating)
</div>
<div class="editor-field">
@Html.EditorFor(Function(model) model.Rating)
@Html.ValidationMessageFor(Function(model) model.Rating)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
End Using
<div>
@Html.ActionLink("Back to List", "Index")
</div>
このコードで、Html.EditorFor
ヘルパーを使用して各 Movie
プロパティの <input>
要素を出力している方法に注目してください。 このヘルパーの隣では、Html.ValidationMessageFor
ヘルパー メソッドを呼び出しています。 これら 2 つのヘルパー メソッドでは、コントローラーからビューに渡されるモデル オブジェクト (この場合は Movie
オブジェクト) が使用されます。 これらは、モデルで指定されている検証属性を自動的に探し、必要に応じてエラー メッセージを表示します。
この方法が非常に優れている点は、コントローラーも Create ビュー テンプレートも、適用される実際の検証規則や表示される特定のエラー メッセージについては何も知らないということです。 検証規則とエラー文字列は、Movie
クラスでのみ指定されています。
検証ロジックを後で変更する場合は、たった 1 か所で変更できます。 アプリケーションの異なる部分で規則の適用方法が一貫しない可能性を心配する必要はありません。すべての検証ロジックは 1 か所で定義され、すべての場所で使われます。 これにより、コードの簡潔さが保たれ、簡単に維持や更新できます。 また、これは DRY 原則に完全に従うことを意味します。
Movie モデルに書式設定を追加する
Movie.vb ファイルを開きます。 System.ComponentModel.DataAnnotations
名前空間には、組み込みの検証属性セットに加え、書式設定の属性もあります。 DisplayFormat
属性と DataType
列挙値をリリース日と価格のフィールドに適用します。 次のコードでは、適切な DisplayFormat
属性が設定された ReleaseDate
プロパティと Price
プロパティを示します。
<DataType(DataType.Date)>
Public Property ReleaseDate() As Date
<DataType(DataType.Currency)>
Public Property Price() As Decimal
または、明示的に DataFormatString
値を設定することもできます。 次のコードは、リリース日のプロパティと日付の書式指定文字列 (つまり "d") を示しています。 これを使うと、時刻をリリース日に含めないように指定することができます。
<DisplayFormat(DataFormatString:="{0:d}")>
Public Property ReleaseDate() As Date
次のコードは、Price
プロパティを通貨として書式設定しています。
<DisplayFormat(DataFormatString:="{0:c}")>
Public Property Price() As Decimal
完全な Movie
クラスを次に示します。
Public Class Movie
Public Property ID() As Integer
<Required(ErrorMessage:="Title is required")>
Public Property Title() As String
<Required(ErrorMessage:="Date is required")>
<DataType(DataType.Date)>
Public Property ReleaseDate() As Date
<Required(ErrorMessage:="Genre must be specified")>
Public Property Genre() As String
<Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
<DataType(DataType.Currency)>
Public Property Price() As Decimal
<StringLength(5)>
Public Property Rating() As String
End Class
アプリケーションを実行し、Movies
コントローラーを参照します。
このシリーズの次のパートでは、アプリケーションを確認し、自動的に生成される Details
および Delete
メソッドに対していくつかの改良を行います。