連載:〜ScottGu氏のブログより〜ASP.NET MVC 2:モデルの検証Scott Guthrie 著/Chica 訳2010/02/08 |
|
|
[ブログに加え、現在Twitterを使って簡単な更新やリンク共有を行っています。twitter.com/scottguで、私をフォローしてください。]
これは、ASP.NET MVC 2リリースに向けたブログ投稿シリーズの第2弾です。このブログ投稿では、ASP.NET MVC 2で追加された検証の改善点のいくつかをカバーします。
ASP.NET MVC 2の検証
ユーザーからの入力の検証やビジネス・ルール/ロジックの実施は、ほとんどのWebアプリケーションで必須要件です。ASP.NET MVC 2には、モデル/ビューモデル上でユーザーからの入力検証や検証ロジックの実施を大幅に簡単にする多くの新機能が含まれています。これらの機能は、検証ロジックが常にサーバ上で実施されるよう、またオプションでJavaScriptを通じてクライアント上でも実施されるように設計されています。ASP.NET MVC 2の検証基盤および機能は、次のことが可能になるように設計されています。
- 開発者が簡単に.NET FrameworkにビルトインされているDataAnnotationの検証サポートを利用できます。DataAnnotationは、最小限のコードでオブジェクトやプロパティに検証ルールを宣言的に追加できる非常に簡単な方法を提供します。
- 開発者はオプションで、独自の検証エンジンと統合したり、Castle ValidatorまたはEntLib Validation Libraryのような既存の検証フレームワークが利用したりできます。ASP.NET MVC 2の検証機能は、新しいASP.NET MVC 2の検証基盤(クライアントサイド検証、モデル・バインディング検証など)を利用しながら、どんな種類の検証アーキテクチャにも簡単にプラグインできるように設計されています。
つまり、共通のアプリケーション・シナリオにおいて非常に簡単に検証が可能で、しかも、より高度なシナリオに対しても、非常に柔軟性に対応できるのです。
ASP.NET MVC 2とDataAnnotationで検証を有効化
新しいビルトインのDataAnnotation検証サポートを利用する簡単なCRUDシナリオをウォークスルーしましょう。具体的には、“Create”フォームを実装して、ユーザーが友人についてのデータを入力できるようにしましょう。
図1 |
入力された情報がデータベースに保存される前に有効であるかを確かめ、そうでなければ適切なエラー・メッセージが表示されるようにしたいと思います。
図2 |
この検証を、サーバおよびクライアント(JavaScriptを通じて)の両方で発生するようにしたいと思います。また、コードもDRYの原則(“don't repeat yourself”:繰り返さない)で保持したいと思います。つまり、1カ所でのみ、その検証ルールを適用し、すべてのコントローラ、アクション、ビューがそれを守るようにするということです。
ASP.NET MVC 2を使用して上記のシナリオを実装するのにVS 2010を使用します。まったく同じシナリオは、VS 2008+ASP.NET MVC 2でも実装できます。
ステップ1:FriendsControllerの実装(最初に検証機能がない状態)
まず以下のように、新しいASP.NET MVC 2プロジェクトに簡単な“Person”クラスを追加します。
図3 |
4つのプロパティがあります(C#の自動プロパティサポートを使用して実装、VS 2010ではVBもサポートしています。やった!)。.
その後“FriendsController”コントローラ・クラスをプロジェクトに追加すると、2つの“Create”アクション・メソッドが公開されます。最初のアクション・メソッドは、/Friends/CreateのURLに対して、HTTP-GETリクエストがきたときに呼ばれます。2つ目のアクション・メソッドは、/Friends/CreateのURLに対して、HTTP-POSTリクエストがきたときに呼ばれます。これは、送信されたフォーム入力をPersonオブジェクトへマップして、バインディング・エラーの発生がないかどうかを検証し、有効な場合は最後にデータベースに保存します(このチュートリアルの後の方でDB関連を実装します)。もし送信されたフォーム入力が無効な場合、アクション・メソッドはフォームにエラーを表示します。
図4 |
コントローラを実装した後、アクション・メソッドの1つで右クリックして、“ビューの追加”コマンドをVisual Studioで選択して、“ビューの追加”ダイアログを開くことができます。Personオブジェクトへ引き渡された“Create”ビューのスキャフォールドを選択します。
図5 |
そうするとVisual Studioは、プロジェクトの\Views\Friends\ディレクトリに、スキャフォールドされたCreate.aspxビューのファイルを生成します。ASP.NET MVC 2の新しい強く型付けされたHTMLヘルパーの利用方法を以下で確認してください(改善されたIntelliSenseとコンパイル時のチェック・サポートが有効化されています)。
図6 |
これでアプリケーションを起動して/Friends/CreateのURLをたたくと、データ入力が可能な空のフォームが表示されます。
図7 |
アプリケーション内では検証を何も実装していないので、フォーム内で誤った入力をしても、サーバへ送信されないようにするものはありません。
ステップ2:DataAnnotationを使用して検証を有効化
アプリケーションを更新して、いくつかの基本的な入力検証ルールを実施しましょう。これらのルールはPersonモデル・オブジェクト上に実装し、コントローラもしくはビュー内には実装しません。Personオブジェクト内にルールを実装する利点は、Personオブジェクトを使用するアプリケーション内のすべてのシナリオを通じて、この検証が実施されることが確証されることです(例:後で編集シナリオを追加する場合)。これにより、コードをDRYに保て、複数の場所でルールを繰り返さなくて済むようになります。
ASP.NET MVC 2により、開発者は簡単に宣言的な検証属性をモデルまたはビューモデルのクラスに追加でき、ASP.NET MVCがアプリケーション内でモデル・バインディングのオペレーションを実施するたびに、自動的にこれらの検証ルールが実施されるようにできます。これを確認するために、検証属性をいくつかPersonクラス上に追加して更新しましょう。これを行うには、ファイルの上部に“System.ComponentModel.DataAnnotations”名前空間に対する“using”ステートメントを追加し、[Required]、[StringLength]、[Range]、[RegularExpression]の検証属性をPersonプロパティに追加します(すべてこの名前空間内に実装されています)。
図8 |
注:上記は文字列で明示的にエラー・メッセージを指定しています。また代替的にリソース・ファイル内で定義し、オプションとして、それらをユーザーの言語/カルチャに応じてローカライズすることもできます。検証エラー・メッセージのローカライズ方法は、ここからより詳細を確認できます。
これで、検証属性をPersonクラスに追加できたので、アプリケーションを再起動し、誤った値を入力して、それがサーバへ送信されるとどうなるか確認しましょう。
図9 |
上記のように、アプリケーションに満足のいくエラー体験が追加されたのを確認できます。無効な入力に対する文字列要素は赤でハイライトされ、指定した検証エラー・メッセージがエンドユーザーに表示されています。フォームはもともとユーザーが入力したデータも保存しているので、再入力は必要ありません。さて、ここで何が起こっているのか、ご質問されるかもしれません。
この動作を理解するために、フォームに対するPOSTシナリオを処理するCreateアクション・メソッドを見てみましょう。
図10 |
HTMLフォームがサーバにポストバックされたとき、上記のメソッドが呼ばれます。これはアクション・メソッドが“Person”オブジェクトをパラメータとして受け入れているため、ASP.NET MVCがPersonオブジェクトを作成し、自動的にそれに対して入力される値をマップします。このプロセスの一部として、Personオブジェクトに対してDataAnnotationの検証属性が有効かどうかも確認します。もしすべてが有効な場合、コード内でModelState.IsValidチェックがTrueを返します。この場合(結果的に)Personをデータベースへ保存して、ホーム・ページへリダイレクトします。
もしPersonオブジェクト上で何か検証エラーがあった場合、アクション・メソッドは無効なPersonを表示します。これは、上記のコード・スニペットの最後の行を通して行われます。
そして、Createフォームが各<%= Html.TextBoxFor() %>ヘルパーの次に、<%= Html.ValidationMessageFor() %>ヘルパー・メソッドを呼び出すため、ビューの中でエラー・メッセージが表示されます。Html.ValidationMessageForヘルパー・メソッドはビューへ引き渡された無効なモデル・プロパティに対して適切なエラー・メッセージを出力します。
図11 |
このパターン/アプローチの良いところは、セットアップが非常に簡単な点と、コントローラやビュー内でコードの変更をすることなく、Personクラス上に簡単に検証ルールを追加したり変更したりできるところです。この、1つの場所で検証ルールを指定して、すべての場所でそれを守り尊重させることができる機能により、最小限の努力でアプリケーションやルールを早急に展開でき、コードを非常にDRYに保てます。
ステップ3:クライアントサイド検証の有効化
アプリケーションは現在、サーバーサイドの検証だけを実施しています。つまり、エンドユーザーは検証エラー・メッセージを見る前に、サーバへフォームを送信する必要があるということです。
ASP.NET MVC 2の検証アーキテクチャで素晴らしい点の1つが、サーバーサイド、そしてクライアントサイドの検証の両方をサポートしていることです。これを有効にするために必要なことは、2つのJavaScript参照をビューへ追加することと、コードを1行書くことだけです。
図12 |
これらの3行を追加すると、ASP.NET MVC 2はPersonクラスに追加した検証メタデータを使用して、クライアントサイドのJavaScript検証ロジックを組み込みます。つまり、ユーザーは無効な入力要素から移動すると、すぐに検証エラーを確認できます。
この友人アプリケーションで、クライアントサイドのJavaScriptサポートを確認するために、アプリケーションを再起動し、最初の3つのテキストボックスに正しい値を入力し、“Create”をクリックしてみてください。サーバをアクセスすることなく、すぐに未入力データに対してエラー・メッセージが表示されることをご確認ください。
図13 |
もし正しいEmailアドレスを入力しないと、エラー・メッセージはすぐに“Email Required(Emailアドレス必須)”から“Not a valid email(無効なEmailアドレス)”に変更されます(Personクラスへルールを追加したときに指定したエラー・メッセージです)。
図14 |
有効なEmailアドレスを入力すると、エラー・メッセージはすぐに非表示になり、テキストボックスの背景色が通常の状態に戻ります。
図15 |
素晴らしいのは、上記の検証ロジックを有効するために独自のJavaScriptを書く必要がないことです。検証コードもまだ非常にDRYで、1つの場所にルールを指定して、アプリケーションすべて、そしてクライアントおよびサーバの両方でそれらを実行できます。
セキュリティの理由から、たとえクライアントサイドのサポートを有効化していても、サーバーサイドの検証ルールは常に実行されることにご注意ください。これはハッカーがサーバを騙したり、クライアントサイドのルールをあざむいたりするのを防ぎます。
ASP.NET MVC 2のクライアントサイドのJavaScript検証サポートは、ASP.NET MVCで使用しているどの検証フレームワーク/エンジンとも動作します。これはDataAnnotation検証のアプローチの利用を必要としません。基盤すべてがDataAnnotationとは独立して動作し、Castle Validator、EntLib Validation Block、そのほかあなたが使用しようと選択した独自の検証ソリューションと動作します。
もし私たちのクライアントサイドJavaScriptファイルを使用したくない場合は、代わりとしてjQuery 検証プラグインで置き換え、そのライブラリを使用することも可能です。ASP.NET MVC Futuresをダウンロードすると、ASP.NET MVC 2のサーバーサイド検証フレームワークに対してjQuery検証を有効にするサポートが含まれています。
ステップ4:独自の[Email]検証属性の作成
.NET Framework内のSystem.ComponentModel.DataAnnotations名前空間には使用可能な多くのビルトイン検証属性が含まれています。上記のサンプルでは、[Required]、[StringLength]、[Range]、[RegularExpression]の4つの異なる属性を使用しました。
オプションとして、独自の検証属性を定義して使用することも可能です。System.ComponentModel.DataAnnotations名前空間内でValidationAttributeベース・クラスから派生させた、完全に独自の属性を定義できます。代替的に、もしベース機能を単純に拡張したいだけの場合は、既存の検証属性のいずれから派生させることも選択できます。
例えば、Personクラスにあるコードをクリーンにするために、有効なEmailをチェックする正規表現をカプセル化する、新しい[Email]検証属性を作成したくなるかもしれません。これを行うには、RegularExpressionベースクラスから単純に派生させて、RegularExpressionのベース・コンストラクタを適切なEmailのRegexで呼び出します。
図16 |
そしてPersonクラスを更新すると、以前に正規表現を使用していた場所で新しい[Email]検証属性を使用できます。これにより、よりクリーンになり、カプセル化されます。
図17 |
独自の検証属性を作成すると、サーバ上およびJavaScriptによるクライアント上の両方で実行する検証ロジックを指定できます。
オブジェクト上の各プロパティに適用する検証属性を作成するだけでなく、クラス・レベルで検証属性を適用することもできます。これによりオブジェクト内で複数のプロパティにわたり検証ロジックを実施できます。この例の実際の動きとして、“PropertiesMustMatchAttribute”という独自の属性をレビューできます。これは、デフォルトのASP.NET MVC 2アプリケーション・プロジェクトのテンプレートにあるAccountModels.cs/vbに含まれています(VS 2010でファイル->新規ASP.NET MVC 2 Webプロジェクトを選択して、このクラスを探すだけです)。
ステップ5:データベースに保存
友人をデータベースに保存するのに必要なロジックを実装してみましょう。
図18 |
まず単純に、シンプルで昔なじみのC#クラス(ときどき“POCO”クラスと呼ばれます。“Plain Old CLR(またはC#)Object”)に対して作業していきます。利用可能な1つのアプローチは、すでに書いてある既存クラスをデータベースにマップするような、別の保存コードをいくつか書くことです。NHibernateのような、オブジェクト・リレーショナル・マッピング(ORM)ソリューションは、今日非常にうまく、このマッピングのPOCO/PI(Persistence Ignorance)スタイルをサポートしています。.NET 4とともに出荷されるADO.NET Entity Framework(EF)もPOCO/PIマッピングをサポートし、NHibernateのように、“コードのみ”(マッピング・ファイルやデザイナが要求されない)の方法で保存マッピングが定義できる機能もオプションで有効化できます。
もし、Personオブジェクトがこの方法でデータベースにマップされた場合、Personクラスや、どの検証ルールに対しても変更を加える必要はなく、それは継続してうまく動作します。
■しかし、ORMマッピングにグラフィカルなツールを使用していたらどうなるのでしょう?
今日のVisual Studioを使用している多くの開発者は、独自のORMマッピング/保存ロジックを書いていません。代わりに、これを管理するためにVisual Studio内のビルトインのデザイナを使用しています。
DataAnnotation(またはそのほかの検証をベースにしている属性の形式)を使用しているときによくある質問の1つが、“取り扱っているモデル・オブジェクトがGUIデザイナで作成/保守されている場合、どのようにそれらを適用するのですか?”というものです。例えば、ここまでに使用してきたPOCOスタイルのPersonクラスの代わりに、LINQ to SQLやADO.NET EFデザイナなどのGUIマッピング・ツールを通じてVisual Studio内でPersonクラスを定義/保守していた場合です。
図19 |
上の図は、VS 2010でADO.NET EFデザイナを使用してPersonクラスを定義しているところを表示したスクリーンショットです。上部のウィンドウはPersonクラスを定義していて、下部のウィンドウはデータベース内で“People”テーブルへ/から、そのプロパティをマップする方法をマッピング・エディタで表示しています。デザイナ上で保存をクリックすると、プロジェクト内でPersonクラスを自動的に生成します。これは素晴らしいですが、変更してから保存すると、Personクラスを再生成します。これにより、記述した検証の属性宣言がすべて失われてしまいます。
追加の属性ベースのメタデータ(検証属性など)を、VSデザイナで自動生成/保守されているクラスに適用できる1つの方法が、“バディ・クラス”と呼んでいる技術を採用することです。基本的には、別のクラスを作成して、その中に検証属性とメタデータを含め、ツールで生成されたクラスと一緒にコンパイルされるパーシャル・クラスへ“MetadataType”属性を適用することで、デザイナが生成するクラスへそれ(作成した別のクラス)をリンクします。例えば、LINQ to SQLやADO.NET EFデザイナが保守するPersonクラスに、先ほど使用していた検証ルールを適用したい場合、以下のコードを使用して、VSで作成される“Person”クラスへリンクされる別の“Person_Validation”クラスの中で動作するように検証コードを更新できます。
図20 |
上記の方法は、純粋なPOCOのアプローチのようにエレガントではないですが、Visual Studio内のどのツールとも、またデザイナにより生成されたコードとも、非常にうまく動作するという利点があります。
■最後のステップ − データベースへ友人を保存
最後のステップは、POCOまたはツールが生成したPersonクラスのどちらを使っているかにかかわらず、データベースへ有効な友人を保存することです。
必要なことは、単純にFriendsControllerクラス内の“Todo”プレースホルダ・ステートメントを、その新しい友人をデータベースへ保存する3行のコードと置換することです。以下は、ADO.NET EFを使用してデータベース保存するときのFriendsControllerクラス全体の完全なコードです。
図21 |
これで/Friends/Create のURLを訪れると、簡単に新しいPeopleを友人データベースへ追加できます。
図22 |
すべてのデータに対する検証がクライアントとサーバの両方で実施されます。1つの場所で検証ルールを簡単に追加/修正/削除でき、アプリケーション全体のすべてのコントローラおよびビューで、それらのルールが実施されるようにできます。
まとめ
ASP.NET MVC 2により、Webアプリケーションに非常に簡単に検証を統合できるようになります。これはモデル・ベースの検証方法を促進しているため、アプリケーションを非常にDRYに保つことができ、アプリケーションを通じて統一的に検証ルールが確実に実施されるよう手助けをします。ASP.NET MVC 2内のビルトインのDataAnnotationサポートは、そのままで一般的な検証シナリオをサポートできます。ASP.NET MVC 2の検証基盤内の拡張サポートでは、広い範囲のさまざまな、より高度な検証シナリオもサポートでき、すべての既存もしくは独自の検証フレームワーク/エンジンをプラグインできます。
Hope this helps,
「〜ScottGu氏のブログより〜」 |
- 第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用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|