パート 3、ASP.NET Core MVC アプリへのビューの追加

作成者: Rick Anderson

このセクションでは、Razor ビュー ファイルを使用するよう、HelloWorldController クラスを変更します。 これにより、クライアントへの HTML 応答を生成するプロセスが完全にカプセル化されます。

ビュー テンプレートは Razor を使用して作成されます。 Razor ベースのビュー テンプレートは次のとおりです。

  • ファイル拡張子は .cshtml です。
  • C# を使用して HTML 出力を作成する洗練された方法が提供されます。

現在、Index メソッドは、コントローラー クラスにメッセージを含め文字列を返します。 HelloWorldController クラスでは、Index メソッドを次のコードで置き換えます。

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

上記のコードでは、次のことが行われます。

  • コントローラーの View メソッドを呼び出します。
  • ビュー テンプレートを使用し HTML 応答を生成します。

コントローラー メソッドは次のとおりです。

  • "アクション メソッド" と呼ばれます。 たとえば、前のコードの Index アクション メソッドです。
  • 通常、string のような型ではなく IActionResult または ActionResult から派生したクラスを返します。

ビューを追加する

Views フォルダーを右クリックし、 [追加]、[新しいフォルダー] の順に選択し、フォルダーに HelloWorld という名前を付けます。

Views/HelloWorld フォルダーを右クリックし、 [追加]、[新しい項目] の順に選択します。

[新しい項目の追加 - MvcMovie] ダイアログで次を行います。

  • 右上の検索ボックスに「view」と入力します。
  • [Razor ビュー - 空] を選択します。
  • [名前] ボックスの値、Index.cshtml を維持します。
  • [追加] を選択します。

[新しい項目の追加] ダイアログ

Views/HelloWorld/Index.cshtml Razor ビュー ファイルを次の内容に置き換えます。

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

<h2>Index</h2>

<p>Hello from our View Template!</p>

次のように https://localhost:{PORT}/HelloWorld に移動します。

  • HelloWorldControllerIndex メソッドにより、ビュー テンプレート ファイルを使用して、ブラウザーに応答をレンダリングするようメソッドを指定する、ステートメント return View(); が実行されました。

  • ビュー テンプレートのファイル名が指定されていないため、MVC で既定のビュー ファイルが使われました。 ビュー ファイル名を指定しない場合は、既定のビューが返されます。 この例では、既定のビューの名前は、アクション メソッド Index と同じ名前が付けられています。 ビュー テンプレート /Views/HelloWorld/Index.cshtml が使用されています。

  • 次のイメージは、ビューにハード コーディングされた "Hello from our View Template!" という文字列を示しています。

    ブラウザー ウィンドウ

ビューとレイアウト ページを変更する

MvcMovieHomePrivacy の各メニューのリンクを選択します。 各ページには同じメニューのレイアウトが表示されます。 メニューのレイアウトは、Views/Shared/_Layout.cshtml ファイルに実装されています。

Views/Shared/_Layout.cshtml ファイルを開きます。

レイアウト テンプレートでは、次のことが可能です。

  • 1 か所でサイトの HTML コンテナー レイアウトを指定できます。
  • サイト内の複数のページに HTML コンテナー レイアウトを適用できます。

@RenderBody() という行を見つけます。 RenderBody は、作成したビュー固有のページがすべて表示されるプレースホルダーで、レイアウト ページに ラップ されます。 たとえば、 Privacy リンクを選択すると、RenderBody メソッド内で Views/Home/Privacy.cshtml ビューがレンダリングされます。

Views/Shared/_Layout.cshtml ファイルの内容を次のマークアップに置き換えます。 変更が強調表示されています。

<!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.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</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">
                <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-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 flex-sm-row-reverse">
                    <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">
            &copy; 2020 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>
<!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.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</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">
                <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-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">
            &copy; 2020 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

上記のマークアップでは、次の変更が加えられています。

  • MvcMovie から Movie App が 3 回発生します。
  • アンカー要素 <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a><a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a> になりました。

上記のマークアップでは、このアプリでは Area が使用されていないため、asp-area="" アンカー タグ ヘルパー属性と属性値が省略されています。

注: まだ Movies コントローラーは実装されていません。 この時点では、Movie App リンクは機能していません。

変更を保存し、 Privacy リンクを選択します。 ブラウザー タブのタイトルの表示が、 Privacy Policy - Mvc Movie ではなく、 Privacy Policy - Movie App になっていることに注目してください。

Privacy タブ

[Home](ログの一元化) リンクを選択します。

タイトルとアンカー テキストに Movie App と表示されていることに着目してください。 レイアウト テンプレートが一度変更され、この新しいリンク テキストと新しいタイトルがサイト上のすべてのページに反映されました。

Views/_ViewStart.cshtml ファイルを確認します。

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml ファイルは Views/Shared/_Layout.cshtml ファイルに取り込まれ、各ビューに適用されます。 Layout プロパティを使用すれば、別のレイアウト ビューを設定することも、null に設定してレイアウト ファイルが使用されないようにすることもできます。

Views/HelloWorld/Index.cshtml ビュー ファイルを開きます。

タイトルと <h2> 要素を、以下の強調表示どおりに変更します。

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

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

タイトルと <h2> 要素は若干違うので、コードのどの部分によって表示が変更されるのかを確認できます。

上のコードの ViewData["Title"] = "Movie List"; では、Title ディクショナリの ViewData プロパティを "Movie List" に設定します。 Title プロパティは、次のように、レイアウト ページの <title> HTML 要素で使用されます。

<title>@ViewData["Title"] - Movie App</title>

変更内容を保存して、https://localhost:{PORT}/HelloWorld に移動します。

次が変更されたことを確認します。

  • ブラウザー タイトル。
  • 1 番目の見出し。
  • 2 番目の見出し。

ブラウザーに変更がない場合は、キャッシュされたコンテンツが表示されている場合があります。 ブラウザーで Ctrl + F5 キーを押して、サーバーからの応答が強制的に読み込まれるようにします。 ブラウザーのタイトルは、Index.cshtml ビュー テンプレートで設定した ViewData["Title"] で作成されます。レイアウト ファイルには "- Movie App" が追加されます。

Index.cshtml ビュー テンプレート内のコンテンツは、Views/Shared/_Layout.cshtml ビュー テンプレートにマージされます。 1 つの HTML 応答がブラウザーに送信されます。 レイアウト テンプレートを使用すれば、アプリのすべてのページに適用される変更を簡単に行うことができます。 詳細については、「Layout」(レイアウト) を参照してください。

ムービー リスト ビュー

ここでは、"データ" のごく一部 (この場合は "Hello from our View Template!" という メッセージ) をハード コーディングしました。 MVC アプリケーションには "V" (ビュー) があり、"C" (コントローラー) もありますが、"M" (モデル) はまだありません。

コントローラーからビューへのデータの受け渡し

コントローラー アクションは、受信 URL 要求への応答として呼び出されます。 コントローラー クラスでは、受信ブラウザー要求を処理するコードが記述されます。 コントローラーはデータ ソースからデータを取得し、ブラウザーに返す応答の種類を決定します。 ビュー テンプレートを使用すれば、コントローラーからブラウザーへの HTML 応答を生成して書式を設定できます。

コントローラーは、ビュー テンプレートで応答をレンダリングするために必要なデータを提供します。

ビュー テンプレートでは、次を 行いません

  • ビジネス ロジックの実行
  • データベースとの直接のやりとり

ビュー テンプレートは、コントローラーから提供されるデータのみを処理する必要があります。 この "関心の分離" を維持すれば、コードを次のように保つことができます。

  • クリーン。
  • テスト可能。
  • 保守しやすい。

現時点では、HelloWorldController クラスの Welcome メソッドは nameID パラメーターを受け取ってから、ブラウザーに直接値を出力します。

コントローラーにこの応答を文字列としてレンダリングさせるのではなく、代わりにビュー テンプレートを使用するようにコントローラーを変更します。 このビュー テンプレートは、応答を動的に生成します。つまり、応答の生成には、コントローラーからビューに適切なデータが渡される必要があります。 そのためには、ビュー テンプレートが必要とする動的データ (パラメーター) を、コントローラーに ViewData ディレクトリに配置させます。 これにより、ビュー テンプレートが動的データにアクセスできるようになります。

HelloWorldController.cs 内で、Welcome メソッドを変更して Message および NumTimes 値を ViewData ディクショナリに追加します。

ViewData ディクショナリは、すべての型を使用できる動的なオブジェクトです。 ViewData オブジェクトには、何かが追加されるまで、プロパティは定義されていません。 MVC のモデル バインド システムは、namenumTimes の名前付きパラメーターをクエリ文字列からメソッドのパラメーターに自動的にマップします。 完全な HelloWorldController は次のとおりです。

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

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

        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

ViewData ディクショナリ オブジェクトには、ビューに渡されるデータが含まれています。

Views/HelloWorld/Welcome.cshtml という名前の [ようこそ] ビュー テンプレートを作成します。

"Hello" NumTimes を表示する Welcome.cshtml ビュー テンプレートでループを作成します。 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>

変更内容を保存し、次の URL を参照します。

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

データは URL から取得され、MVC モデル バインダーを使用してコントローラーに渡されます。 コントローラーはデータを ViewData ディクショナリにパッケージ化し、そのオブジェクトをビューに渡します。 その後、ビューでブラウザーに HTML としてデータがレンダリングされます。

[ようこそ] ラベルと、Hello Rick という語句が 4 つ示された Privacy ビュー

上のサンプルでは、ViewData ディクショナリを使用して、コントローラーからビューにデータを渡しました。 チュートリアルの後半では、ビュー モデルを使用して、コントローラーからビューにデータを渡します。 データを渡すには、ViewData ディクショナリを使用する方法より、ビュー モデルを使用する方法が推奨されます。

次のチュートリアルでは、ムービーのデータベースを作成します。

このセクションでは、クライアントに対する HTML 応答を生成するプロセスを完全にカプセル化するために、Razor ビュー ファイルを使用して、HelloWorldController クラスを変更します。

ビュー テンプレート ファイルは Razor を使用して作成します。 Razor ベースのビュー テンプレートには .cshtml ファイル拡張子が含まれています。 C# を使用して HTML 出力を作成する洗練された方法が提供されます。

現在、Index メソッドは、コントローラー クラスでハード コーディングされるメッセージを含む文字列を返します。 HelloWorldController クラスでは、Index メソッドを次のコードで置き換えます。

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

上のコードでは、コントローラーの View メソッドを呼び出します。 ビュー テンプレートを使用して、HTML 応答を生成します。 上記の Index メソッドなどのコントローラー メソッド (アクション メソッド ともいう) は、一般に、string などの型ではなく、IActionResult (または ActionResult から派生したクラス) を返します。

ビューを追加する

  • Views フォルダーを右クリックし、 [追加]、[新しいフォルダー] の順に選択し、フォルダーに HelloWorld という名前を付けます。

  • Views/HelloWorld フォルダーを右クリックし、 [追加]、[新しい項目] の順に選択します。

  • [新しい項目の追加 - MvcMovie] ダイアログ

    • 右上の検索ボックスに「view」と入力します。

    • [Razor ビュー] を選択します

    • [名前] ボックスの値、Index.cshtml を維持します。

    • [追加] を選択します。

[新しい項目の追加] ダイアログ

Views/HelloWorld/Index.cshtml Razor ビュー ファイルを次の内容に置き換えます。

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

<h2>Index</h2>

<p>Hello from our View Template!</p>

https://localhost:{PORT}/HelloWorld に移動します。 HelloWorldControllerIndex メソッドでは多くのことは行いませんでした。つまり、ステートメント return View(); を実行し、メソッドでビュー テンプレート ファイルを使用して、ブラウザーへの応答をレンダリングするよう指定しただけです。 ビュー テンプレートのファイル名が指定されていないため、MVC では既定のビュー ファイルが使われました。 既定のビュー ファイルはメソッド (Index) と同じ名前なので、 /Views/HelloWorld/Index.cshtml が使われます。 次のイメージは、ビューにハード コーディングされた "Hello from our View Template!" という文字列を示しています。

ブラウザー ウィンドウ

ビューとレイアウト ページを変更する

メニューのリンク (MvcMovieHomePrivacy ) を選択します。 各ページには同じメニューのレイアウトが表示されます。 メニューのレイアウトは、Views/Shared/_Layout.cshtml ファイルに実装されています。 Views/Shared/_Layout.cshtml ファイルを開きます。

[レイアウト] テンプレートでは、1 か所でサイトの HTML コンテナー レイアウトを指定し、それをサイト内の複数のページに適用できます。 @RenderBody() という行を見つけます。 RenderBody は、作成したビュー固有のページがすべて表示されるプレースホルダーで、レイアウト ページに ラップ されます。 たとえば、 Privacy リンクを選択すると、RenderBody メソッド内で Views/Home/Privacy.cshtml ビューがレンダリングされます。

  • タイトル要素とフッター要素で、MvcMovieMovie App に変更します。
  • アンカー要素 <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a><a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a> に変更します。

次のマークアップには、強調表示された変更点が示されています。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              crossorigin="anonymous"
              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
    </environment>
    <link rel="stylesheet" href="~/css/site.css" />
</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">
                <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-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 flex-sm-row-reverse">
                    <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">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
        </script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
        </script>
    </environment>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

上記のマークアップでは、このアプリで領域が使用されていないため、asp-area アンカー タグ ヘルパー属性は省略されました。

:Movies コントローラーは実装されていません。 この時点で、Movie Appリンクは機能しません。

変更した内容を保存し、 Privacy リンクを選択します。 ブラウザー タブのタイトルの表示が、 Privacy Policy - Mvc Movie ではなく、 Privacy Policy - Movie App になっていることに注目してください。

Privacy タブ

Home リンクを選択し、タイトルとアンカー テキストにも [Movie App] と表示されていることをご確認ください。 レイアウト テンプレートで一度変更しただけで、サイト上のすべてのページに新しいリンク テキストと新しいタイトルが反映できました。

Views/_ViewStart.cshtml ファイルを確認します。

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml ファイルは Views/Shared/_Layout.cshtml ファイルに取り込まれ、各ビューに適用されます。 Layout プロパティを使用すれば、別のレイアウト ビューを設定することも、null に設定してレイアウト ファイルが使用されないようにすることもできます。

Views/HelloWorld/Index.cshtml ビュー ファイルのタイトルと <h2> 要素を次のように変更します。

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

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

タイトルと <h2> 要素は若干異なります。これにより、コードのどの部分によって表示が変更されるのかを確認できます。

上のコードの ViewData["Title"] = "Movie List"; では、Title ディクショナリの ViewData プロパティを "Movie List" に設定します。 Title プロパティは、次のように、レイアウト ページの <title> HTML 要素で使用されます。

<title>@ViewData["Title"] - Movie App</title>

変更内容を保存して、https://localhost:{PORT}/HelloWorld に移動します。 ブラウザーのタイトル、プライマリ見出し、およびセカンダリ見出しが変更されていることに注意してください (ブラウザーに変更内容が表示されない場合は、キャッシュされたコンテンツを表示している可能性があります。 ブラウザーで Ctrl + F5 キーを押して、サーバーからの応答が強制的に読み込まれるようにしてください)。ブラウザーのタイトルは、Index.cshtml ビュー テンプレートで設定した ViewData["Title"] で作成されます。レイアウト ファイルには "- Movie App" が追加されます。

Index.cshtml ビュー テンプレートのコンテンツがどのように Views/Shared/_Layout.cshtml ビュー テンプレートにマージされ、1 つの HTML 応答がブラウザーに送信されたかにも注目してください。 レイアウト テンプレートを使用すれば、アプリケーションのすべてのページに適用される変更をとても簡単に行うことができます。 詳細については、「Layout」 (レイアウト) を参照してください。

ムービー リスト ビュー

ここでは、"データ" のごく一部 (この場合は "Hello from our View Template!" というメッセージ) を ハード コーディングしました。 MVC アプリケーションには "V" (ビュー) があり、"C" (コントローラー) もありますが、"M" (モデル) はまだありません。

コントローラーからビューへのデータの受け渡し

コントローラー アクションは、受信 URL 要求への応答として呼び出されます。 コントローラー クラスでは、受信ブラウザー要求を処理するコードが記述されます。 コントローラーはデータ ソースからデータを取得し、ブラウザーに返す応答の種類を決定します。 ビュー テンプレートを使用すれば、コントローラーからブラウザーへの HTML 応答を生成して書式を設定できます。

コントローラーは、ビュー テンプレートで応答をレンダリングするために必要なデータを提供します。 ベスト プラクティス: ビュー テンプレートでは、ビジネス ロジックを実行したり、データベースと直接やりとりしたり しない でください。 ビュー テンプレートでは、コントローラーによって提供されるデータのみを処理するようにしてください。 この "懸念事項の分離" を維持すれば、コードをクリーンでテスト可能な保守しやすい状態に保つことが楽になります。

現時点では、HelloWorldController クラスの Welcome メソッドは nameID パラメーターを受け取ってから、ブラウザーに直接値を出力します。 コントローラーにこの応答を文字列としてレンダリングさせるのではなく、代わりにビュー テンプレートを使用するようにコントローラーを変更します。 このビュー テンプレートでは動的応答が生成されます。これは、応答を生成するために、コントローラーからビューに適量のデータを渡す必要があることを意味します。 そのためには、コントローラーで動的データ (パラメーター) を設定します。これは、ビュー テンプレートでアクセスできるようにするために ViewData ディレクトリに必要なデータです。

HelloWorldController.cs 内で、Welcome メソッドを変更して Message および NumTimes 値を ViewData ディクショナリに追加します。 ViewData ディクショナリは動的オブジェクトです。つまり、任意の型を使用することができます。ViewData オブジェクトでは、その内部に何かを設定するまでプロパティは定義されません。 MVC のモデル バインド システムは、名前付きパラメーター (namenumTimes) を、アドレス バーのクエリ文字列からメソッドのパラメーターに自動的にマップします。 完全な HelloWorldController.cs ファイルは次のようになります。

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

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

        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

ViewData ディクショナリ オブジェクトには、ビューに渡されるデータが含まれています。

Views/HelloWorld/Welcome.cshtml という名前の [ようこそ] ビュー テンプレートを作成します。

"Hello" NumTimes を表示する Welcome.cshtml ビュー テンプレートでループを作成します。 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>

変更内容を保存し、次の URL を参照します。

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

データは URL から取得され、MVC モデル バインダーを使用してコントローラーに渡されます。 コントローラーはデータを ViewData ディクショナリにパッケージ化し、そのオブジェクトをビューに渡します。 その後、ビューでブラウザーに HTML としてデータがレンダリングされます。

[ようこそ] ラベルと、Hello Rick という語句が 4 つ示された Privacy ビュー

上のサンプルでは、ViewData ディクショナリを使用して、コントローラーからビューにデータを渡しました。 チュートリアルの後半では、ビュー モデルを使用して、コントローラーからビューにデータを渡します。 一般には、ViewData ディクショナリを使用する方法より、ビュー モデルを使用してデータを渡す方法が推奨されます。 詳細については、ViewBag、ViewData、または TempData を使用するタイミングに関するページをご覧ください。

次のチュートリアルでは、ムービーのデータベースを作成します。