連載:〜ScottGu氏のブログより〜

ASP.NET MVCベータ版がリリース

Scott Guthrie 著/Chica
2008/10/24
Page1 Page2 Page3

フォーム送信とモデル・バインダの改善

 ASP.NET MVC “Preview 5”リリースでの最大の機能投資は、フォーム送信のシナリオへの対応でした。これらのフォーム送信シナリオにおける機能については、先月詳細なブログ投稿を行っています。

 本日のベータには、この部分において数多くの追加修正、改善、更新が行われています。これらには次のものがあります。

■複合型に対するビルトインのモデル・バインダ・サポート

 Preview 5では“モデル・バインダ”の概念が導入されました。これにより、コントローラのアクション・メソッドのパラメータとして、フォームから送信された値を複雑な.NETの型へ割り当てることができます。Preview 5のモデル・バインダは拡張性があるため、独自のバインダを作成し、それらをシステムの複数のレベルで登録できます。Preview 5には“あらかじめビルドされた”バインダは含まれていませんでしたが、手を加えることなくすぐに使用できました(各自でビルドする必要がありました)。本日のベータには、ビルトインで登録済みのバインダが含まれており、追加のコードや登録の必要がなく、標準の.NETの型を自動的に処理するために使用できます。

 例えばいま、以下のような標準的なプロパティを持った“Person”クラスを作成できます(図9)。


図9

 その後、コントローラのアクション・メソッドでは、単に以下のようなコードを書くだけで、それをパラメータとして取り扱います(図10)。


図10

 上記のパラメータには“person”という名前が付いているため、モデル・バインダはデフォルトで、フォーム送信された値からキーの名前が“person.Name”、“person.Age”、“person.Email”になっているものを検索します。その後、それらの値を使用して、新しい“Person”オブジェクトが作成・ひも付けされ、アクション・メソッドへ引き渡されます。

 開発者はオプションとして、本日のベータで導入された新しい[Bind]属性を使用して“Prefix”プロパティを設定することにより、ロジックにマッピングされたデフォルトの名前をオーバーライドできます。例えば、もしプリフィックスのプロパティに“PersonToSave”を設定した場合、Personインスタンスが作成された際、そのバインダは代わりに“PersonToSave.Name”、“PersonToSave.Age”、“PersonToSave.Email”というフォームの値を検索します。プリフィックスを空の文字列にして、バインダにプリフィックスのない“Name”、“Age”、“Email”をマッピングするようにも設定できます(図11)。


図11

 [Bind]属性はオプションで“Include”または“Exclude”プロパティを指定できます。これらはオブジェクトにマッピングされたものに対して、“ホワイトリスト”または“ブラックリスト”プロパティとして使用できます。例えば以下のコードは、Personオブジェクト上に“Name”および“Age”プロパティだけマッピングしたいことを示しています。


図12

重要な安全TIPS:通常は、マッピングしたくないプロパティがマッピングされないように慎重に確認した方がよいでしょう。オブジェクトにマッピングしたくないプロパティがある場合は、常にInclude/Excludeを使用してください。例えば、Personオブジェクトに“Salary”があり、明示的にエンドユーザーに設定させたい場合以外は、それをマッピングしたくないとします。このようなマッピングしたくないプロパティを明示し、ハッカーにフォームのリクエストを変更させないよう、またUI(ユーザー・インターフェイス)で編集できないプロパティの情報を追加で送信させないようにした方がいいでしょう。

■リファクタリングされたモデル・バインダの基盤

 モデル・バインダのシステムは、今回のベータで大幅にリファクタリングされました。今回では、独自のモデル・バインダをビルドする際に、その機能性をより詳細な方法で再利用しプラグインすることができます。

 モデル・バインダは、UpdateModelおよびTryUpdateModelメソッドで使用することも可能で、1つのバインダを書けば、ASP.NET MVC内でフォームの値が処理される場所なら、どこでも再利用できます。

■改善されたUpdateModelおよびTryUpdateModelメソッド

 UpdateModelおよびTryUpdateModelメソッドはいまや、(よりリッチなホワイトリストやブラックリストのオプションを含む)新しいオプションやオーバーロードをいくつかサポートしています。

 またオプションとして、“UpdateModel”を呼び出すだけで、デフォルトのバインディング・ルールでインスタンスをひも付けることができる機能もサポートされています(Preview 5では常にホワイトリストを提供する必要があり、すべてをマッピングするだけのオプションが求められていました)(図13)。


図13

 今回のベータのもう1つの新しい機能は、UpdateModel/TryUpdateModelとともに使用する強く型付けされたホワイトリスト・フィルタを定義する機能です。これを行うには、マッピングしたいバインド可能なプロパティのサブセットとともにインターフェイスを定義します。例えば以下は、3つのプロパティのみを持つ(Salaryプロパティを持たない)“IPersonFormBindable”インターフェイスを定義しています(図14)。


図14

 その後、以下のようなコードを使用して、マッピングされるプロパティを制限するために、このコントラクトを使用することを示します(図15)。


図15

 これにより、IPersonFormBindable上で定義されたプロパティのみがマッピングされ、Salaryはマッピングされないようになります。

■改善されたUpdateModelおよびTryUpdateModelシナリオの単体テスト

 Preview 5では、UpdateModelもしくはTryUpdateModelメソッドを使用したフォーム送信シナリオを単体テストするためには、モッキングを使用しなければなりませんでした。本日のベータでは、モッキングの必要はまったくなく、すべてのフォーム送信シナリオを単体テストできます(これにより、よりスムーズな単体テストが可能になります)。

 本日のベータには、新しく導入されたIValueProviderインターフェイスがあり、これはモデル・バインディング基盤が(いままでリクエスト・オブジェクトに対して常に行われていたのとは反対に)バインドする値を取得するために使用します。FormCollectionクラス(ベータにビルトインされています)は、このインターフェイスを実装しているので、このインスタンスを明示的にUpdateModel/TryUpdateModelに引き渡して、その値をバインドさせることができます。

 例えば、以下の“Save”アクション・メソッドでは、すべてのフォームの値をFormCollectionにバインディングしています(アクション・メソッドへ引数として引き渡します)。その後、このフォーム・コレクションをUpdateModelの呼び出しへ引き渡し、このパラメータを使用してPersonモデル・オブジェクトに値がマッピングされるようにします(図16)。


図16

 その後、以下のコードを使用して、上記のアクション・メソッドに対して成功時のフォーム送信シナリオを単体テストできます(何もモックする必要はありません。代わりとして、FormCollectionを作成、ひも付けし、パラメータとして引き渡すだけになりました)(図17)。


図17

 それから以下のコードを使用して、失敗時のフォーム送信を単体テストできます(これは年齢の値に無効な入力がされたため失敗します)。フォーム送信の失敗時のシナリオにおいて、どのように編集フォームが再表示されるかご確認ください(これによりユーザーは間違いを修正できます)(図18)。


図18

 上記の両方のフォーム送信シナリオを単体テストするのに何のモックも必要はありません。

■強く型付けされた[AcceptVerbs]属性

 ASP.NET MVC Preview 5では、新しい[AcceptVerbs]属性が導入され、どのHTTP Verbがアクション・メソッドでサポートされているかを示すことができます。

 Preview 5では、常に文字列を使用してVerbを指定していました。ベータではまだこれをサポートしていますが、強く型付けされたenumマスクを使用して指定された共通のVerbもサポートされるようになりました。以下はその例です。


図19

 本日のベータ・リリースでは、上記のようなどちらのアクション上でも[AcceptVerbs]を指定する必要はありません。デフォルトでASP.NET MVCは、やってくるHTTP Verbを明示的にサポートするアクション・メソッドを検索し、もしそれが見つからない場合は、明示的にVerbが指定されていないアクション・メソッドを使用します。これにより、よくあるGET/POSTシナリオに対して記述を省くことができます(GETメソッドを修飾する必要はもうありません)。

■バリデーション・エラー・メッセージ

 ベータに残念ながら入らなかった機能の1つ(次の更新では追加します)が、固有のモデル・クラスから独自のエラー・バリデーション・メッセージを公開できる機能です(それとは逆に、現在可能なのはコントローラでのカスタマイズです)。いまはこれを可能にする方法を探している最中です。これには、System.ComponentModel.DataAnnotations名前空間にあるIDataErrorInfoインターフェイスや新しいDynamic Data属性のサポートが含まれます。

 本日のベータに含めることができた改善点ですが、デフォルトのバリデーション・エラー・メッセージがよりユーザーフレンドリになっています(多くの場合で、独自のバリデーション・エラー・メッセージを定義する必要がなくなっていると思います)(図20)。


図20


 INDEX
  〜ScottGu氏のブログより〜
  ASP.NET MVCベータ版がリリース
    1.VSの新しい“ビューの追加”メニュー/新しい\ScriptsディレクトリとjQueryサポート
  2.フォーム送信とモデル・バインダの改善
    3.HTMLヘルパ/Silverlightプロジェクトの統合/ASP.NET MVC Futuresアセンブリ
 
インデックス・ページヘ  「〜ScottGu氏のブログより〜」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間