ASP.NET Core MVCのチュートリアルを丁寧にやってみた①(プロジェクトの作成からビューの追加まで)

ASP.NET Core

ASP.NET Core MVCを初めて触る人でも理解できるように、公式チュートリアルを丁寧に解説する記事を全4回に分けて作ってみました。

公式チュートリアルで少しわかりにくい表現をかみ砕いて説明したり、英語圏向けの表記を日本語向けに直したりしています。また、冗長と思われる部分を省いています。

第1回では、プロジェクトの作成から、コントローラーとビューの基本的な使い方までを見ていきます。(公式チュートリアルのパート1~3に対応)

ASP.NET Core MVC の概要
ASP.NET Core MVC の概要について説明します。

(2022.7.18)使用フレームワークを.NET 6に更新し、全体的に記事の内容を見直しました。

スポンサーリンク

本記事の対象

  • ASP.NET Core MVCの基本的な使い方を理解したい人
  • C#の基本文法がある程度わかる人

環境

  • Windows 10
  • Visual Studio Community 2022
  • .NET 6

準備と新規プロジェクトの作成

.NET 6を使用するにはVisual Studio 2022が必要なので、まだインストールしていない場合は下記リンクからインストールしてください。

Visual Studio 2022 | 無料ダウンロード
Visual Studio でコード補完機能、デバッグ、テスト、Git 管理、クラウド配置を使用して、コードを作成します。 無料のコミュニティを今日ダウンロードします。

また、Visual Studio Installerのワークロードに「ASP.NETとWeb開発」が追加されていない場合はインストールしておきましょう。

それではプロジェクトを作成します。
Visual Studio 2022の新規プロジェクトの作成画面を開き、「ASP.NET Core Web アプリ (Model-View-Controller) 」を選択してください。

プロジェクト名は公式チュートリアルと同様に「MvcMovie」にします。

フレームワークには「.NET 6.0 (長期的なサポート)」を選択し、「作成」をクリックします。

プロジェクトが作成できたら、上部の「MvcMovie」をクリックしてみてください。
プログラムが実行され、ブラウザが起動します。

以下のようなページが表示されれば成功です。
※もし「証明書をインストールしますか?」という確認が表示された場合は「はい」を選択してください。)

アドレスの「localhost」はアプリが動作してるコンピュータ自身を表す特殊なホスト名で、ここで実行されたアプリは自分のPCでしか見ることができません。

その後ろのポート番号は実行環境によって異なります。

(参考)起動するブラウザを変更したい場合は以下から変更できます。

コントローラーの追加

アプリの実装を開始する前に、MVCアーキテクチャについて簡単に説明します。

MVCアーキテクチャとは

ソフトウェアの設計思想の1つで、機能をM:モデル、V:ビュー、C:コントローラーの3つに分けて実装するものです。

3つの機能の主な役割は次のようになります。

  • モデル:アプリのデータ処理部分を担当。DBのデータ取得や更新などを行う。
  • ビュー:画面表示(UI)部分を担当。モデルのデータを画面に表示する。
  • コントローラー:アプリの全体的な制御を担当。クライアントからリクエストを受け付け、モデルに連携してデータを取得し、レスポンスとしてビューを返すといった一連の処理を行う。

このように異なる機能のロジックを分離することで、アプリの構造がわかりやすくなり、メンテナンスがしやすくなるといったメリットがあります。

コントローラーの追加とルーティングの説明

それではまずコントローラーを作成して、実際の挙動などを確認していきます。

プロジェクト作成時に「HomeController.cs」が自動的に作成されていますが、今回は新しいコントローラーを追加してみましょう。

ソリューションエクスプローラーの「Controllers」フォルダを右クリックして、「追加」→「コントローラー」をクリックします。

「MVCコントローラー – 空」選択します。

名前を「HelloWorldController」にして追加します。
※ASP.NET Core MVCではコントローラー名を必ず○○Controllerとする必要があります。

作成したHelloWorldController.csに、次の2つのpublicメソッドを追加します。

using Microsoft.AspNetCore.Mvc;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        // /HelloWorld にアクセスした時の処理
        public string Index()
        {
            return "Hello World!";
        }

        // /HelloWorld/Welcome にアクセスした時の処理
        public string Welcome()
        {
            return "Welcomeページです。";
        }
    }
}

このようにコントローラークラス内で定義されたpublicメソッドをアクションメソッドといいます。

F5でデバッグ実行し、/helloworldにアクセスすると「Hello World!」と表示されます。

/helloworld/welcomeに移動すると、Welcomeメソッドで設定したメッセージが表示されます。

このように、指定したURLに応じてコントローラーのアクションメソッドが実行されます。

このルーティングのルールは{コントローラー名}/{アクションメソッド名}/{パラメーター(省略可能)}となっており、Program.csのConfigureメソッド内で決められています。

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");


既定のルールでは、アプリを起動するとまずHomeControllerのIndexメソッドの内容が表示されます。

試しにコントローラー名をHelloWorld、アクションメソッド名をWelcomeに変えて実行してみると、初期表示はHelloWorldControllerのIndexメソッドの内容になります。

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=HelloWorld}/{action=Welcome}/{id?}");


では次にHelloWorldControllerのWelcomeメソッドを次のように変更してみます。

       public string Welcome(string name, int age = 1)
       {
           return $"名前:{name}さん, 年齢:{age}歳";
       }

第1引数に文字列型、第2引数に数値型の値(デフォルト値は1)を取るメソッドに変更しました。

これで /HelloWorld/welcome?name=Taro&age=20

のようなアドレスを指定すると、指定した値が画面に表示されます。

このようにnameおよびageパラメーターはクエリ文字列※で渡すことができます。

これはASP․NET Core MVCに備わっているモデルバインドシステム※によって実現されています。

※クエリ文字列とは

クエリ文字列(URLパラメーター)とは、サーバーに情報を送るためにURLの末尾につけ足す文字列(変数)のこと

「?」をURLの末尾につけ、その次に「パラメーター=値」をつけ、複数のパラメーターをつけたい場合は「&」を使用します。

※モデルバインドシステムとは

フォーム等から送信された値やクエリ文字列の値を自動で.NET 型に変換して、コントローラーのアクションメソッドに提供する仕組みです。

今回の処理の流れを簡潔に示すとこのようになります。

  1. URLでリクエストを受信
  2. アクションメソッドの最初の引数(今回はnameというstring型の変数)を検索
  3. クエリ文字列内のname=Taroを見つける
  4. 次の引数(ageというint型)を検索
  5. クエリ文字列内のage=20を取得
  6. 文字列の”20″を数値の20に変換
  7. Welcomeメソッドが呼ばれて引数に取得した値が渡される
ASP.NET Core でのモデル バインド
ASP.NET Core でのモデル バインドのしくみと、その動作のカスタマイズ方法について説明します。

最後に、先ほど説明していなかったパラメーターのidを指定した場合の挙動について見てみます。

Welcomeメソッドを以下のように書き換えます。

       public string Welcome(string name, int Id = 1)
       {
           return $"名前:{name}さん, ID:{Id}";
       }

そのうえで、/HelloWorld/welcome/3?name=Taroにアクセスしてみると以下のように表示されます。

今まではidを省略していましたが、今回はidを3と指定したことで、Program.csのURLパターンのidパラメーターと一致し、Welcomeメソッドに値が渡されました。

ビューの追加

今まではコントローラーで直接文字列を返していましたが、今後はビューテンプレートを返すように変更します。

Razorビューテンプレートの呼び出し

Razorとは、HTMLにC#の構文を埋め込んだテンプレートを生成することができる仕組みです。

テンプレートの拡張子は○○.cshtmlとなります。

まずHelloWorldControllerクラスのIndexメソッドを次のように書き換えます。

public IActionResult Index()
{
   return View();
}

今までは単純な文字列を返すだけだったので戻り値にstring型を指定していましたが、今回はIActionResult型を指定しました。

IActionResultを実装すると、RazorテンプレートやJSON形式の文字列をレスポンスとして返すことができたり、他のURLへリダイレクト処理ができたりと様々なパターンに対応できます。

このようにViewメソッドを引数なしで呼び出すと「/Views/コントローラー名/アクション名.cshtml」が返されます。
つまり今回の場合は「/Views/HelloWorld/Index.cshtml」が呼び出されます。

テンプレートの追加

Indexメソッドで返すためのテンプレートを作成しましょう。

まずViewsフォルダの直下に「HelloWorld」という名前のフォルダを作成します。
(Viewsフォルダを右クリックして、「追加」→「新しいフォルダー」)

次に、作成したHelloWorldフォルダを右クリックして「追加」→「ビュー」で「新規スキャフォールディング アイテムの追加」ウィンドウを開きます。

「Razorビュー – 空」を選択後、ファイル名を「Index.cshtml」として追加してください。

追加できたら、index.cshtmlの中身を書き換えます。

ViewData[“Title”]には各ページのページタイトルを設定します。

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

F5で実行し、/HelloWorld/ にアクセスしてみましょう。このように表示されれば成功です。

共通レイアウト

ヘッダーやフッターなど各ページに共通するレイアウトは、Views/Shared/_Layout.cshtmlに書かれています。

6行目のViewData[“Title”]には、先ほどのように各ページで指定したタイトルが代入されます。
34行目の@RenderBody()の部分では、各ページ固有のコンテンツを表示しています。

少し表記を変更してみましょう。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            © 2021 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

アプリの名称を「Movie App」に変更しました。
また、ヘッダーのアプリ名をクリックするとMovies/Indexに飛ぶようにしました。
※Moviesコントローラーは次回作成します。

F5で実行し、ヘッダーとフッターの文言が変更されていることを確認してみましょう。

※もし共通レイアウトを変更しても反映されない場合は、Ctrl + F5 キーを押して強制リロードしてみてください。

ちなみに、Views/_ViewStart.cshtmlの中身はこのようになっており

@{
    Layout = "_Layout";
}

ビューの処理にあたってまずこの_ViewStart.cshtmlが呼び出され、_Layout.cshtmlが各ページに適用されるという流れになります。

もし共通レイアウトを各ファイルに適用したくない場合はnullを指定すればOKです。

コントローラーからビューへデータを渡す

Welcomeメソッドでもビューテンプレートを返すように変更してみましょう。

既に登場したViewDataを使って、コントローラーからビューテンプレートにデータを渡します。

using Microsoft.AspNetCore.Mvc;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        // /HelloWorld
        public IActionResult Index()
        {
            return View();
        }

        // /HelloWorld/Welcome
        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = $"こんにちは!{name}さん";
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

nameとnumTimes変数をそれぞれViewDataに格納することで、ビューに渡すことができます。

ViewDataとは

ViewDataはすべての型を使用できる動的な辞書型オブジェクトで、実行時に型が決まるため「弱い型指定」と呼ばれます。

一方で、第2回で紹介するビューモデルは、コンパイル時に型チェックが行われるため「厳密な型指定」と呼ばれます。

弱い型指定のデータはビューモデルに比べて便利なものの、型チェックができない分エラーが発生しやすいといったデメリットがあるため、多用するのは避けるべきです。

詳しくは以下を参照してください。

ASP.NET Core MVC のビュー
ビューがアプリのデータ表示と、ASP.NET Core MVC でのユーザー操作を処理する方法について説明します。

Views/HelloWorldフォルダ内にWelcome.cshtmlを新規追加し、次のように書き換えます。

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

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

コントローラーから渡されたViewDataの中身をループで取り出し、リストで表示しています。

実行後に、/HelloWorld/Welcome?name=Taro&numtimes=4

というアドレスにアクセスしてみると、ViewData[“Message”]の内容がnumTimes分だけ繰り返されて表示されます。

プロジェクトの作成からビューを追加するまでの基本的な説明は以上です。

第2回では、ViewDataではなくビューモデルを使ってデータを渡す方法について見ていきたいと思います。

【参考書籍】

著:増田 智明
¥3,366 (2022/07/18 14:18時点 | Amazon調べ)
\楽天ポイント5倍セール!/
楽天市場

コメント

  1. かと より:

    これはありがたい・・・

    .NET6がリリースされたので、15年ぶりに色試してみようと思ったのですが、いろいろ拡張されまくってまって、どこから手を付けたらいいのか途方に暮れていたところでした。

    まずはひらひらさんのわかりやすいチュートリアルから手をつけてみようと思います。

    感謝してます。
    ありがとうございました!

    • ひらひら より:

      コメントありがとうございます。
      15年前とは相当仕様が変わってしまっていますよね…
      私もまだまだ勉強中の身ですが、そう言っていただけるととても励みになります!
      いずれは.NET6に対応した記事も書いていきたいと思いますので、その際もぜひ参考にしていただけたら嬉しいです。

タイトルとURLをコピーしました