「マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。
目次 †
概要 †
MVC †
「ASP.NET MVCの用語」は
「ASP.NET MVCの利用方法」と比べて、
ASP.NET MVCの基本的なトピックをまとめています。
M(Model)に実装される処理 †
Modelには、
- B層クラスと、
- B層クラスが返すViewに渡されるEntity, Bean, POCO的なクラス(ViewModel?)
がある。
V(View)に実装される処理 †
View = 画面表示のための処理。
- マスタページ的なViewと、
- 全体View
- 部分Viewがある。
C(Controller)に実装される処理 †
- Action Methodを実装する。
- Action Methodは、
- 「M(Model)」を呼び出して
- 「(Bean≒M)」を取得して
- 「V(View)」呼び出す。
モジュールの作成順 †
- C(Controller)を作成
- V(View)を作成
- M(Model)を作成
- C(Controller)にAction Methodを追加し、C→M→Vと繋げる。
C(Controller)関連 †
URL ルーティング †
ルート定義 †
- ルート定義に従い、URLからControllerやAction Methodに処理を振り分ける。
- ユーザがブラウザに URL を入力すると、
指定したルーティング規則を使用し、URL が解析され、Controllerのパスが特定される。
既定のルート定義 †
- 既定のルート定義は、RouteConfig?.RegisterRoutes?メソッドで定義されている。
- ココでMapRoute?()メソッドを使用し、ルートパラメタ(routeName, routeValues)を登録する。
- ルートパラメタ(routeName, routeValues)は、URLの作成にも使用される。
- デフォルトでは以下のようにルート定義されている(自由にカスタマイズ可能)
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
属性ルーティングによるルート定義 †
- また、パラメタについて、以下の様な設定を行うことができる。
- オプション設定
- 既定値の設定
- 制約条件の設定
- データ型指定
- 値範囲指定
- 正規表現指定
- カスタム制約条件指定
ルートプレフィックスの定義 †
ルートプレフィックスを使用すると、モデルレベルに、
「URL with parameters」のルート部分の定義を追加できる。
呼び出されるAction Methodとその引数 †
この時、ブラウザから
http://server/applicationname/Products/Index/1
というURLでリクエストを送信した場合、
http://(Server FQDN名)/(Controller名)/(Action Method名)/(id 値)
ルート定義に従い、ページハンドラは
- Controller名:Products
- Action Method名:Index
- id (Action Methodに渡す値):1
と判断し、
Products Controllerの Index Action Methodを呼び出し、Action Methodの引数として "1" を渡す。
Action Method名と id 値は省略可能で、Action Method名を省略すると、Index Action Methodが実行される。
Action Method †
リクエストデータの取得方法 †
- 単方向バインディング
POST や GET のパラメタの名前と一致した引数を定義しておけば、自動的にマップされる。
- Get ならクエリ文字列のキー名
- Post ならフォームデータのキー名
- モデルバインディング
Modelクラスを使うこともできる(Property名と一致させる)。
- 双方向バインディング
- ControllerのActionMethod?とViewの間に、
ポストバック的な復元動作がある場合に便利。
- Modelクラスを使う(Post の場合のみ)。
- その他
- FormCollection? を使う (Post の場合のみ)
<form> の中身がコレクション型として保持されたもの。
戻り値 †
Action Methodの結果として、Action Resultを返す。
詳細はAction Resultを参照。
単方向バインディング †
- クライアントから送信されてきたデータのキー名と、
ControllerのAction Methodの引数名とが一致するキー値を探して、バインドする。
- 非常に単純な仕組みのため、ASP.NET Web Formsに比べて、
単体テストが遣り易くなっている反面、オーバーポスティング攻撃を受け易く、
セキュリティ的に脆弱とまでは言えないが、課題があると言える。
ValuProvider? †
Requestを検索してValueを取得するクラス。
- 既定のValuProvider?
項番 | ValuProvider? | 値取得元 |
1 | ChildActionValueProvider? | 子アクション |
2 | FormValueProvider? | フォーム値 |
3 | RouteDataValueProvider? | Routeデータ |
4 | QueryStringValueProvider? | クエリ文字列 |
5 | HttpFileCollectionValueProvider? | HTTPファイルのコレクション |
- その他のValuProvider?
項番 | ValuProvider? | 値取得元 |
1 | JsonValueProvider? | Json |
2 | CookieValueProvider? | Cookie |
3 | SessionValueProvider? | Session |
4 | ServerVariablesValueProvider? | ServerVariables? |
5 | TempDataValueProviderFactory? | TempData? |
- ValueProvider?の処理順
上記の既定のValuProvider?はController.ValueProvider?の順番と同じ
(同じキー名の場合、ValuProvider?の順に先勝になる)
- ValueProvider?の追加
以下のValueProviderFactory?で順に新規ValueProvider?を追加できる。
- カスタムValueProvider?の自作
カスタムのValueProvider?を実装するために以下のI/Fを使用する。
- IValueProvider?(値プロバイダーに必要なメソッドを定義)
- IEnumerableValueProvider?(列挙に必要なメソッドを定義)
- IUnvalidatedValueProvider?(検証スキップに必要なメソッドを定義)
ModelBinder? †
- ModelBinder?は、ValuProvider?から必要なデータを取得し、Modelに対して値の設定を行う。
- DefaultModelBinder?は、前述の「既定のValuProvider?」から必要なデータを検索する。
ModelBinder?属性 †
前述のModelBinder?の動作を制御する。
通常、
- コレクション系はForm
- プリミティブ型はQueryString?
から取得するようになっているが、
以下の属性をAction Methodの引数に対して使用すると、この動作を変更できる。
- FromUri?属性
QueryString?から値を取得するように制御。
- FromBody?属性
Formから値を取得するように制御。
Bind属性 †
ASP.NET MVCは、ASP.NET Web Formsと比べて、
オーバーポスティング攻撃を受け易いため引数を明記する仕組み。
- 設定方法
Action Methodに以下の様な属性を付与する。
- [Bind(Include = "PropName1, PropName2...")]
- [Bind(Exclude = "PropName3, PropName4...")]
- [Bind(Include = "PropName1, PropName2...", Exclude = "PropName3, PropName4...")]
参考 †
- DefaultModelBinder?
- ValueProvider?
双方向バインディング †
- ControllerのActionMethod?とViewの間に、ポストバック的な復元動作がある場合に便利。
- Modelクラスを使う(Post の場合のみ)。
@modelで定義したModelプロパティと、
のHtmlヘルパーを使用する。
双方向バインディングの方法 †
以下のように双方向バインドする。
- Controller
return View(vm);
通常、Modelプロパティは、Modelでアクセスするが、
ここでのmodelはラムダ式の仮引数名なので自由。
- XxxxxForメソッドは、モデルバインディングに対応する
- 要素名(id, name属性)を自動で設定するため、
- 要素名(id, name属性)を指定する引数が無い。
Action Result †
Controller のAction Methodは、View の選択と指示として、
ActionResult クラスのオブジェクトを返す必要がある。
Action Methodで、
return View();
と、Viewを指定しないoverloadで呼び出すと、
/Views/コントローラ名/アクション名.cshtml
を呼び出す。
ActionResult?の種類とヘルパー・メソッド †
ActionResult? クラスには、以下の種類が存在する。
項番 | 種類 | 概要・用途 | コード例(ヘルパー・メソッド) |
1 | ViewResult? | 指定された全体 View の表示を指示する。 基本的には HTML.BeginForm の場合に使用する。 | return View("Result"); ("Result" は全体 View 名) |
2 | PartialViewResult? | 指定された部分 View の表示を指示する。 基本的には Ajax.BeginForm の場合に使用する。 | return PartialView?("Result"); ("Result" は部分 View 名) |
3 | RedirectResult? | 指定した URL にリダイレクトする場合に使用する。 | return Redirect("http://www.wings.msn.to/"); |
4 | RedirectToActionResult? | 指定した Controller, Action にリダイレクトする場合に使用する。 | return RedirectToAction?("Index"); |
5 | 指定したルートパラメタ(routeName, routeValues)にリダイレクトする場合に使用する。 | return RedirectToRoute?("View Product", new { ProductName? = <商品名> }); |
6 | FilePathResult? | 指定されたパスの内容をファイルとして出力 | return File("C:\temp\file.zip", "application/zip", "file.zip"); |
7 | FileContentResult? | byte配列の内容をファイルとして出力 | return File(bytes, "application/pdf"); |
8 | FileStreamResult? | ストリームの内容をファイルとして出力 | return new FileStreamResult?(fileStream, "application/pdf"); |
9 | ContentResult? | プレーン・テキストを出力(CSV出力等) | Return Content("こんにちは、世界!", "text/plain"); |
10 | JsonResult? | 指定されたコンテンツをJSONとして出力(Ajax通信) | return Json(JsonConvert?.SerializeObject?(result), JsonRequestBehavior?.AllowGet?); |
11 | JavaScriptResult? | 指定されたコンテンツをJavaScriptスクリプトとして出力 | return JavaScript(code); |
12 | EmptyResult? | 何もしない | - |
- 連載:ASP.NET MVC入門:第3回
ActionResult?オブジェクトでアクション操作も自由自在 - @IT
HttpStatusCodeResult? †
Viewではなく、HTTP状態コードを返す。
項番 | 種類 | 概要・用途 | コード例(ヘルパー・メソッド) |
1 | HttpStatusCodeResult? | 任意のHTTP応答コードをセット | - |
2 | HttpUnauthorizedResult? | HTTP応答コード「401 Unauthorized」をセット | - |
3 | HttpNotFoundResult? | HTTP応答コード「404 NotFound?」をセット | - |
ActionResult?の自作 †
可能
属性 †
フィルタ属性 †
- フィルタ属性は、ActionMethod?に、以下の様な共通的な処理を追加するために使用する。
- フィルタ属性は、以下に設定可能である。
項番 | 適用範囲 | 設置場所 | 説明 |
1 | ActionMethod? Filter | ActionMethod? | ActionMethod?単位 |
2 | Controller Filter | Controller | Controller単位 |
3 | Global Filter | FilterConfig? | Application単位 |
- 以下のフィルタ属性分類があり、実装される処理は項番の順番に呼び出される。
項番 | 分類 | 実装するI/F | 実装する処理 |
1 | 認証 | IAuthenticationFilter? | 認証に関係する処理 |
2 | 承認 | IAuthorizationFilter? | 承認(認可)に関係する処理 |
3 | Action | IActionFilter? | ActionMethod?の開始処理の前後処理 |
4 | Result | IResultFilter? | ActionMethod?の終了処理の前後処理 |
5 | 例外 | IExceptionFilter? | 例外処理 |
6 | Override | IOverrideFilter? | 上位フィルタを上書き |
- 標準のフィルタ属性には以下の様なものがある。
項番 | 分類 | 属性 | 概要 |
1 | 承認 | Authorize属性 | 認証済みアクセス(Cookie認証、Token認証) |
2 | 承認 | ChildActionOnly属性 | 子アクションとしてのみ呼び出し可能に設定 |
3 | 承認 | RequireHttps?属性 | HTTPSアクセスのみ呼び出し可能に設定 |
4 | 承認 | ValidateInput?属性 | XSS対策に使用する。 |
5 | 承認 | ValidateAntiForgeryToken属性 | CSRF対策に使用する。 |
6 | 例外 | HandleError?属性 | <CustomErrors? mode="On or RemoteOnly?"/> +FilterConfig?に設定した時のカスタムエラーページの定義 |
7 | Action/例外/Result | OutputCache?属性 | 出力キャッシュルールの定義 |
8 | Action/Result | AsyncTimeout?属性 | 非同期処理のタイムアウトの定義 |
9 | Override | OverrideAuthentication?属性 | グローバル・モデルなど上位で定義されたフィルタを上書き |
OverrideAuthorization?属性 |
OverrideAction?属性 |
OverrideResult?属性 |
OverrideException?属性 |
セレクタ属性 †
ControllerからのActionMethod?の呼び出しを制御する。
項番 | 属性 | 概要 |
1 | HttpXxxxx属性 | Action Methodが受け付けるHTTP Methodを指定 |
2 | AcceptVerbs属性 | Action Methodが受け付ける1つ以上のHTTP Methodを指定 |
3 | NonAction?属性 | Action Methodでないことを明示する。 |
4 | ActionName属性 | Action Method名と別名のAction Nameを付与する。 |
セレクタ属性は、自作可能。
非同期Controller †
この技術の登場の背景には C10k problem (C10K問題)と言うものがある模様。
- 非同期Controllerを使用すると、async/awaitを使用し、
Webサーバのスレッド枯渇を防ぐことができる。
- 実行に時間のかかる CPU バインド以外の要求に非同期Controllerを使用すると、
Webサーバの待機スレッドを他に転用可能になるので、Webサーバのスレッド数を節約し、
スレッド枯渇による「HTTP 503 (サーバーがビジー状態です。)」を防止できる。
- 図から、リクエスト処理開始時とレスポンス処理終了時のスレッドが変わることが解る。
後のスレッドは独立したスレッドプールから取得する。複雑なのでオーバーヘッドがある。
内部的には、I/O完了ポートを使用しているものと思われる。
使い方 †
- 旧(AsyncController?を継承する。)
- AsyncController? を継承する。
- 以下の命名規約を守ったAction Methodを定義する。
- ActionNameAsync?
- ActionNameCompleted?(delegate)
- Task<ActionResult?>を返す。
MVC 4 以降であれば、以下のように書ける。
参考 †
M(Model)関連 †
ここでは、B層クラスではなく、
「B層クラスが返すViewに渡される
Entity, Bean, POCO的なクラス(ViewModel?)」
について説明する。
ViewBag?, ViewData?, TempData? †
ControllerからViewにデータを渡すときに使用する入れ物的なモノ。
ViewBag? †
- ViewBag? は dynamic object。
ViewData? †
TempData? †
- TempData? は Dictionary。
- TempData? は保持されるため、リダイレクト先に値を渡したいときなどに使う。
- TempData? の詳しい動作は、以下が参考になる。
Modelプロパティ †
Viewスクリプトから強く型付けされたViewModel?を参照する際に使用する。
使い方 †
- 次の構文に置き換える。
@model ViewModelClass
- @modelキーワードで指定したViewModel?に対しては、Modelプロパティでアクセスする。
- ControllerからViewにModelを渡す。
return View(vm);
- ViewスクリプトでModelを使う。
@Model ViewModel
参考 †
V(View)関連 †
View には、
ビューエンジン †
Webページのビューエンジンには以下の2つのものがある。
ASPX †
従来の ASP.NET と同様、
式やコードブロックを コード・ナゲット(<% ~ %>)で囲む記述形式。
View の拡張子も、従来の ASP.NET と同様、「*.aspx」で表される。
Razor(主流) †
ASP.NET MVC 3 で登場したビューエンジン。
式やコードブロックの先頭に「@」を付与する記述形式で、
冗長なコード・ナゲット(<% ~ %>)が不要になる。
View の拡張子は、C# の場合は「*.cshtml」、VB の場合は「*.vbhtml」で表される。
参考 †
全体 View †
通常のViewはコレ。
部分 View †
部分 View は、「Partial View」ともいわれ、以下の用途で使われる。
配置場所 †
- /View/Shared/_XXXXPartial.cshtml
- /View/Controller名/_XXXXPartial.cshtml (優先)
使用方法(部分Viewだけ呼び出す) †
使用方法(Action Methodと部分Viewの両方を呼び出す) †
- 子Action Methodの呼び出し
- 通常
@Html.Action("XXXX", model)
- HTML文字列を戻さず、応答ストリームに直接書き出す。
ViewDataDictionary?の独自のコピーを取得するので、親のViewData?には影響を与えない。
@{ Html.RenderAction("XXXX", model); }
Htmlヘルパー †
(Viewヘルパーという呼称もあるようだが、
ここではHtmlヘルパーという呼称に統一する)
従来の ASP.NET では、ASP.NET Web コントロールを使用して、
ラベルやテキストボックスなどのコントロールを表示していたが、
ASP.NET MVC では、基本的に、以下の様な便利な機能が実装されているHtmlヘルパーを使用する。
主な Htmlヘルパー †
ASP.NET MVC では、主に以下のような Htmlヘルパーが使用できる。
- 表示のためのHtmlヘルパー
項番 | HTMLタグ | Htmlヘルパー |
1 | データの表示 | Html.DisplayFor? |
2 | 入力可能なデータの表示 | Html.EditorFor? |
3 | ラベルの表示1 | Html.DisplayNameFor? |
4 | ラベルの表示2 | Html.LabelFor? |
- HTMLタグに対応したHtmlヘルパー
項番 | HTMLタグ | Htmlヘルパー |
1 | フォーム <form> | HTML.BeginForm または Ajax.BeginForm |
2 | リンク <a> | Html.ActionLink? |
3 | テキストボックス <input type="text"> | Html.TextBox? または Html.TextBoxFor? |
4 | テキストエリア <textarea> | Html.TextArea? または Html.TextAreaFor? |
5 | パスワード <input type="password"> | Html.Password または Html.PasswordFor? |
6 | チェックボックス <input type="checkbox"> | Html.CheckBox? または Html.CheckBoxFor? |
7 | ドロップダウンリスト <select> | Html.DropDownList? または Html.DropDownListFor? |
8 | リストボックス <select> | Html.ListBox? または Html.ListBoxFor? |
9 | ラジオボタン <input type="radio"> | Html.RadioButton? または Html.RadioButtonFor? |
10 | 隠しフィールド <input type="hidden"> | Html.Hidden または Html.HiddenFor? |
- URL生成
項番 | HTMLタグ | Htmlヘルパー |
1 | 「~/...」を仮想パスに変換 | Url.Content |
2 | Controller、ActionMethod?名などから仮想パスを生成 | Url.Action |
3 | RouteValueDictionary?から仮想パスを生成 | Url.RouteUrl? |
- なお、ボタンを生成する Htmlヘルパーはないため、
直接 <input type="button"> または <input type="submit"> を記述する。
Modelバインディング用のHtmlヘルパー †
Html.xxxx と Html.xxxxFor の2種類のHtmlヘルパーがある。
- Html.xxxx
Model から View への単方向バインディング。
Html.TextBox?("Category") のように、
プロパティを文字列でマップ指定する場合は、
"For" がつかない Htmlヘルパーを使用する。
- ...Forという名称のHtmlヘルパーは、ViewとModelの間での双方向バインディングを行う。
- Html.TextBoxFor?(model => model.Category) のように、
プロパティをラムダ式でマップ指定する場合は、"For" で終わる Htmlヘルパーを使用する。
ただし、HTTP を経由しての双方向バインディングになるので、
処理方式的には、以下のような処理シーケンスになる。
- POST 時に、Html.TextBoxFor? などへの入力値を、自動的に Model に復元する。
- Controller は、復元された Model から情報を取得して処理を行う。
マスターページ †
ヘッダーやフッター、サイドメニューなどをアプリケーションで共通的に表示させたい場合、
マスターページを使用してレイアウトを共通化させることができる。
マスターページには、画面ごとに個別実装が必要な箇所を定義する。
ビューエンジン †
- ビューエンジンが ASPX の場合は、従来の ASP.NET と同様 ContentPlaceHolder? を使用する。
- ビューエンジンが Razor の場合は、RenderBody? を使用してメインのコンテンツ領域を定義する。
配置場所と使用方法 †
- アプリケーション共通
- 配置場所
- /View/Shared/_Layout.cshtml
- 使用方法
- View単位
- 配置場所
- /View/Shared/_XXXXLayout.cshtml
- /View/Controller名/_XXXXLayout.cshtml (優先)
- 使用方法
マスターページへのセクションの定義 †
メインのコンテンツ領域以外に、画面ごとに個別実装が必要な箇所を定義する場合、
RenderSection? を使用して「セクション」と呼ばれるサブのコンテンツ領域を定義する。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<!-- メインのコンテンツ領域を描画する場所を定義 -->
@RenderBody()
@Scripts.Render("~/bundles/jquery")
<!-- セクション (サブのコンテンツ領域) を描画する場所を定義 -->
@RenderSection("scripts", required: false)
</body>
</html>
マスターページの利用 †
- 上記のように、セクションを実装する場合、
- C# の場合は「@section <セクション名> { ~ }」、
- VB の場合は「@Section <セクション名> ~ End Section」
で囲む必要がある。
マスターページのネスト †
- /View/Controller名/YYYY.cshtml のLayoutプロパティ経由で呼び出される。
マスターページの選択 †
- ActionResult?で選択する場合、
if文などを使用して、return View()の第二引数に設定する部分View名を切り替える。
BeginForm? †
BeginForm?には以下の2つのものがある。
Html.BeginForm?の特徴 †
従来のASPなどでMVC方式を採用した場合と同じ、画面全体を再描画する仕組み。
@系 †
@inherits †
@modelに置き換えられた。
@model †
Viewスクリプトから強く型付けされたViewModelを参照する際に使用する。
@section †
マスタページを利用する際、定義されたsectionを実装する。
@helper †
Viewスクリプト内にHtmlヘルパーを定義。
Razor系 †
- コードナゲット(インライン式)
式の値の出力
- 通常のコードナゲット
@...
- 明示的なコードナゲット
@(...)
- コードブロック
- 値の代入
- メソッド呼び出し
- オブジェクトの生成
@{...}
- 制御構文(ネスト可能)
if, switch, while, for/foreach
- while
@while (flg)
{
・・・
}
- 静的コンテンツ化
- 単一行
@:
- 複数行
<text>・・・</text>
- コメント
- サーバーコメント
@* ... *@
- HTMLコメント
<!-- ... -->
フォルダ構成 †
既定のフォルダ構成 †
ASP.NET MVC のテンプレートは、グルーピングを目的に、既定で以下のフォルダ構成となっている。
それぞれのフォルダには、以下のようにファイルを配置することが推奨されている。
項番 | フォルダ名 | 配置されるファイル | 備考 |
1 | App_Start | 起動時に、初期設定を行うモジュール | - |
2 | Contents | CSS | BundleConfig? が使用しているため、既定の CSS ファイルは変更しない |
3 | Controllers | Controller | - |
4 | Models | Model | - |
5 | Scripts | JavaScript | BundleConfig? が使用しているため、既定の JavaScript ファイルは変更しない |
6 | Views | View | 対応する Controller 名のフォルダ以下に、View のファイルを配置する 例 Views\(コントローラー名)\Index.cshtml |
Area (区分)による分割 †
Area (区分) とは、ASP.NET MVC アプリケーションを論理的に分割する仕組みのことである。
(ASP.NET MVC プロジェクトをシステム全体とすると、Area ごとにサブシステム (のようなもの) に分割できる。
App_Start のマップルートが追加されるような感じ、と理解すると分かりやすいかもしれない)
Tags: :.NET開発, :ASP.NET, :ASP.NET MVC