SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

.NET最新版でASP.NET Core

.NET 6でASP.NET CoreのMVCアプリケーションの基本を理解する

.NET最新版でASP.NET Core 第5回


Indexアクションの動き

 プロジェクトのフォルダ構成を見たところで、実際のファイルを見てそれらの関連を理解しましょう。まず、MVCアプリケーションの基本的な動きを理解するために、MvcSampleアプリケーションのトップページに相当するHomeコントローラのIndexアクションを見ていきます。

コントローラのファイル(Indexアクション) - Controllers/HomeContoller.cs

 コントローラの役割は、リクエストに基づきアクションを呼び出し、その処理結果をビューに反映することです。アクションとはその名のとおり、コントローラに行わせたいことで、具体的にはアクションメソッドとして定義します。

 コントローラのファイルは、Controllersフォルダに置くことになっています。ファイル名の制約はありませんが、通常は「{コントローラ名}Controller.cs」となります。これから見ていくHomeContoller.csファイルは、既定で作成されるHomeコントローラのファイルです(リスト1)。

リスト1:Controllers/HomeController.cs
…略…
namespace MvcSample.Controllers;

public class HomeController : Controller	(1)
{
    …略…
    public IActionResult Index()	(2)
    {
        return View();		(3)
    }
    …略…
}

 コントローラファイルの基本的な構造は、(1)コントローラクラスの定義、(2)アクションメソッドの定義となります。コンストラクタなどもありますが、重要なのはこの2つです。

 (1)は、コントローラの基本クラスであるControllerを継承してHomeControllerクラスを定義しています。これで、HomeControllerクラスはコントローラとして認識されます。

 (2)は、Indexアクションに対応するIndexメソッドの定義です。アクションメソッドの戻り値は、すべてIActionResultインタフェース型を持つことになっています。ここでは(3)のようにViewメソッドの戻り値をそのまま返していますが、これはIActionResultインタフェース型を継承するViewResult型であり、ビューの表示に使われるさまざまな情報を持ったクラスです。つまり、この場合のアクションメソッドの戻り値はビューの表示情報となり、Indexメソッドの戻り値をもとに、表示すべきビューを決めるという動きになります。

 なお、コントローラクラスにあるpublicなメソッドは、すべてアクションメソッドと解釈されます。アクションメソッドとしたくないメソッドはprivateにするか、NoAction属性をメソッドの宣言に付記してください。

[NOTE]コントローラクラスの条件

 クラスがコントローラクラスとして認識されるための条件は以下のいずれかになっています。通常はControllerクラスを継承するので、あまり気にする必要はないでしょう。

  • クラス名の後半(サフィックス)が「Controller」である
  • Controllerクラスを継承している
  • Controller属性をクラス宣言に付記する

ビューのファイル(Indexアクション) - Views/Home/Index.cshtml

 ビューの役割は、コントローラ(アクションメソッド)の処理結果を受け取ってHTMLなどを生成(レンダリング)することです。上記のとおり、アクションメソッドはビューの表示情報を返しますが、このとき実際の表示に使われるテンプレート(ひな型)がビューのファイルです。

 ビューのファイルは、Viewsフォルダに置くことになっています。図3のプロジェクト構成を見るとわかりますが、Viewsフォルダの下にはHomeフォルダがあります。このように、ビューのファイルはコントローラと同名のフォルダに分けて置くことになっています。

 また、ビューのファイルは、基本的に「/コントローラ名/アクション名.cshtml」と命名することになっています。よって、HomeコントローラのIndexアクションに対応するビューはViews/Home/Index.cshtmlファイルということになります。このファイルの中身を見てみます(リスト2)。

リスト2:Views/Home/Index.cshtml
@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

 本連載を読み進んできた読者には、見覚えがある内容と思われたのではないでしょうか? それもそのはずで、これはRazor Pagesの既定のビューであるPages/Index.cshtmlとほぼ同じで、同様にRazor構文でコードを記述できます。異なるのは、以下の2点です。

  • @pageディレクティブが存在しない――Razor Pagesページ特有のディレクティブで、MVCには不要。
  • @modelディレクティブが存在しない――Indexアクションには処理すべきデータがないので省略されている。Razor Pagesではビューに対するページモデルが常に存在するので必須。MVCでもビューがデータを受け取る場合には必要。

 ディレクティブについては、Razor PagesにおけるPages/Home/Index.cshtmlについて説明している第3回を参照してください。このViews/Home/Index.cshtmlファイルの内容(実際にはViews/Shared/_Layout.cshtmlとともにレンダリングされた内容)が、HomeコントローラのIndexアクションの実行の結果、Viewメソッドによって呼び出され表示されます。

[NOTE]アクションに対応するビューのひも付け

 ASP.NET Core MVCでは、既定でViews/{Controller}/{Action}.cshtmlファイルを探しますが、見つからない場合にはViews/Shared/{Action}.cshtmlファイルを探します。これにより、異なるコントローラの同一のアクションでビューを共有できます。

エントリポイントのファイル(ルーティング) - Program.cs

 HomeコントローラとIndexアクション、ビューを見てきましたが、ここで押さえておきたいのがルーティングです。ルーティングとは、URLのパス部から適切なコントローラとアクションを呼び出すためのルール設定のことを言います。例えば、/Home/IndexというパスがURLにある場合、HomeコントローラからIndexアクションを呼び出しなさいという設定がルーティングです。

 Razor Pagesでは、Pagesフォルダの構造がそのままURLのパス部を構成するというルーティングルールでした。これに対してMVCでは、物理的なフォルダ/ファイルの構造がパスと一致している必要がないので、柔軟性のあるサイト構成が可能になります。その分、コントローラやアクションの追加、変更に伴いルーティングルールを適宜メンテナンスする必要が生じます。

 ルーティングは、エントリポイントというアプリケーションの起点のファイルに対して設定します。ASP.NETの世界では、プロジェクトのルートにあるProgram.csファイルが、エントリポイントです(リスト3)。ルーティングの設定のほかに、アプリケーションの動作に必要な基本的な設定も行うのはRazor Pagesと同様です。

 Razor Pagesでは、ルーティングを使用するというUseRoutingメソッドに加えて、既定の動作を指定するMapRazorPagesメソッドが呼ばれるだけでしたが、MVCでは上記のとおりルーティングルールの明示的な設定が必要になっています。

リスト3:Program.cs
…略…
app.UseRouting();		(1)
app.UseAuthorization();
app.MapControllerRoute(		(2)
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");		(3)
app.Run();

 (1)と(2)がルーティングの設定です。(2)では、「規約によるルーティング」(Conventional Routing)を設定しています。既定値として、名前(name)が「default」でパターン(pattern)が「{controller=Home}/{action=Index}/{id?}」であるルートをMapControllerRouteメソッドで登録しています。

 このパターンは、「コントローラ名/アクション名/id値」を表しており、パターンに合致するURLでは自動的に指定されるコントローラ/アクションが呼び出されます(図4)。なお、「?」の付加されたid値は省略可能を意味し、指定された場合のみアクションに渡されます。このパターンに当てはまらないパス部を構成する場合には、そのためのルート設定を追加していくことになります。

 なお、(3)のように等号(=)を使ってコントローラとアクションの既定値も指定できます。この場合は、既定値は「Home/Index」となり、パスが「/」や「/Home」であるURLに対応します。

図05-04 ルーティングのパターンとコントローラ、アクション
図4 ルーティングのパターンとコントローラ、アクション

その他のアクションについて

 HomeコントローラのIndexアクションとそのビュー、そしてルーティングを見ることで、MVCにおけるリクエストからページが表示されるまでの基本的な流れを見てきました。最後に、他のアクションについても見ておきましょう。

コントローラのファイル(その他) - Controllers/HomeContoller.cs

 コントローラのファイルを再掲します(リスト4)。

リスト4:Controllers/HomeController.cs
…略…
public class HomeController : Controller
{
    // ロガーを保持するフィールド
    private readonly ILogger<HomeController> _logger;	(1)

    // ロガーを受け取るコンストラクタ
    public HomeController(ILogger<HomeController> logger)	(2)
    {
        _logger = logger;
    }
    …Indexアクションは既出なので略…
    // Privacyアクション
    public IActionResult Privacy()	(3)
    {
        return View();
    }

    // Errorアクション
    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()	(4)
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

 (1)(2)はロガーを受け取るコンストラクタとそれを保持するフィールドで、Razor Pagesにおけるものと同じです。そして(3)(4)が、Index以外のアクションメソッドです。(3)のPrivacyアクションの処理内容はIndexアクションと全く同じなので、ひも付いたビューの内容を表示するだけになります。(4)のErrorアクションもViewメソッドの呼び出しを行っているのですが、他の2つのアクションメソッドとは異なり、引数を伴うものになっています。これは、ビューがデータを受け取る場合の書式です。ビューがデータを受け取る場合については第6回で詳しく紹介しますので、ここではErrorアクションがビューにErrorViewModel型のデータを渡している、ということに触れておくのみにします。

モデルのファイルを見る - ErrorViewModel.cs

 ErrorアクションがViewメソッドの引数で渡しているデータのコードが書かれている、ErrorViewModel.csファイルはどのようになっているでしょうか(リスト5)。

リスト5:Models/ErrorViewModel.cs
namespace MvcSample.Models;

public class ErrorViewModel	(1)
{
    public string? RequestId { get; set; }	(2)
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);	(3)
}

 ErrorViewModelはErrorアクションのためのクラスで、Homeコントローラ内で何らかのエラーが発生した際に、エラー画面を表示するための情報をビューに渡すために用いられます。

 (1)ではErrorViewModelクラスを定義していますが、継承元のクラスがないPOCOです。メンバーは(2)の文字列型のプロパティのみであり、これはエラー画面で表示すべきリクエストIDを保持します。(3)のShowRequestIdメソッドは、RequestIdプロパティを参照可能かを返します。これらのプロパティとメソッドがどのように使われているかは、次のErrorビューで後述します。

Views/Shared/Error.cshtml

 Errorアクションに対応するビューError.cshtmlは、Views/Sharedフォルダにあります。つまり、コントローラ間で共有します。リスト6は、Views/Shared/Error.cshtmlの内容です。

リスト6:Views/Shared/Error.cshtml
@model ErrorViewModel	(1)
…略…
@if (Model?.ShowRequestId ?? false)	(2)
{
    <p>
        <strong>Request ID:</strong> <code>@Model?.RequestId</code>
    </p>
}
…後略…

 ここでは、(1)のように@modelディレクティブが指定されています。Viewメソッドで渡されたデータを扱う場合には、そのデータ型を@modelディレクティブで指定する必要があります。

 (2)のブロックは、モデルがnullでなくShowRequestIdメソッドの戻り値がtrueであれば、(3)でRequestIdフィールドの値を表示しています。ここで使用されている疑問符(?)はC#のnull許容演算子(?)とnull結合演算子(??)です。いずれも、nullの可能性のあるオブジェクトから安全かつシンプルに値を取り出すことのできる演算子です。ここで先ほどのモデルの定義にさかのぼると、(2)と(3)の意味が理解できるのではないでしょうか?

まとめ

 今回は、MVCパターンのためのフレームワークであるASP.NET Core MVCのアプリケーションをテンプレートから作成し、その基本的な構成を見てきました。次回は、これを発展させて、データ処理を絡めたアプリケーションに強化していきながら、アクションやビューの変化について見ていきます。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
.NET最新版でASP.NET Core連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/16254 2023/05/26 17:19

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー