Open棟梁Project - マイクロソフト系技術情報 Wiki
目次 †
概要 †
「ASP.NET MVCの利用方法」は
「ASP.NET MVCの用語」と比べて、
少々高度な応用的トピックをまとめています。
モジュール化の考え方 †
まず、Model と View と Controller の役割について整理する。
- Model: アプリケーションの基礎となるデータ構造、およびそのデータを取得・加工する業務ロジック
- View: Model が保持するデータを参照し、ユーザーに表示するもの
- Controller: ユーザーからの入力を受け取り、Model に対してデータの取得・加工を指示する。
その結果を受けて、View に表示を指示する。
Modelと全体Viewの関係 †
Model (0..1) <---> (1) 全体View
Model (0) <---> (1) 全体View †
全体View が、Model が保持するデータを何も表示しない状態。(静的なページなど?)
Model (1) <---> (1) 全体View †
全体View が、Model が保持するデータを参照し、ユーザーに表示している状態。
ただし、全体View が参照できるのは「Model のプロパティ」のみであり、
全体View から直接 Model のメソッドが呼ぶことはしない。
Controllerと全体Viewの関係 †
全体View (1..*) <---> (1) Controller
全体View (1) <---> (1) Controller †
1 つの 全体View に対して、1 つの Controller を対応させる考え方。
その 全体View からは、対応する Controller へのみリクエストを送る。
Controller の処理の結果は、対応する 全体View にのみ指示を送る、というもの。
Controller の処理の結果を、別の 全体View に表示させたい場合は、
Controller.RedirectToAction? メソッドなどを使用して、
その 全体View に対応した Controller に処理をリダイレクトする。
乱暴な言い方をすれば、従来の ASP.NET の WebForm? に近い考え方、と言えるかもしれない。
- 画面 (*.aspx) が、全体View に相当する
- コードビハインド (*.aspx.cs, *.aspx.vb) が、Controller に相当する
- 画面を遷移するときは、Response.Redirect メソッドを使用して処理をリダイレクトする
- メリット
- 従来の ASP.NET の経験がある人には、とっつきやすい可能性がある。
- デメリット
- Controller クラスの数が膨大になる可能性がある。
全体View (1..*) <---> (1) Controller †
複数の 全体View に対して、1 つの Controller を対応させる考え方。
たとえば、受注処理を行うアプリケーションを考えると、「受注作成画面」・「受注内容更新画面」・「受注削除画面」など、
複数の 全体View に分かれていても、同じ「受注」業務=受注エンティティに関するリクエストは 1 つの Controller が受け付ける、という考え方。
- スキャフォールディングの場合、M/V/C それぞれの多重度は、以下のようになる。
- 全体View (4) <---> (1) Model
(1 つの Model に対して、CRUD を行う 全体View がそれぞれ作成される)
- Controller (1) <---> (1) Model
(1 つの Model に対して、その Model に関するリクエストを受け付ける Controller が 1 つ作成される)
- 全体View (4) <---> (1) Controller
(CRUD を行う 4 つの 全体View は、1 つの Controller にのみリクエストを送る)
- しかし、1 つの 全体View で、CRUD 全てを実現できる (CRUD ごとに 全体View が分かれない) 場合は、以下のようになる。
- 全体View (1) <---> (1) Model
- Controller (1) <---> (1) Model
- 全体View (1) <---> (1) Controller
- メリット
- まとまった業務ごとに Controller を作るので、Controller の数を抑えられる。
- デメリット
- 複数の 全体View からの処理をすべて 1 つの Controller で受け付けるため、その Controller のコード量が多くなる可能性がある。
モジュール化の要約 †
スキャフォールディング方式 †
- 全体View (1..*) <---> (1) Model
- Controller (1) <---> (1..*) Model
- 全体View (1..*) <---> (1) Controller
全体View ごとに Controller を作成する方式 †
- 全体View (1..*) <---> (1) Model
- Controller (1) <---> (1..*) Model
- 全体View (1) <---> (1) Controller
Controller の作成 †
モジュール化 †
モジュール化の要約で紹介した、
何れかの方針に合わせて、Controllerを作成する。
利用可能な属性 †
HTTP メソッド属性 †
特定の HTTP メソッドのみを受け入れる属性を付与することができる。
なお、Action MethodにHTTPメソッド属性を指定しなかった場合、
Action Methodは、すべての HTTP メソッドを受け入れる。
AcceptVerbs? 属性は、複数のHTTPメソッドを受け入れるAction Methodの定義に使用する。
MVC 2 からはHttpGet?, HttpPost?, HttpPut?, HttpDelete?という4つの属性が追加された。
- [HttpGet?] メソッド属性
- 概要
- Get メソッドのみ受け入れる。
- それ以外の HTTP メソッドは受け入れない(404 が返る)。
- ユースケース
- Get で別画面に画面遷移する場合
- 入力項目が無い状態で、同一画面内で状態遷移する場合
- [HttpPost?] メソッド属性
- 概要
- Post メソッドのみ受け入れる。
- それ以外の HTTP メソッドは受け入れない(404 が返る)。
- ユースケース
- フォームの入力項目を Controller に Post する場合。
- Post で別画面に画面遷移する場合。
ActionName?属性 †
Action Method名と、外部に公開するAction Nameとを別にする。
例えば
項番 | Action Method名 | ActionName? | 処理の内容 |
1 | Delete | Delete | 削除画面の初期表示処理 |
2 | DeleteConfirmed? | Delete | 削除処理の実行 |
ValidateAntiForgeryToken?属性 †
CSRF対策に使用する。
複数ブラウザウィンドウ対応がなされているかどうかは未確認。
Model の作成 †
モジュール化 †
モジュール化の考え方のように、Model には 2 つの意味がある。
- アプリケーションの基礎となるデータ構造
- POCO として作成する。
- XXXXViewModel?という名称を付与する。
利用可能な属性 †
System.ComponentModel?.DataAnnotations?属性により、
- 検証機能
- テンプレート・ヘルパーと呼ばれるView
- Controllerのスキャフォールディング生成
の動作を制御する事ができる。
DataType?属性 †
型情報を指定することで、
として使用される。
[DataType(DataType.XXXX)]
DataType?の派生の属性 †
DataType属性と同様に利用される。
DisplayName?, Display属性 †
表示名(Label表示用のViewヘルパーに使用される)
- Display
- Name
- ResourcesType?(国際化対応用)
- [Display(Name = "xxxx", ResourceType? = typeof(yyyy))]
DisplayFormat?属性 †
フォーマットの指定。
[DisplayFormat(DataFormatXXXX="YYYY")]
UIHint属性 †
- 独自の表示/編集テンプレート・ヘルパーを準備する。
- 例えばDateTime?型を指定したEditorFor?で
使用するjQuery UIのDatepickerを適用する。
DisplayColumn?属性 †
- Model間のRelationを設定した際、Modelの表示名に使用しているColumn。
- Model間のRelationは、ナビゲーション・プロパティで設定する。
検証属性 †
検証属性については、コチラ。
View の作成 †
モジュール化 †
Razer、ASPX の使い分け †
基本、Razer(主流)を使用する。
BeginForm? の使い分け †
ASP.NET MVC には、<form> タグを生成する Viewヘルパーが 2 種類ある。
BeginForm? ヘルパーは引数にコントローラー名、アクション名が付与でき、指定したアクションメソッドにリクエストを送ることができる。
HTML.BeginForm? †
通常の <form> タグを生成する場合に使用する。
- 全体更新が多数を占める場合 (アクションメソッドの結果として、View 全体を更新する場合)。
- 画面リフレッシュにより、リクエスト・レスポンスのステータスを明確にしたい場合。
Ajax.BeginForm? †
<form> タグに Ajax リクエスト用の属性が付与され、リクエストが非同期で処理される。
- 部分更新が多数を占める場合 (アクションメソッドの結果として、View の一部分のみを更新する場合)。
- サーバー側処理が非常に重い業務の場合 (Ajax は非同期処理のため)。
- 画面入力状態を保持したまま POST 送信したい場合
- ViewState? がサポートされない MVC で、情報復元処理を割愛したい場合。
- リクエスト・レスポンスのサイズを削減して、性能向上を図りたい場合。
- 画面リフレッシュによる、画面のちらつきなどをなくしたい場合。
参考 †
From タグの切り方 †
画面設計によるが、以下を考慮する。
- 1 View に対して 1 Form?
- 1 View に対して複数 Form?
複数 Form の場合は Form をネストさせないこと。
#HTML の仕様で Form のネストは禁止されている。
Viewヘルパーの使い分け †
HTMLヘルパー(Html.xxxx と Html.xxxxFor †
- Html.xxxxFor
- ポスト時にModelデータを復元する場合。
- 例えばエラー発生時に、自画面の再表示(≒ポストバック)をする場合。
- Html.xxxx
上記以外は、Html.xxxxで良い。
GridView?的な一覧(グリッド)生成用のViewヘルパー †
ASP.NET MVC で一覧(グリッド)のある View を作成する場合、以下の 3 種類が考えられる。
- WebGrid クラスを使用する
ソートやページングが容易に実装できる反面、レンダリング部分は多少ブラックボックスになる
- <table> タグを自前で生成し、<tr> タグをループで実装する
ASP.NET の Repeater コントロールのような処理の実装方法(Razorなぶん楽)。
テンプレートに対応したViewヘルパー(テンプレート・ヘルパー) †
- Viewヘルパー
- EditFor?
- HTMLヘルパーの第二引数でテンプレート・ヘルパーを指定できる。
- UIHint属性で指定したテンプレート・ヘルパーが使用される。
属性の優先度は、UIHint属性 -> DataType?属性 -> 実際のデータ型
- DisplayForModel?、EditForModel?
- Model単位にテンプレート・ヘルパーを決定する。
- テンプレート・ヘルパー名とテンプレート・ヘルパー配置場所
- DisplayTemplates?
- EditorTemplates?
Html.Hidden または Html.HiddenFor? †
タイムスタンプ型など、ユーザに見えない情報だが
内部処理に必要な情報を引き継ぐ場合に使用する。
カスタムViewヘルパー(カスタム・コントロールみたいな) †
画面遷移 †
モジュール化の要約で紹介した、
共に、画面遷移の処理フローは以下のようになる。
処理フロー †
- View から、対応する Controller にリクエストを送る
- Controller はリクエストを受け付け、Model に処理を指示する
- Model は業務ロジックを実行し、データを更新する
- Controller は View に表示を指示する
実装方法 †
なお、1つの View が、任意の Controller にPOSTリクエストを送る
ASP.NET Web Formsの「ページ間ポスティング」的な実装も書けるが、
View と Controller の関係が複雑になるのでオススメしない。
従って、上記の「4.」で、どの View に表示の指示をするかによって、
使用する ActionResult? クラスを下記のように変える様に実装する。
- その Controller に対応する View に、表示を指示する場合
- 別の Controller に対応する View に、表示を指示する場合
- RedirectToActionResult? または RedirectToRouteResult? を使用する
モバイル対応 †
Mobil Template †
「モバイル アプリケーション」テンプレートを使用して、
モバイルデバイス向けアプリケーションを作成できる。
このテンプレートでは、jQuery Mobile をベースとしており、
タッチ操作に最適化した UI を構築できる。
DisplayModes? †
Bootstrapによるレスポンシブデザインに頼らず、
PC 向けサイト、モバイル向けサイトの画面を分けるアプローチ。
- DesktopかMobilかは、UserAgent?やUserHostAddress?を使用して判別している。
- 通常、XXXXX.cshtmlとXXXXX.Mobil.cshtmlの2つのViewスクリプトを作成する。
上記は、マスタページや部分ViewなどのViewスクリプトにも適用することができる。
- XXXXX.cshtml (PC 向けサイト)
- XXXXX.Mobil.cshtml (モバイル向けサイト)
- 以下のコードを追加してデバイスごとにXXXXX.YYYYY.cshtmlとViewスクリプトを追加する。
- Global.asax の Application_Start メソッドに定義する。
protected void Application_Start()
{
(中略)
DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone ")
{
ContextCondition = (context => context.GetOverriddenUserAgent().IndexOf("iPhone ", StringComparison.OrdinalIgnoreCase) >= 0)
});
}
この時、
- 「XXXXX.cshtml」と同じフォルダに
- 「XXXXX.iPhone.cshtml」を作成し、
iPhone 向けのレイアウトを定義すると、
http://server/application/Controller/Index/id
という同じ URL に対し、
- PC のブラウザからアクセスした場合、「Index.cshtml」が使用され、
- iPhone からアクセスした場合は「Index.iPhone.cshtml」が使用されるようになる。
情報の持ち回り・状態管理方式 †
ViewState? †
利用不可能
必要であれば、
ViewState?相当の状態保存処理を独自実装する必要がある
(For付きのViewヘルパー(Html.xxxxFor)を使用する)。
Hidden †
使用可能
Session †
使用可能
検証機能 †
Action メソッド内で個別にチェックロジックを実装するか、
ModelMetadata?を使用したチェックが可能。
Model側 †
検証属性 †
以下の属性を使用して検証可能。
項番 | 属性 | 概要 |
1 | DataType属性(enumDataType?, errmsg) | 指定のデータ型に変換可能か |
2 | Required属性(errmsg) | 必須入力 |
3 | StringLength?属性(max, errmsg) | 文字列の最大長 |
4 | MaxLength?属性(max, errmsg) | 文字列の最大長 |
5 | MinLength?属性(min, errmsg) | 文字列の最小長 |
6 | Range属性(min, max, errmsg) | 範囲 |
7 | RegularExpression?属性(pattern, errmsg) | 正規表現 |
8 | MembershipPassword?属性() | パスワード |
9 | Compare属性(targetname, errmsg) | 比較(e-mailやpasswdの確認用フィールドに使用する) |
10 | Remote属性(actionMethod, errmsg) | Ajaxを使用したチェック |
11 | CustomValidation?属性() | カスタム |
各属性の errmsgプロパティに何も設定しなくても既定でエラーメッセージが出る。
DataType属性も検証属性として機能する。
CustomValidation?属性 †
ざっくり、以下のようにして、CustomValidation?属性を使用する。
- 単項目チェック処理
- プロパティにCustomValidation?属性を設定し、呼び出す検証メソッドと関連付ける。
- CustomValidation?属性に設定した、staticの検証メソッドを定義する。
- 検証メソッドでは、検証結果として、ValidationResult?を返す。
- 関連チェック処理
- モデルにCustomValidation?属性を設定し、呼び出す検証メソッドと関連付ける。
- CustomValidation?属性に設定した、staticの検証メソッドを定義する。
- 検証メソッドでは、検証結果として、ValidationResult?を返す。
自作Validation属性 †
ざっくり、以下のようにして、自作Validation属性を定義して使用する。
- 単項目チェック処理
- プロパティに自作Validation属性を指定して検証パラメタやエラーメッセージを指定する。
- 自作Validation属性の作成
- ValidationAttribute?クラスを継承した自作Validationを定義する。
- コンストラクタを実装
検証パラメタとエラーメッセージを準備(必要に応じてパラメタライズ)
- メソッドをoverrideして実装する。
- FormatErrorMessage?メソッドでエラーメッセージを生成
- IsValid?メソッドで検証処理を実装し、検証結果として、boolを返す。
- 自作Validation属性をクライアント側検証に対応させる。
- IClientValidation?インターフェイスを実装する。
- 属性とViewの橋渡しを行なうGetClientValidationRule?メソッドを実装する。
- GetClientValidationRule?メソッドでは、IEnumerable<ModelClientValidationRule?>を返す。
- これにより、検証名に対応する検証パラメタとエラーメッセージがHTML側に属性として出力される。
- jQuery Validation プラグインとの関連付け。
検証ロジックとを独自jsファイルに定義する。
- $.Validator.addMethod('検証名'~、
- $.validator.unobtrusive.adapters.addSingleVal?('検証名', '検証パラメタのKey');。
- BundleConfig?.csに、この独自jsファイルをjqueryvalにincludeするバンドル定義を追加する。
IValidatableObject?の実装 †
ざっくり、以下のようにして、IValidatableObject?を使用する。
複数の検証結果を返せるのは、IValidatableObject?だけである。
- 関連チェック処理(IValidatableObject?)
- モデルでIValidatableObject?を実装してIValidatableObject?.Validateメソッドを実装する。
- 検証メソッドでは、検証結果として、IEnumerable<ValidationResult?>を返す。
Controller側 †
検証タイミング †
Action Methodの実行前に、モデル・バインディングが行われたタイミング。
ModelStateDictionary? †
- 概要
- Controller.ModelState?でアクセスできる。
- モデルの状態とモデル・バインディングの検証結果を含む。
- Property
- IsValid? プロパティ
モデル・バインディングの検証結果として、モデルの有効・無効を返す。
- Keysプロパティ
- Valuesプロパティ
- Method
- ModelState?.AddModelError?()
エラー情報を追加する。
View側 †
サーバ側 †
- Method
- Html.ValidationSummary?
すべての検証結果のエラー メッセージを要約する。
- Html.ValidationMessage?
個々の検証結果のエラー メッセージを表示する。
- Html.ValidationMessageFor?
個々の検証結果のエラー メッセージを表示する。
クライアント †
- 検証後に適用されるCSSクラス
これらのCSSクラスをSite.cssファイルに定義しておく。
- validation-summary-errors
ValidationSummary?メソッドによって出力されたメッセージの<div>要素(エラー有)
- validation-summary-valid
ValidationSummary?メソッドによって出力されたメッセージの<div>要素(エラー無)
- field-validation-error
ValidationMessage?メソッドによって出力されたメッセージの<span>要素(エラー有)
- field-validation-valid
ValidationMessage?メソッドによって出力されたメッセージの<span>要素(エラー無)
- input-validation-error
検証エラーが発生した要素
appSettings †
クライアント側検証の無効化 †
CustomValidation属性ではクライアント側検証が実行されない。
整合性をとるために、クライアント側検証の無効化を行なう。
<add key="ClientValidationEnabled" value="false" />
若しくは、自作Validation属性にクライアント側検証を実装する。
クライアント側検証に「控えめなJavaScript」のパラダイムが導入されている。
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
参考 †
スキャフォールディング †
概要 †
スキャフォールディング(Scaffolding)。
日本語で「足場」、「骨組み」の意味。
を自動で生成する機能。
- 通常、
- CRUDのAction Methodだけが自動生成される。
- Entity Frameworkによるデータ操作を行う場合、
Action Methodに加えて View も自動生成できる。
M(Model) †
- 使用するModelを選択する。
- Modelの新規作成も可能
C(Controller) †
- M(Model)の複数形 + Controllerという名称になる。
- Action Method
- Index
- Details
- Create
- Edit
- Delete
V(View) †
項番 | View名 | 対応するAction Method名 | 使用されるTemplate名 |
1 | Index.cshtml | Index | List |
2 | Details.cshtml | Details | Details |
3 | Create.cshtml | Create | Create |
4 | Edit.cshtml | Edit | Edit |
5 | Delete.cshtml | Delete | Delete |
テンプレートをオーバーライド †
ModelMetadata?を使用した開発 †
脆弱性 †
サニタイジング †
- HTML ヘルパーを使用すると、自動的にサニタイジングが行われる。
- Model のプロパティを直接 View に表示する場合は、自前でのサニタイジングが必要。
リクエスト検証 †
OAuth / OpenID 対応 †
Tags: :ASP.NET, :ASP.NET MVC