ASP.NET Core MVC 3.1 「空のテンプレートからサクサクセットアップ」

# はじめに

今回は「**空**」のテンプレートからASP.NET Core **MVC**アプリケーションをセットアップする際の手順を記載します。

「**Web アプリケーション（モデル ビュー コントローラー）**」テンプレートは、最初からMVCプロジェクトに必要な最低限の構成が用意されているので便利です。
ただし、最初からjQueryやBootstrapが組み込まれていたりと、場合によっては不要になるものも組み込まれています。
そのため、著者はまっさらな「**空**」のテンプレートから作成するようにしています。

### 前回の記事

[ASP.NET Core MVC 3.1 入門 その５ 「View」](https://qiita.com/yagi405/items/b39c6c704e49a78c51a3)

### 今回のゴール

* MVCを有効にする
* Controllerを追加する
* Viewを追加する
* Routeを設定する
* 特殊なViewテンプレートを追加する
* タグヘルパーを有効にする
* 静的ファイルを利用可能にする
* スタイルシートを適用する
* JavaScriptファイルを適用する

### 環境
<dl>
    <dt>IDE</dt>
    <dd>Visual Studio 2019</dd>

    <dt>言語</dt>
    <dd>C#</dd>
</dl>

# セットアップ

## 「ASP.NET Core Web アプリケーション」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/484ab968-62f9-7b50-92d6-7b3618987003.png)

## 任意の「プロジェクト名」及び「ソリューション名」を入力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/73050ab3-1476-ceb5-27e7-93515c304f73.png)

## テンプレートの選択
今回は「ASP.NET Core 3.1」「**空**」のプロジェクトを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/b5727350-f933-6e4e-50e7-f9838fb16c54.png)

## プロジェクトの作成完了
VisualStudioで以下のような画面が立ち上がります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/ab7559ab-64b0-149e-afff-c20de8ed110e.png)

## ソリューションエクスプローラーを眺める
「**空**」のテンプレートのソリューションエクスプローラーを眺めてみましょう。

こちらのテンプレートには、MVCテンプレートとは異なり、`Controllers`や`Views`といったMVC用のフォルダ等は一切含まれておりません。これから作成していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/9504b574-49ac-bbdd-587a-a6b2ba70ff6f.png)

## MVCを有効にする

`Startup.cs`の`ConfigureServices`メソッドを以下のように変更してください。
`ConfigureServices`メソッドでは、アプリケーションで使用するサービスを追加（登録）します。

`AddControllersWithViews`は、`View`を使った`Controller`を追加するという意味です。
これによって、`View`と`Controller`を用いた（MVCの基本的な）機能が組み込まれます。

```cs

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }
```

## Controllersフォルダを追加

MVCパターンに沿った形で名前空間を構成します。
ルートに`Controllers`フォルダを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/ed14badc-e6ee-4b19-936d-f1016f6bf6ae.png)

## Controllerを追加

`Controllers`フォルダに空の`Controller`を追加してください。
ここでは`ChatController`としておりますが、もちろん、ご自身が作成するアプリケーションに含まれる機能と対応したController名をつけてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/1a1ee4b8-a823-d640-8928-1ce1e2b397bc.png)

### 作成した空の`Controller`

```cs

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

## Viewを追加

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

と進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/3f8aba9e-5439-ed25-2d26-85b0eb85655a.png)

「Razor ビュー」を選択します。
なお「スキャフォールディング」というのは、要は**雛形を自動生成する機能**のことを示します。ここではViewの雛形を自動生成してもらうために、この機能を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/b2a746ca-564d-68c4-dd5f-ce0e4a124895.png)

続いてビュー名ですが、アクションメソッド名とします。
アクションメソッドで呼び出される`View`メソッドが
明示的に指定しない限り、`/Views/コントローラー名/アクションメソッド名.cshtml`を読み込むためです。
テンプレートは「Empty（モデルなし）」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/c43fd9c3-a602-2718-a6bc-1107c5a6d827.png)

## Routeの設定

`Startup.cs`の`Configure`メソッドを以下のように変更し、Routeも合わせて登録しておきます。
`Configure`メソッドでは、Routeの定義に代表されるように、アプリケーションがHTTPリクエストに対してどのように応答するかを定義します。
Routeについては[こちらの記事](https://qiita.com/yagi405/items/ca9d6f17ff87073ed8cd)を参照してください。

### 変更前

```cs
	app.UseEndpoints(endpoints =>
	{
	    endpoints.MapGet("/", async context =>
	    {
	        await context.Response.WriteAsync("Hello World!");
	    });
	});
```

### 変更後

デフォルトのRouteは先ほど作成した`Controller`の`Index`アクションメソッドに向けておきます。

```cs
	app.UseEndpoints(endpoints =>
	{
	    endpoints.MapControllerRoute(
	        name: "default",
	        pattern: "{controller=Chat}/{action=Index}/{id?}"
	    );
	});
```

## 動作確認
F5で実行します。
作成した`Controller`の`Index`アクションメソッドが呼び出されていることが確認できればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/ec82501d-56a8-ef8a-3055-110f894de3b2.png)

## レイアウトページを追加

レイアウトページについては[こちらの記事](https://qiita.com/yagi405/items/b39c6c704e49a78c51a3)を参照してください。

`Views` > `Shared`フォルダを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/7f9378e0-9a6f-c2b2-9ea7-7e8c226ee35d.png)

> `Shared`フォルダを右クリック > 追加 > 新しい項目

と進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/95956207-5d54-2e33-716c-750704b83167.png)

Razorレイアウトを選択します。
ファイル名は最初から`_Layout.cshtml`となっているので、そのままでOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/d22aaa36-7c3b-23a4-dfc0-175f46d8cb3b.png)

`_Layout.cshtml`が追加できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/8383d9ba-5d66-4fca-16ba-9a9e395f641d.png)

## スタートページ(_ViewStart.cshtml)を追加

スタートページ(_ViewStart.cshtml)については[こちらの記事](https://qiita.com/yagi405/items/b39c6c704e49a78c51a3)を参照してください。

> `Views`フォルダを右クリック > 追加 > 新しい項目

と進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/650dca39-83b4-8fc6-7c30-0fbc052771e3.png)

Razorビューの開始を選択します。
ファイル名は最初から`_ViewStart.cshtml`となっているので、そのままでOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/89ffbd57-5b48-f64e-82c3-8f27c658f725.png)

`_ViewStart.cshtml`が追加できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/1437e8c5-e2bb-ce91-1b4f-03e02f95d65c.png)

## 動作確認
F5で実行します。
レイアウトページが適用されていることが確認できればOKです。
分かりづらいですが、タブの表示名に`<title>`が効いて`Index`となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/3134c238-6685-39c2-3a45-05a386bba281.png)

## _ViewImports.cshtmlを追加

`Views`  に `_ViewImports.cshtml` を追加します。
このファイルでは、複数のViewで利用する名前空間のインポートをおこないます。

> `Views`フォルダを右クリック > 追加 > 新しい項目

と進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/810b91c2-3973-551b-7a52-23f10ff5fa95.png)

Razorビューのインポートを選択します。
ファイル名は最初から`_ViewImports.cshtml`となっているので、そのままでOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/59b3205b-5977-bd3c-cb77-80465d29a997.png)

`_ViewImports.cshtml`が追加できました。
以後、複数のViewで利用する名前空間が発生した場合には、このファイルでusingすると効率的です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/0e25795d-3ab3-c01a-da30-24c2a784f25b.png)

## タグヘルパーの有効化

`@addTagHelper`ディレクティブにより、Viewでタグヘルパーが使用可能になります。

最初のパラメーターでは、読み込むタグヘルパーを指定します。
すべてのタグヘルパーを指定する場合は `*` を使用します。

2 番目のパラメーターでは、タグヘルパーを含む名前空間を指定します。

`Microsoft.AspNetCore.Mvc.TagHelpers`
=> ASP.NET Core に組み込まれているタグヘルパーが存在する名前空間

下記のコードを `Views/_ViewImports.cshtml` に追加すると、
`Microsoft.AspNetCore.Mvc.TagHelpers` に含まれるすべてのタグヘルパーを、
=> ワイルドカード`*`での指定によるもの
`Views`フォルダまたはサブフォルダ内のすべてのViewで使用可能にする
=> Views/_ViewImports.cshtmlに定義したことによるもの

という意味になります。

```cs
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
```

## Configuration

`Configuration`クラスが `appsettings.json`に設定した値の取得機能を提供してくれます。
まだ設定値が無いので、ここでは`Configuration`を定義して、取得できる状態までとしておきます。

```cs
    public IConfiguration Configuration { get; set; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
```

## wwwroot の追加

ルートに`wwwroot`フォルダを作成します。
スタイルシートや画像ファイル、JavaScriptファイルといった静的ファイルを格納するフォルダで、Webルートと呼びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/2ffc6a1a-00c9-4aae-c0a3-b92664a458e2.png)

## 静的ファイルを利用可能にする

スタイルシートや画像ファイル、JavaScriptファイルといった静的ファイルを利用可能にします。
`Startup.cs`の`Configure`メソッドを以下のように変更し、`UseStaticFiles`メソッドを呼び出します。
これで`wwwroot`に格納されているファイルにアクセスできるようになります。

```cs
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseStaticFiles(); //追加

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Chat}/{action=Index}/{id?}"
            );
        });
    }
```

## スタイルシートを追加

`wwwroot`にスタイルシートを追加します。

`wwwroot` > `css`フォルダを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/6882570d-9461-b568-f484-919dd0317864.png)

> `css`フォルダを右クリック > 追加 > 新しい項目

と進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/0e746bfc-7789-3f14-9bb2-c3d5065dfe44.png)

スタイルシートを選択します。
ファイル名は`site.css`としておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/3ff1350d-0f91-baae-ac0b-fad20cc4948f.png)

## スタイルシートを適用

レイアウトページで参照します。

```html
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" type="text/css" href="~/css/site.css" asp-append-version="true"/> @*追加*@
</head>
<body>
    <div>
        @RenderBody()
    </div>
</body>
</html>
```

## JavaScriptファイルを追加

`wwwroot` > `js`フォルダを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/5461dcc6-c8ae-0895-e391-034d0090a076.png)

> `js`フォルダを右クリック > 追加 > 新しい項目

と進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/c0f0b6c8-9bdd-583a-4667-84516505f1f9.png)

JavaScriptファイルを選択します。
ファイル名は`site.js`としておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544508/2124d730-2ae3-676c-f3a2-9b28d89eab77.png)

## Javascriptファイルを適用
レイアウトページで参照します。

```html
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" type="text/css" href="~/css/site.css" asp-append-version="true"/>
</head>
<body>
    <div>
        @RenderBody()
    </div>
    <script type="text/javascript" src="~/js/site.js" asp-append-version="true"></script> @*追加*@
</body>
</html>
```

以後はアプリケーション固有の機能を追加していきます。

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