IDataErrorInfo インターフェイスの検証 (VB)
Stephen Walther が、モデル クラスに IDataErrorInfo インターフェイスを実装して、カスタム検証エラー メッセージを表示する方法について説明します。
このチュートリアルの目的は、ASP.NET MVC アプリケーションで検証を実行するための 1 つのアプローチについて説明することです。 必須フォーム フィールドの値を指定せずに、他のユーザーが HTML フォームを送信できないようにする方法について説明します。 このチュートリアルでは、IErrorDataInfo インターフェイスを使用して検証を実行する方法について説明します。
前提条件
このチュートリアルでは、MoviesDB データベースと Movies データベース テーブルを使用します。 このテーブルには、次の列があります。
列名 | [データ型] | [NULL を許容] |
---|---|---|
Id | int | False |
Title | Nvarchar (100) | False |
監督 | Nvarchar (100) | False |
DateReleased | DateTime | False |
このチュートリアルでは、Microsoft Entity Framework を使用してデータベース モデル クラスを生成します。 Entity Framework によって生成された Movie クラスを図 1 に示します。
図 01: Movie エンティティ (クリックすると、フルサイズの画像が表示されます)
Note
Entity Framework を使用してデータベース モデル クラスを生成する方法の詳細については、チュートリアル「Entity Framework でモデル クラスを作成する」を参照してください。
コントローラー クラス
Home コントローラーを使用してムービーを一覧表示し、新しいムービーを作成します。 このクラスのコードは、リスト 1 に含まれています。
リスト 1 - Controllers\HomeController.vb
Public Class HomeController
Inherits Controller
Private _db As New MoviesDBEntities()
Public Function Index() As ActionResult
Return View(_db.MovieSet.ToList())
End Function
Public Function Create() As ActionResult
Return View()
End Function
<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude := "Id")> ByVal movieToCreate As Movie) As ActionResult
' Validate
If (Not ModelState.IsValid) Then
Return View()
End If
' Add to database
Try
_db.AddToMovieSet(movieToCreate)
_db.SaveChanges()
Return RedirectToAction("Index")
Catch
Return View()
End Try
End Function
End Class
リスト 1 の Home コントローラー クラスには、2 つの Create() アクションが含まれています。 最初のアクションでは、新しいムービーを作成するための HTML フォームが表示されます。 2 番目の Create() アクションは、新しいムービーをデータベースに実際に挿入します。 2 番目の Create() アクションは、最初の Create() アクションによって表示されるフォームがサーバーに送信されると呼び出されます。
2 番目の Create() アクションには、次のコード行が含まれていることに注目してください。
' Validate
If (Not ModelState.IsValid) Then
Return View()
End If
IsValid プロパティは、検証エラーが発生すると false を返します。 その場合、ムービーを作成するための HTML フォームを含む作成ビューが再表示されます。
部分クラスの作成
Movie クラスは Entity Framework によって生成されます。 ソリューション エクスプローラー ウィンドウで MoviesDBModel.edmx ファイルを展開し、コード エディターで MoviesDBModel.Designer.vb ファイルを開くと、Movie クラスのコードが表示されます (図 2 を参照)。
図 02: Movie エンティティのコード (クリックすると、フルサイズの画像が表示されます)
Movie クラスは部分クラスです。 つまり、同じ名前の別の部分クラスを追加して、Movie クラスの機能を拡張できます。 検証ロジックを新しい部分クラスに追加します。
リスト 2 のクラスを Models フォルダーに追加します。
リスト 2 - Models\Movie.vb
Public Partial Class Movie
End Class
リスト 2 のクラスに partial 修飾子が含まれていることに注目してください。 このクラスに追加するすべてのメソッドまたはプロパティは、Entity Framework によって生成された Movie クラスの一部になります。
OnChanging メソッドと OnChanged 部分メソッドの追加
Entity Framework がエンティティ クラスを生成すると、Entity Framework によって部分メソッドが自動的にクラスに追加されます。 Entity Framework は、クラスの各プロパティに対応する OnChanging および OnChanged 部分メソッドを生成します。
Movie クラスの場合、Entity Framework は次のメソッドを作成します。
- OnIdChanging
- OnIdChanged
- OnTitleChanging
- OnTitleChanged
- OnDirectorChanging
- OnDirectorChanged
- OnDateReleasedChanging
- OnDateReleasedChanged
OnChanging メソッドは、対応するプロパティが変更される直前に呼び出されます。 OnChanged メソッドは、プロパティが変更された直後に呼び出されます。
これらの部分メソッドを利用して、Movie クラスに検証ロジックを追加できます。 リスト 3 の更新プログラム Movie クラスは、Title と Director プロパティに値が割り当てられ、空でないことを確認します。
Note
部分メソッドは、実装が必須でないクラスで定義されたメソッドです。 部分メソッドを実装しない場合、コンパイラはメソッド シグネチャとメソッドのすべての呼び出しを削除し、部分メソッドに関連付けられた実行時のコストが発生しないようにします。 Visual Studio Code エディターでは、キーワード partial を入力し、その後にスペースを入力すると、実装する部分メソッドの一覧が表示され、そのようにして部分メソッドを追加できます。
リスト 3 - Models\Movie.vb
Imports System.ComponentModel
Partial Public Class Movie
Implements IDataErrorInfo
Private _errors As New Dictionary(Of String, String)()
Private Sub OnTitleChanging(ByVal value As String)
If value.Trim().Length = 0 Then
_errors.Add("Title", "Title is required.")
End If
End Sub
Private Sub OnDirectorChanging(ByVal value As String)
If value.Trim().Length = 0 Then
_errors.Add("Director", "Director is required.")
End If
End Sub
End Class
たとえば、Title プロパティに空の文字列を割り当てようとすると、エラー メッセージが _errors という名前のディクショナリに割り当てられます。
この時点で、Title プロパティに空の文字列を割り当て、プライベート _errors フィールドにエラーが追加されても、実際には何も起こりません。 これらの検証エラーを ASP.NET MVC フレームワークに公開するには、IDataErrorInfo インターフェイスを実装する必要があります。
IDataErrorInfo インターフェイスの実装
IDataErrorInfo インターフェイスは、.NET フレームワークの最初のバージョンから含まれています。 このインターフェイスは非常に単純なインターフェイスです。
Public Interface IDataErrorInfo
Default ReadOnly Property Item(ByVal columnName As String) As String
ReadOnly Property [Error]() As String
End Interface
クラスが IDataErrorInfo インターフェイスを実装する場合、ASP.NET MVC フレームワークは、クラスのインスタンスを作成するときにこのインターフェイスを使用します。 たとえば、Home コントローラーの Create() アクションは、Movie クラスのインスタンスを受け入れます。
<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude := "Id")> ByVal movieToCreate As Movie) As ActionResult
' Validate
If (Not ModelState.IsValid) Then
Return View()
End If
' Add to database
Try
_db.AddToMovieSet(movieToCreate)
_db.SaveChanges()
Return RedirectToAction("Index")
Catch
Return View()
End Try
End Function
ASP.NET MVC フレームワークは、モデル バインダー (DefaultModelBinder) を使用して、Create() アクションに渡される Movie のインスタンスを作成します。 モデル バインダーは、HTML フォーム フィールドを Movie オブジェクトのインスタンスにバインドすることで、Movie オブジェクトのインスタンスを作成します。
DefaultModelBinder は、クラスが IDataErrorInfo インターフェイスを実装するかどうかを検出します。 クラスがこのインターフェイスを実装する場合、モデル バインダーは、クラスの各プロパティに対して IDataErrorInfo.this インデクサーを呼び出します。 インデクサーからエラー メッセージが返された場合、モデル バインダーはこのエラー メッセージをモデルの状態に自動的に追加します。
DefaultModelBinder は、IDataErrorInfo.Error プロパティもチェックします。 このプロパティは、クラスに関連付けられているプロパティ固有ではない検証エラーを表すことを目的としています。 たとえば、Movie クラスの複数のプロパティの値に依存する検証規則を適用できます。 その場合は、Error プロパティから検証エラーを返します。
リスト 4 の更新された Movie クラスは、IDataErrorInfo インターフェイスを実装します。
リスト 4 - Models\Movie.vb (IDataErrorInfo を実装)
Imports System.ComponentModel
Partial Public Class Movie
Implements IDataErrorInfo
Private _errors As New Dictionary(Of String, String)()
Private Sub OnTitleChanging(ByVal value As String)
If value.Trim().Length = 0 Then
_errors.Add("Title", "Title is required.")
End If
End Sub
Private Sub OnDirectorChanging(ByVal value As String)
If value.Trim().Length = 0 Then
_errors.Add("Director", "Director is required.")
End If
End Sub
#Region "IDataErrorInfo Members"
Public ReadOnly Property [Error]() As String Implements IDataErrorInfo.Error
Get
Return String.Empty
End Get
End Property
Default Public ReadOnly Property Item(ByVal columnName As String) As String Implements IDataErrorInfo.Item
Get
If _errors.ContainsKey(columnName) Then
Return _errors(columnName)
End If
Return String.Empty
End Get
End Property
#End Region
End Class
リスト 4 では、インデクサー プロパティは _errors コレクションをチェックし、インデクサーに渡されるプロパティ名に対応するキーが含まれているかどうかを確認します。 プロパティに関連付けられている検証エラーがない場合は、空の文字列が返されます。
変更した Movie クラスを使用するために Home コントローラーを変更する必要はありません。 図 3 に表示されるページは、[Title] または [Director] フォーム フィールドに値が入力されていない場合の動作を示しています。
図 03: 値が指定されていないフォーム (クリックすると、フルサイズの画像が表示されます)
DateReleased 値が自動的に検証されています。 DateReleased プロパティは NULL 値を受け入れないので、DefaultModelBinder は値がない場合にこのプロパティの検証エラーを自動的に生成します。 DateReleased プロパティのエラー メッセージを変更する場合は、カスタム モデル バインダーを作成する必要があります。
まとめ
このチュートリアルでは、IDataErrorInfo インターフェイスを使用して検証エラー メッセージを生成する方法について説明しました。 最初に、Entity Framework によって生成された Movie 部分クラスの機能を拡張する Movie 部分クラスを作成しました。 次に、Movie クラス OnTitleChanging() と OnDirectorChanging() 部分メソッドに検証ロジックを追加しました。 最後に、これらの検証メッセージを ASP.NET MVC フレームワークに公開するために、IDataErrorInfo インターフェイスを実装しました。