ASP.NET MVC（.NET Framework）記載まとめ　【初学者編】3


##    はじめに
ASP.NET MVC (.NET Framework) のプロジェクトを作成し、掲示板の基本的な CRUD 機能を備えたアプリケーションを構築します。

------------------------------------
[前回の記事はこちら](https://qiita.com/nano357/items/4b145b9c16710786ad07)

--------------------------------------------------------------
## <font color="green">①プロジェクトの作成</font>

1.1･･･ Visual Studio インストーラでのセットアップ
```markdown
 1. Visual Studio Installerを開き、必要なワークロード、次のものを選択
   ●  「ASP.NETとWeb開発」
      : Webアプリケーションの開発に必要なコンポーネントを含むワークロードです。

   ●  「.NETデスクトップ開発」
      : デスクトップアプリケーションの開発用のコンポーネントと Web開発で必要なコンポーネントが含まれています。


 2. 個別のコンポーネントとして、次のものを選択
   ●「.NET Framework 4.7.2 Targeting Pack」
      : プロジェクトが .NET Framework 4.7.2 をターゲットにしているため、これが必要です。

   ●「.NET 6.0 ランタイム（長期サポート）」と「.NET 8.0 ランタイム（長期サポート）」
      : 最新の .NET バージョンをサポートするために選びます。

   ●「Entity Framework 6 Tools」
      : データベースのマッピングにEntity Frameworkを利用します。

   ●「.NET SDK」
      : 開発に必要な .NET コマンドラインツールを含むコンポーネントです。
   ●「.NET Framework プロジェクトと項目のテンプレート」
     : .NET Frameworkベースのプロジェクトに必要なテンプレートを提供します。

 3. その後、プロジェクト作成で「新しいプロジェクトの作成」をクリックし、ASP.NET Webアプリケーション (.NET Framework) を選択

 4. プロジェクト名を「BulletinBoardApp」にして、フレームワークのバージョンは「.NET Framework 4.7.2」を選択

 5. 「テンプレートの選択」で「MVC」を選択し、「認証なし」を選択

````

--------------------------------------------------------------
## <font color="green">②プロジェクトの構成</font>


````
 ・ App_Start/RouteConfig.cs：
     ルーティングの設定ファイル。
     デフォルトルート設定で `BulletinBoardsController` に対応するように設定。

 ・ Web.config：
     アプリケーションの設定ファイル。
     データベース接続設定を `LocalDb` の SQL Server インスタンスに変更し、接続文字列 `BulletinBoardContext` を設定。

 ・ Models/：
     データモデルを管理。
     ├── BulletinBoard.cs：掲示板のデータモデル。
     |　　　　　　　　　　　 投稿ID、タイトル、内容、作成日などのフィールドを定義。
     └── ApplicationDbContext.cs：データベースコンテキスト。
                                  `DbSet<BulletinBoard>` を含み、`BulletinBoard` モデルを管理。

 ・ Controllers/：
     コントローラー（ロジック）を管理。
     └── BulletinBoardsController.cs：掲示板に関するCRUD機能を管理するコントローラー。

 ・ Views/：
     表示（HTML/CSS/JS）を生成。
     ├── BulletinBoards/：
     │    ├── Index.cshtml：掲示板の一覧を表示。
     │    ├── Details.cshtml：掲示板の詳細情報を表示。
     │    ├── Create.cshtml：新しい掲示板作成フォームを表示。
     │    ├── Edit.cshtml：掲示板編集フォームを表示。
     │    └── Delete.cshtml：削除確認画面を表示。
     
 ・ Migrations/：
     データベースマイグレーションを管理。
     ├── Configuration.cs：マイグレーション設定ファイル。
     |　　　　　　　　　　　 自動的にマイグレーションを適用する設定などが含まれる。
     └── マイグレーションファイル（例: InitialCreate）：データベースの最初のスキーマを定義するファイル。自動生成され、データベースの構造をバージョン管理。

 ````
--------------------------------------------------------------
## <font color="green">③ルーティング設定 (App_Start/RouteConfig.cs)</font>
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace BulletinBoardApp
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // 特定のリソース (.axd など) をルーティングから除外
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            // デフォルトのURLルーティングを設定
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "BulletinBoards", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}
````
・このルート設定は、デフォルトルートを「BulletinBoards」コントローラーの Index アクションに変更し、アクションメソッドとIDをオプションで指定します。

--------------------------------------------------------------

## <font color="green">④データベース接続設定</font>

4.1･･･ Web.config にデータベース接続情報を追加します。
```xml
<configuration>
・・・
  </system.codedom>

	<!-- 既存の設定 ... -->

	<connectionStrings>
		<add name="BulletinBoardContext"
			 connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=BulletinBoardDb;Integrated Security=True;"
			 providerName="System.Data.SqlClient" />
	</connectionStrings>
	
</configuration>
````

・説明：それぞれの要素の説明は以下の通りです。
````
１．< connectionStrings> セクション
   ●  データベース接続情報を定義するためのセクション。
      複数の接続文字列を追加できます。

````

````
２．< add name="DefaultConnection" ... />
   ●  1つの接続文字列を追加しています。
   ●  name属性は、この接続の名前を指定しており、
      ここでは「BulletinBoardContext」が指定されています。
      ⇒　プログラム内で、この名前を使って接続文字列を参照することができます。

````

````
３．connectionString="..."　属性：
    :データベースへの接続文字列です。
    この例では次のような内容を含んでいます:

   ●  Data Source=.
    : SQLサーバーの場所を示しています。
    　ピリオド（.）は「ローカルホスト」、つまり現在のマシンを指します。
      ここでは　Data Source=(LocalDb)\MSSQLLocalDB:
      　⇒　ローカルSQL Serverインスタンスの指定。

  Initial Catalog=BulletinBoardDb
    :使用するデータベースの名前を指定します。
    　ここでは「BulletinBoardDb」というデータベースに接続します。

  Integrated Security=True
    :Windows認証（統合セキュリティ）を使用してデータベースに接続します。
    ユーザー名とパスワードを指定する代わりに、
    Windowsのログイン資格情報を利用します。

````

````
４．providerName　属性：
   ●  providerName="System.Data.SqlClient"
    :使用するデータベースプロバイダを指定します。
    この例では、SQL Serverに接続するための.NETのクライアントライブラリ
    「System.Data.SqlClient」を使用しています。

    この設定により、ローカルのSQL Serverインスタンス上にある
    「BulletinBoardDb」というデータベースに、
    Windows認証を用いて接続するための情報を定義しています。

````
--------------------------------------------------------------

## <font color="green">⑤モデルの作成</font>

5.1･･･ Models フォルダにクラス BulletinBoard.cs を追加し、掲示板のモデルを定義します。
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;


namespace BulletinBoardApp.Models
{
    public class BulletinBoard
    {

        // 投稿の一意の識別子 (プライマリキー)
        /** エンティティを一意に識別します。**/
        public int Id { get; set; }

        // 投稿のタイトル
        /** StringLength 属性によって
            入力最大文字100文字を設定**/
        [Required]
        [StringLength(100)]
        public string Title { get; set; }

        // 投稿の内容
        /** Required 属性によって
            必須フィールドとして設定 **/
        [Required]
        public string Content { get; set; }

        // 作成日時
        /** デフォルトで現在の日時が設定 **/
        public DateTime CreatedAt { get; set; } = DateTime.Now;

    }
}
````

--------------------------------------------------------------

## <font color="green">⑥ApplicationDbContext クラスの作成(Models/BulletinBoardContext.cs)</font>

6.1･･･ Models フォルダに ApplicationDbContext.cs を追加し、Entity Framework の DbContext を定義します。
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/** Entity FrameworkのDbContextクラスを使用するために必要 **/
using System.Data.Entity;

using BulletinBoardApp.Models;

namespace BulletinBoardApp.Models
{

    // データベースとのやり取りを管理するクラス
    public class ApplicationDbContext : DbContext
    {
        // データベース接続に使用するコンストラクタ
        /** コンストラクタで接続文字列 "BulletinBoardContext" を指定 **/
        public ApplicationDbContext() : base("BulletinBoardContext") { }

        // 掲示板のデータを管理するDbSet
        public DbSet<BulletinBoard> BulletinBoards { get; set; }
    }

}
````
・DbContext を継承し、BulletinBoards プロパティでデータベースに保存するエンティティを定義します。



6.2･･･ エラー対応方法

エラー:
````
CS0234	型または名前空間の名前 'Entity' が名前空間 'System.Data' に存在しません (アセンブリ参照があることを確認してください)		

CS0246	型または名前空間の名前 'DbContext' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください)	
````

解決策:
```plaintext
これらのエラーは、DbContext と System.Data.Entity が
参照されていないことに起因しています。
エンティティフレームワークの設定が正しくないため、
次の解決策を試してみてください。
````
Entity Framework のインストール

````
DbContext は Entity Framework に含まれるクラスです。
プロジェクトに Entity Framework の参照が不足している
可能性があるため、以下の手順で追加します。
````
6.2.1. NuGet パッケージの管理を開きます:
````
Visual Studio の「ソリューション エクスプローラー」でプロジェクト
（BulletinBoardApp）を右クリックし、
「NuGet パッケージの管理」を選択します。
````
6.2.2. Entity Framework のインストール:
````
「参照」タブで Entity Framework を検索し、
最新の安定バージョンをインストールします。
````
6.2.3. パッケージがインストールされたことを確認:
````
Entity Framework のインストールが成功した後、
References (参照) セクションに 
EntityFramework が追加されていることを確認してください。
````

--------------------------------------------------------------

## <font color="green">⑦CRUD機能の自動生成</font>

7.1･･･ コントローラーの追加
````
Controllers フォルダを右クリックし、
「追加」→
「新しいスキャフォールディングアイテム」を選ぶ。
````

7.2･･･ スキャフォールディングの選択
````
「Entity Framework を使用した、ビューがある MVC 5 コントローラー」を選択します。

これは、通常のASP.NET MVCアプリケーションで使用する選択肢で、
モデルに基づいたビューとコントローラーのセットを自動生成します。
ビューを含むCRUDのアクションメソッド
（Index、Create、Edit、Details、Delete）が生成されます。

補足
「Entity Framework を使用したアクションがある 
Web API 2 コントローラー」:

これは、Web APIを使ってデータを扱う際の選択肢で、ビュー（HTMLページ）は生成されません。APIのエンドポイントを提供し、JSONやXMLなどのフォーマットでデータをやり取りするためのコントローラーを作成します。
今回はこちらは選択しません。
````
7.3･･･ モデルとデータコンテキストの指定
````
・モデルクラスとして BulletinBoard (BulletinBoardApp.Models)を選択
・ApplicationDbContext (BulletinBoardApp.Models) を使用します。
````
7.4･･･ コントローラーの名前を変更
````
新しく生成されたコントローラーに「BulletinBoardsController」という名前を付けます。

````
7.5･･･ エラー対応方法（データベースマイグレーションの適用時も同様）

エラー
選択したコード ジェネレーターを実行中にエラーが発生しました：
'型'BulletinBoardApp.Models.BulletionBoard' の取得中にエラーが発生しました。プロジェクトをビルドし直してください。

解決策:

プロジェクトのクリーンとリビルド
````
「ビルド」メニューから「ソリューションのクリーン」を選択し、その後「ソリューションのビルド」を選択します。
````

プロジェクトの再ビルド
````
NuGet パッケージが正しくインストールされ、必要な追加がされた場合、プロジェクト全体を再ビルドしてください。
メニューから「ビルド」→「ソリューションのビルド」を選択します。
````
Visual Studio の再起動
````
時々、Visual Studio の内部キャッシュや一時ファイルが原因でエラーが発生することがあります。これをクリアするために Visual Studio を再起動してください。
````

--------------------------------------------------------------

## <font color="green">⑧データベースマイグレーションの適用</font>

8.1･･･  NuGet パッケージ マネージャー コンソールを開く
```plaintext
Visual Studio 上部メニューから「ツール > NuGet パッケージ マネージャー
> パッケージ マネージャー コンソール」を選択。
````

8.2･･･  以下のコマンドをコンソールで実行します。
```powershell
Enable-Migrations
Add-Migration InitialCreate
Update-Database
````



8.3･･･  エラー対応方法

エラー:
```plaintext
No migrations configuration type was found...
````

解決策:
```plaintext
1. Enable-Migrations コマンドでマイグレーションを有効にします。
2. その後、再度 Add-Migration InitialCreate を実行して、マイグレーションを作成します。
````

注意点:
```plaintext
DbContext 確認:
プロジェクトが正しい DbContext を使用しているか確認してください。ターゲットフレームワークが異なる場合、コマンドの動作が変わることがあります。
````

メッセージの解説:
```plaintext
Scaffolding migration 'InitialCreate'.
The Designer Code for this migration file includes a snapshot of your current Code First model...
````
このメッセージは、マイグレーションが正常に作成されたことを示します。マイグレーションファイルは、現在のモデルのスナップショットを含み、データベースに適用される変更が記述されています。


--------------------------------------------------------------

## <font color="green">⑨コントローラーの修正 (BulletinBoardsController.cs)</font>

### コードに対する変更点

9.1･･･  まず、Visual Studio で Controllers フォルダ内の BulletinBoardsController.cs を開きます。

9.2･･･  自動生成されたコードを修正して、追加機能やロジックを導入します。

#### メソッドの説明コメントを追加:

各アクションメソッドに対して、処理内容を説明するコメントを追加します。

#### メソッド名の修正:

Details メソッドの引数から int? id を int id に変更し、IDが必ず提供されることを前提とします。

#### コードの可読性向上:

コメントを日本語に翻訳して、各セクションの目的を明確にします。


```csharp
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using BulletinBoardApp.Models;

namespace BulletinBoardApp.Controllers
{
    // 掲示板に関するCRUD機能を管理するコントローラー
    public class BulletinBoardsController : Controller
    {
        // データベースコンテキストを使用してDBにアクセスするためのオブジェクト
        private ApplicationDbContext db = new ApplicationDbContext();

        // 掲示板の一覧を表示するアクション
        /**  Indexアクション **/
        
        // GET: BulletinBoards
        public ActionResult Index()
        {

            /**  掲示板のリストをデータベースから取得し、ビューに渡す **/
            return View(db.BulletinBoards.ToList());

        }

        // 掲示板の詳細を表示
        /**  Detailsアクション: 指定されたIDの掲示板の詳細を表示 **/

        // GET: BulletinBoards/Delete/5
        public ActionResult Details(int id)
        {
            /** int 型引数: Details アクションの引数 id は int 型であり、
             *  null 値を取ることができません。
             *  したがって、以下の null チェックは不要です。 **/

            /*
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            */

            /**  IDに基づいて掲示板を検索 **/
            BulletinBoard bulletinBoard = db.BulletinBoards.Find(id);
            /**  掲示板が見つからない場合は404エラーページを返す **/
            if (bulletinBoard == null)
            {
                return HttpNotFound();
            }
            return View(bulletinBoard);
        }

        // 新規作成用のフォームを表示
        /**  Createアクション **/

            // GET: BulletinBoards/Create
            public ActionResult Create()
        {
            return View();
        }

        // フォームで入力されたデータを受け取り、新しい掲示板を作成する
        /**  Createアクション (POST) **/

        // POST: BulletinBoards/Create
        // 過多ポスティング攻撃を防止するには、バインド先とする特定のプロパティを有効にしてください。
        // 詳細については、https://go.microsoft.com/fwlink/?LinkId=317598 をご覧ください。
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "Id,Title,Content,CreatedAt")] BulletinBoard bulletinBoard)
        {
            /**  入力データが有効かどうかを確認 **/
            if (ModelState.IsValid)
            {
                db.BulletinBoards.Add(bulletinBoard);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(bulletinBoard);
        }

        // 掲示板を編集するフォームを表示
        /**  Editアクション: 指定されたIDの掲示板を編集するフォームを表示 **/

            // GET: BulletinBoards/Edit/5
            public ActionResult Edit(int id)
        {

            /*
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            */

            /**  IDに基づいて掲示板を検索 **/
            BulletinBoard bulletinBoard = db.BulletinBoards.Find(id);

            /**  掲示板が見つからない場合は404エラーページを返す **/
            if (bulletinBoard == null)
            {
                return HttpNotFound();
            }
            return View(bulletinBoard);
        }

        // 編集された掲示板データを保存
        /**  Editアクション (POST) **/

        // POST: BulletinBoards/Edit/5
        // 過多ポスティング攻撃を防止するには、バインド先とする特定のプロパティを有効にしてください。
        // 詳細については、https://go.microsoft.com/fwlink/?LinkId=317598 をご覧ください。
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,Title,Content,CreatedAt")] BulletinBoard bulletinBoard)
        {
            /**  入力データが有効かどうかを確認 **/
            if (ModelState.IsValid)
            {
                db.Entry(bulletinBoard).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(bulletinBoard);
        }

        // 掲示板の削除確認画面を表示
        /**  Deleteアクション: 指定されたIDの掲示板を削除する確認画面を表示 **/

            // GET: BulletinBoards/Delete/5
            public ActionResult Delete(int id)
        {

            /*
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            */

            /**  IDに基づいて掲示板を検索 **/
            BulletinBoard bulletinBoard = db.BulletinBoards.Find(id);

            /**  掲示板が見つからない場合は404エラーページを返す **/
            if (bulletinBoard == null)
            {
                return HttpNotFound();
            }
            return View(bulletinBoard);
        }

        // 掲示板を削除
        /**  Deleteアクション (POST): 指定されたIDの掲示板を削除する **/

        // POST: BulletinBoards/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            /**  掲示板を検索し、削除を実行 **/
            BulletinBoard bulletinBoard = db.BulletinBoards.Find(id);
            db.BulletinBoards.Remove(bulletinBoard);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        /**  リソースを解放するためのメソッド **/
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
````
--------------------------------------------------------------
--------------------------------------------------------------
## <font color="green">⑩作成されたViewsの確認</font>

Viewsディレクトリには各アクションに対応するHTMLファイルが存在します。

10.1. Index.cshtml
```html
@model IEnumerable<YourApp.Models.YourModel>

<!-- モデルのデータを一覧表示するためのビュー -->
<h2>Index</h2>

<p>
    <!-- 新しいデータを作成するためのリンク -->
    <a asp-action="Create">Create New</a>
</p>

<table class="table">
    <thead>
        <tr>
            <th>
                <!-- カラム名（プロパティ名）を表示 -->
                @Html.DisplayNameFor(model => model.Property1)
            </th>
            <!-- 他のカラムも同様に表示 -->
            <th></th>
        </tr>
    </thead>
    <tbody>
    @foreach (var item in Model) {
        <tr>
            <td>
                <!-- 各行のデータを表示 -->
                @Html.DisplayFor(modelItem => item.Property1)
            </td>
            <td>
                <!-- 詳細、編集、削除リンクを表示 -->
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
    }
    </tbody>
</table>
````
リスト形式でデータの一覧を表示します。
データを表示し、編集や削除、詳細のリンクがついています。

------------------------------------
10.2. Details.cshtml
```html
@model YourApp.Models.YourModel

<!-- データの詳細情報を表示するビュー -->
<h2>Details</h2>

<!-- 各プロパティの表示 -->
<div>
    <h4>YourModel</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Property1)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Property1)
        </dd>
        <!-- 他のプロパティも同様に -->
    </dl>
</div>

<!-- 編集リンク -->
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<!-- リストに戻るリンク -->
<a asp-action="Index">Back to List</a>
````
新しいデータを作成するためのフォームを表示します。フォームには検証エラーを表示する機能も含まれています。

------------------------------------
10.3. Create.cshtml
```html
@model YourApp.Models.YourModel

<!-- 新しいデータを作成するフォーム -->
<h2>Create</h2>

<!-- フォームの開始 -->
<form asp-action="Create">
    <div class="form-horizontal">
        <div class="form-group">
            <label asp-for="Property1" class="control-label"></label>
            <!-- 入力フィールド -->
            <input asp-for="Property1" class="form-control" />
            <span asp-validation-for="Property1" class="text-danger"></span>
        </div>
        <!-- 他のプロパティも同様に -->
    </div>
    <div class="form-group">
        <input type="submit" value="Create" class="btn btn-default" />
    </div>
</form>

<!-- リストに戻るためのリンク -->
<a asp-action="Index">Back to List</a>
````
新しいデータを作成するためのフォームを表示します。フォームには検証エラーを表示する機能も含まれています。

------------------------------------
10.4. Edit.cshtml
```html
@model YourApp.Models.YourModel

<!-- データの編集フォーム -->
<h2>Edit</h2>

<!-- フォームの開始 -->
<form asp-action="Edit">
    <div class="form-horizontal">
        <div class="form-group">
            <label asp-for="Property1" class="control-label"></label>
            <!-- 編集用の入力フィールド -->
            <input asp-for="Property1" class="form-control" />
            <span asp-validation-for="Property1" class="text-danger"></span>
        </div>
        <!-- 他のプロパティも同様に -->
    </div>
    <div class="form-group">
        <input type="submit" value="Save" class="btn btn-default" />
    </div>
</form>

<!-- リストに戻るリンク -->
<a asp-action="Index">Back to List</a>
````
既存のデータアイテムを編集するためのフォームを表示します。ユーザーはフォームで編集し、「Save」を押すことで変更を保存します。

------------------------------------
10.5. Delete.cshtml
```html
@model YourApp.Models.YourModel

<!-- データの削除確認ビュー -->
<h2>Delete</h2>

<!-- 削除するデータの確認 -->
<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>YourModel</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Property1)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Property1)
        </dd>
        <!-- 他のプロパティも同様に -->
    </dl>
</div>

<!-- 削除フォーム -->
<form asp-action="Delete">
    <input type="hidden" asp-for="Id" />
    <input type="submit" value="Delete" class="btn btn-danger" /> |
    <!-- キャンセルリンク -->
    <a asp-action="Index">Back to List</a>
</form>
````
ユーザーに特定のデータを削除するか確認する画面です。削除を確定するとデータが削除されますが、キャンセルも可能です。

--------------------------------------------------------------
## その他（サブアカウント）

https://qiita.com/nekoozi/items/89268cf62079b3904cdf
   
------------------------------------

   次回：ASP.NET Core MVC 記載まとめ　【初学者編】1

https://qiita.com/nano357/items/6d573e1845ab4216c56d

--------------------------------------------------------------