LoginSignup
17
17

More than 3 years have passed since last update.

ASP.NET Core MVC 3.1 入門 その5 「View」

Last updated at Posted at 2020-07-14

はじめに

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
言語
C#

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を読み込むためです。

image.png

一部の特殊なテンプレートについては、ViewsまたはViews/Sharedに配置します。特殊なテンプレートについては、後述します。

image.png

Viewスクリプト

Viewテンプレート内に記述するスクリプトです。
Viewエンジン固有の言語(Razor)で記述していきます。

Viewを追加する

では実際にViewを作ってみましょう。

ASP.NET Core MVC 3.1 のプロジェクトを作成する

まずは「Web アプリケーション(モデル ビュー コントローラー)」テンプレートでプロジェクトを作成します。

image.png

ソリューションエクスプローラーを眺める

各フォルダ/ファイルの概要についてはこちらの記事をご参照ください。
前述したとおり、Viewテンプレートは/Views/コントローラー名/アクションメソッド名.cshtmlに配置するようにしましょう。

image.png

Controller の追加

HelloControllerを追加します。
Controllerについてはこちらの記事をご参照ください。

public class HelloController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

View の追加

新しい View を追加してみます。

アクションメソッド(Indexメソッド)のメソッド名を右クリック > ビューの追加

image.png

と進んでください。

スキャフォールディング

以下のようなウィンドウが立ち上がると思います。
「スキャフォールディング」というのは、要は雛形を自動生成する機能のことを示します。
今回はViewの雛形を自動生成してもらうために、この機能を使います。

自動で/Views/コントローラー名/に配置してくれたり、指定したモデルクラスの新規作成(Create)や一覧表示(List)のテンプレート(Bootstrap向けのcssセレクタまで付与されたもの)を用意してくれたりと、手間が省けるので、 Viewを追加する際には、この手順でスキャフォールディング機能を利用することをおすすめします。

今回は「Razor ビュー」> 「Empty(モデルなし)」を選択します。
上述した通り、よりリッチなテンプレートもありますが、まずはシンプルなViewを使っていきましょう。

image.png

続いてビュー名ですが、アクションメソッド名とします。
アクションメソッドで呼び出されるViewメソッドが
明示的に指定しない限り、/Views/コントローラー名/アクションメソッド名.cshtmlを読み込むためです。

image.png

無事にHelloコントローラーのIndexアクションメソッドと対応する View(Index.cshtml) を追加することができました。

image.png

Viewのコードを確認する

以上でViewは追加できたと思います。
では、追加されたViewを見ていきましょう。

Index.cshtml

まず注目して頂きたいのは<h1>タグです。
Viewスクリプトには、お馴染みの HTML/CSS/Javascript をゴリゴリ書いていくことができます。
HTML/CSS/Javascript を用いてページの構成を作りつつ、C#のコードを利用して動的な値を埋め込んでいくというのがView開発の流れになります。

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

次に@ViewDataといった見慣れない構文が目に付くかと思います。これらの構文については後述します。

説明の便宜上、HelloControllerIndex.cshmlに少々手を加えます。

まずはHelloControllerIndexメソッドを以下のように修正します。

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.csConfigureメソッドを以下のように修正し、HelloControllerIndexアクションメソッドが呼び出されるように、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アクションメソッドで設定した値が画面に表示されれば成功です。

image.png

View変数(ViewBag/ViewData)

<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>

ViewBagViewDataをView変数と呼びます。
要はViewスクリプトに埋め込む値のことです。
Controller のアクションメソッドから View にデータを渡すことができます。

Controller側で表示に必要なデータを用意しておき、Viewではデータを埋め込む場所や表示方法を定義する

というのが ControllerView の基本的な関係となります。

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を使うと、ViewDataDictionaryベースの読みづらいコードを記述する必要はなくなりますが、DLRによって解釈されるコードを使いたくないのであればViewDataをおすすめします。

多用は禁物

View変数の利用は、 Controller から View にデータを渡す最も単純な方法です。

ただし、多用は禁物です。
型の指定ができないので、例えば ControllerView を別の開発者が担当していた場合、 View 側の開発者からすれば、一体どんなデータが設定されてくるのか、見当がつかないかもしれません。

そんな時は、後々記事としてあげますが、強く型指定されたViewModelを利用すべきと筆者は考えます。

@(コードナゲット)

続いて、@について説明していきます。
Viewスクリプトにおいて、C#のコードであることを示すキーワードです。

一行の場合、明示的に閉じる必要はありません。(セミコロンは不要です)コード行がどこで閉じるか解析してくれます。

<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>

コードブロックを記述したいときは@{...}とします。

@{
    ViewData["Title"] = "Index";
}

特殊なViewテンプレート

特定のアクションメソッドと対応しない特殊なViewが存在します。
ここでは最も基本的な2つを紹介します。

レイアウトページ(_Layout.cshtml)

まずは動作確認

再度実行してみましょう。
以下のような画面が表示されると思います。

image.png

少々違和感があります。
Index.cshtmlに記述したコードはこれだけです。
にも関わらず、それっぽいヘッダーやフッターが付いていますね。

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<h2>@ViewBag.Message</h2>
<p>@ViewData["Now"]</p>

これはレイアウトページ(_Layout.cshtmlという仕組みによるものです。
複数のページで共通するデザインの外枠を定義するための仕組みです。
レイアウトページを指定しておくと、ヘッダー、フッター、サイドメニューといった共通のデザインを一か所にまとめることができます。

変更する際も、レイアウトページだけを変更すれば一気に適用されるので、保守性も高まります。

レイアウトページはViews/Shared/に格納されています。
レイアウトページだけではなく、複数のViewテンプレートから利用し得るものは基本ここに配置します。

image.png

_Layout.cshtmlのコードを確認しましょう。
headerfooterの間に以下のコードが見つかると思います。

@*省略*@
    <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の処理に当たって、最初に処理される特別なファイルです。

重要なのはレイアウトページと異なり、名前空間もファイル名も固定です。

image.png

役割

一般的にはViewで使用するレイアウトページを指定するコードを記述します。実際にテンプレートでも_Layoutをレイアウトページとして扱う旨のコードが記述されていることが確認できます。

ただし、個別のViewでレイアウトページを改めて指定した場合はそちらが優先されます。

@{
    Layout = "_Layout";
}

これが、ただのViewテンプレートの1つに過ぎない_Layout.cshtmlがレイアウトページとして検出されている理由です。_ViewStart.cshtmlで指定されていたというわけです。

他にも、View関連のスタートアップコードが必要な場合はここに記述します。

規約

ファイル名

_ViewStart.cshtml

配置場所(名前空間)

Views/ 直下

以上です。
ありがとうございました。

17
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
17