はじめに
ASP.NET Core MVC 3.1 の View について、自分が学んだことを備忘録として記載します。
このフレームワークに殆ど触れたことが無い方に少しでも参考になれば幸いです。
誤り等あれば、ご指摘頂けますと大変喜びます。
前回の記事
ASP.NET Core MVC 3.1 入門 その4 「Routing」
今回の流れ
- MVCパターンの説明
- Viewの説明
- Viewを作ってみる
- 動かしてみる
- 特殊なViewテンプレートの説明
今回のゴール
- MVCパターンにおけるViewの役割を理解する
- Viewを追加できる
- 特殊なViewテンプレートとその役割を知る
本記事に含まれない内容
以下は別の記事で紹介する予定です。
@model @using @inject
- HTMLヘルパー/タグヘルパー
- 部分ビュー
- ビューエンジンとは
環境
- IDE
- Visual Studio 2019
<dt>言語</dt>
<dd>C#</dd>
MVCパターン
コントローラーの説明に入る前に、
まずはMVCパターンについて確認しておきましょう。
全体像を把握したうえで、View について具体的にみていきます。
MVCパターンとは
画面表示と、ビジネスロジックの分離を実現するためのアーキテクチャ(設計手法)です。
要はHTMLの生成といった画面表示のための処理と
DBアクセスのようなデータの管理/操作をするための処理
これらを分離させるために先人が考え出したプログラムの作り方の一つです。
MVCというのは構成要素の略称で、以下の単語の先頭文字をそれぞれ取り出したものです。
Model – View – Controller
実現できると、それぞれが分離しているので変更・修正があった場合、お互いに影響を受けづらく、Testability (テスト容易性) が高まるというメリットがあります。
画面に表示する項目の書式変更によってDBアクセス処理に影響が出たり、
DBの軽微な定義変更によって画面表示処理に影響が出るといった事態が発生しづらくなります。
各要素の役割
要素 | 概要 |
---|---|
Model | データの管理/操作といったビジネスロジックを担当 |
View | データ入力用のフォーム、処理結果の表示といったアプリケーションのフロントエンドを担当 |
Controller | ModelとViewの橋渡しを担当 |
View
Viewとは
MVCの全体像を把握したうえで、 View について具体的にみていきます。
MVCにおいて、 データ入力用のフォーム、処理結果の表示といったアプリケーションのフロントエンドを担当する要素です。
画面(HTML)の生成
というのが主なお仕事です。
後述するViewテンプレートとControllerから渡されるデータを組み合わせて出力するHTMLを生成します。
Viewの構成要素
Viewエンジン
View
メソッドの呼び出しによって起動し、
Viewテンプレートと、Controllerから渡されるデータを組み合わせて出力するHTMLを生成します。
ASP.NET Core MVC では「Razor」が既定のViewエンジンとして採用されています。
Viewテンプレート
拡張子が「.cshtml」のファイルです。
配置場所と命名
/Views/コントローラー名/アクションメソッド名.cshtml
とすることをおすすめします。
アクションメソッドで呼び出されるView
メソッドが
明示的に指定しない限り、/Views/コントローラー名/アクションメソッド名.cshtml
を読み込むためです。
一部の特殊なテンプレートについては、Views
またはViews/Shared
に配置します。特殊なテンプレートについては、後述します。
Viewスクリプト
Viewテンプレート内に記述するスクリプトです。
Viewエンジン固有の言語(Razor)で記述していきます。
Viewを追加する
では実際にViewを作ってみましょう。
ASP.NET Core MVC 3.1 のプロジェクトを作成する
まずは「Web アプリケーション(モデル ビュー コントローラー)」テンプレートでプロジェクトを作成します。
ソリューションエクスプローラーを眺める
各フォルダ/ファイルの概要についてはこちらの記事をご参照ください。
前述したとおり、Viewテンプレートは/Views/コントローラー名/アクションメソッド名.cshtml
に配置するようにしましょう。
Controller の追加
HelloController
を追加します。
Controller
についてはこちらの記事をご参照ください。
public class HelloController : Controller
{
public IActionResult Index()
{
return View();
}
}
View の追加
新しい View を追加してみます。
アクションメソッド(Indexメソッド)のメソッド名を右クリック > ビューの追加
と進んでください。
スキャフォールディング
以下のようなウィンドウが立ち上がると思います。
「スキャフォールディング」というのは、要は雛形を自動生成する機能のことを示します。
今回はViewの雛形を自動生成してもらうために、この機能を使います。
自動で/Views/コントローラー名/
に配置してくれたり、指定したモデルクラスの新規作成(Create
)や一覧表示(List
)のテンプレート(Bootstrap向けのcssセレクタまで付与されたもの)を用意してくれたりと、手間が省けるので、 Viewを追加する際には、この手順でスキャフォールディング機能を利用することをおすすめします。
今回は「Razor ビュー」> 「Empty(モデルなし)」を選択します。
上述した通り、よりリッチなテンプレートもありますが、まずはシンプルなViewを使っていきましょう。
続いてビュー名ですが、アクションメソッド名
とします。
アクションメソッドで呼び出されるView
メソッドが
明示的に指定しない限り、/Views/コントローラー名/アクションメソッド名.cshtml
を読み込むためです。
無事にHello
コントローラーのIndex
アクションメソッドと対応する View(Index.cshtml) を追加することができました。
Viewのコードを確認する
以上でViewは追加できたと思います。
では、追加されたViewを見ていきましょう。
Index.cshtml
まず注目して頂きたいのは<h1>
タグです。
Viewスクリプトには、お馴染みの HTML/CSS/Javascript をゴリゴリ書いていくことができます。
HTML/CSS/Javascript を用いてページの構成を作りつつ、C#のコードを利用して動的な値を埋め込んでいくというのがView開発の流れになります。
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
次に@
やViewData
といった見慣れない構文が目に付くかと思います。これらの構文については後述します。
説明の便宜上、HelloController
とIndex.cshml
に少々手を加えます。
まずはHelloController
のIndex
メソッドを以下のように修正します。
public IActionResult Index()
{
ViewBag.Message = "Hello World!"; //追加
ViewData["Now"] = DateTime.Now; //追加
return View();
}
続いてIndex.cshtml
も以下のように修正します。
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>
動作確認
ここまで来たら、実行してみましょう。
URLを書き換えるのが手間なので、Startup.cs
のConfigure
メソッドを以下のように修正し、HelloController
のIndex
アクションメソッドが呼び出されるように、Routingの設定をしておきます。
Routingについてはこちらの記事をご参照ください。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//省略
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Hello}/{action=Index}/{id?}"); //Home => Hello
});
}
Index
アクションメソッドで設定した値が画面に表示されれば成功です。
View変数(ViewBag/ViewData)
<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>
ViewBag
とViewData
をView変数と呼びます。
要はViewスクリプトに埋め込む値のことです。
Controller のアクションメソッドから View にデータを渡すことができます。
Controller側で表示に必要なデータを用意しておき、Viewではデータを埋め込む場所や表示方法を定義する
というのが Controller と View の基本的な関係となります。
ViewBag
Controllerでプロパティとして値を設定しておくと、 Viewで参照することができます。
View内で値を設定、参照することも可能です。
型を指定することはできず、Intelisenceも効きません。
public IActionResult Index()
{
ViewBag.Message = "Hello World!";
//省略
}
<h2>@ViewBag.Message</h2>
ViewData
Dictionary
としてキーと値を設定することができます。
用途はViewBag
と同様です。やはり型指定もできません。
public IActionResult Index()
{
ViewData["Now"] = DateTime.Now; //追加
//省略
}
<p>@ViewData["Now"]</p>
ViewBag vs ViewData
お好みで、どちらを採用しても良いと思います。
ViewBag
を使うと、ViewData
のDictionary
ベースの読みづらいコードを記述する必要はなくなりますが、DLRによって解釈されるコードを使いたくないのであればViewData
をおすすめします。
多用は禁物
View変数の利用は、 Controller から View にデータを渡す最も単純な方法です。
ただし、多用は禁物です。
型の指定ができないので、例えば Controller と View を別の開発者が担当していた場合、 View 側の開発者からすれば、一体どんなデータが設定されてくるのか、見当がつかないかもしれません。
そんな時は、後々記事としてあげますが、強く型指定されたViewModel
を利用すべきと筆者は考えます。
@(コードナゲット)
続いて、@
について説明していきます。
Viewスクリプトにおいて、C#のコードであることを示すキーワードです。
一行の場合、明示的に閉じる必要はありません。(セミコロンは不要です)コード行がどこで閉じるか解析してくれます。
<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>
コードブロックを記述したいときは@{...}
とします。
@{
ViewData["Title"] = "Index";
}
特殊なViewテンプレート
特定のアクションメソッドと対応しない特殊なViewが存在します。
ここでは最も基本的な2つを紹介します。
レイアウトページ(_Layout.cshtml)
まずは動作確認
再度実行してみましょう。
以下のような画面が表示されると思います。
少々違和感があります。
Index.cshtml
に記述したコードはこれだけです。
にも関わらず、それっぽいヘッダーやフッターが付いていますね。
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>
これは**レイアウトページ(_Layout.cshtml
)**という仕組みによるものです。
複数のページで共通するデザインの外枠を定義するための仕組みです。
レイアウトページを指定しておくと、ヘッダー、フッター、サイドメニューといった共通のデザインを一か所にまとめることができます。
変更する際も、レイアウトページだけを変更すれば一気に適用されるので、保守性も高まります。
レイアウトページはViews/Shared/
に格納されています。
レイアウトページだけではなく、複数のViewテンプレートから利用し得るものは基本ここに配置します。
_Layout.cshtml
のコードを確認しましょう。
header
とfooter
の間に以下のコードが見つかると思います。
@*省略*@
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
@*省略*@
重要なのは@RenderBody
という部分です。
ここに個別のViewスクリプト(例えばさきほど作成したIndex.cshtml
)が埋め込まれます。
これが、特に記述した記憶のないヘッダーやフッターが付いていた理由です。_Layout.cshtml
に記述されていたというわけです。
_Layout.cshtml
レイアウトページの名称は必ずしも_Layout.cshtml
である必要はありません。また、Views/Shared/
に格納しなければならないという規約もありません。
_Layout.cshtml
とはただのViewテンプレートの1つに過ぎないのです。
では、なぜ_Layout.cshtml
がレイアウトページとして検出されているのでしょうか?理由は後述します。
複数のレイアウトページ
これは雑記等、別の記事で紹介しますが、レイアウトページは複数用意することもできます。
例えば、メインのレイアウトページ、管理者用のレイアウトページ、未ログインユーザー向けのレイアウトページなどです。
_ViewStart.cshtml
ViewStart.cshtml
とは、Viewの処理に当たって、最初に処理される特別なファイルです。
重要なのはレイアウトページと異なり、名前空間もファイル名も固定です。
役割
一般的にはViewで使用するレイアウトページを指定するコードを記述します。実際にテンプレートでも_Layout
をレイアウトページとして扱う旨のコードが記述されていることが確認できます。
ただし、個別のViewでレイアウトページを改めて指定した場合はそちらが優先されます。
@{
Layout = "_Layout";
}
これが、ただのViewテンプレートの1つに過ぎない_Layout.cshtml
がレイアウトページとして検出されている理由です。_ViewStart.cshtml
で指定されていたというわけです。
他にも、View関連のスタートアップコードが必要な場合はここに記述します。
規約
ファイル名
_ViewStart.cshtml
配置場所(名前空間)
Views/
直下
以上です。
ありがとうございました。