MVCをWeb作成から理解する。

### 処理フロー
1. ログイン画面を初期表示
2. ログイン画面からサインアップ画面に移動
3. アカウント登録を行い、サインイン画面に移動
4. 作成したアカウントでサインイン


### 開発環境
<table>
    <tr>
      <td>IDE</td>
      <td>Visual Studio</td>
    </tr>
    <tr>
      <td>フレームワーク</td>
      <td>.Net Core</td>
    </tr>
    <tr>
      <td>バックエンド</td>
      <td>C＃</td>
    </tr>
        <tr>
      <td>フロントエンド</td>
      <td>Html Css JavaScript </td>
    </tr>
    <tr>
      <td>DB</td>
      <td>My Sql</td>
    </tr>
    <tr>
      <td>DB操作</td>
      <td>Linq</td>
    </tr>    
    <tr>
      <td>Webサーバ</td>
      <td>Apache Tompat</td>
    </tr>    
 </table>

:::note info
クライアントとApacheの間にTomcatを挟むことでアクセス数が多くなった場合も対応できるようになるため。
:::

### SDK　
.NET SDK をダウンロードする(.NET Coreを扱うために必要)
https://dotnet.microsoft.com/ja-jp/download/visual-studio-sdks

### Entity Framework Core
.NET Coreの中のMVCの構造を再現するためのMVCフレームワーク

:::note info

NuGet
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951099/d949f8a7-6058-2182-9a8c-42fbb239f430.png)
:::

:::note info

:::

### ファイル構成
<details>
<summary>ファイル構成を開く</summary>
<div>

プロジェクト名
├Migrations
├Model
│├ Book.cs
│└ User.cs
├Pages
│└Shared
│ ├ Index.cshtml　ー　(View)
│ │└ Index.cshtml.cs　ー　(Service)
│ ├ LoginPage.cshtml
│ │ └ LoginPage.cshtml.cs
│ ├ Mypage.cshtml
│ │└ Mypage.cshtml.cs
│ ├ privacy.cshtml
│ │ └ privacy.cshtml.cs
│  └ SignUp.cshtml
│   └ SignUp.cshtml.cs
├ViewModel
│├LoginPageVModel.cs
│├MypageVModel.cs
│└SignUpVModel.cs
├appsettings.json
├MyContext.cs
└Program.cs

<details>
<summary>ファイル構成詳細</summary>
<div>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951099/fd0e1e33-987f-2349-198d-69b31834a2d7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951099/02778420-cc81-6770-d4ae-f9ea581f4f02.png)

</div>
</details>

</div>
</details>

# DBとMVCの関係性
### 全体のデータ流れ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951099/208d5657-67f1-7931-62a3-859ae61335cf.png)

## 部分的に切り分けて理解していく
### ModelーDBのテーブルにあたる役割

<details>
<summary>サンプルコード</summary>
<div>

#### Modelの記述方法(book.cs User.cs)
~~~C#:User.cs
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;

namespace MvcEx0421.Model
{
    public class User : IdentityUser
    {
    }
}

~~~

:::note info
#### IdentityUser（.NET Coreの機能）
IdentityUserを継承することで、ユーザ管理に必要な基本情報をModelに作成できる。
UserModelに基本情報以外のプロパティを定義することができる。
:::

~~~C#:Book.cs
using System.ComponentModel.DataAnnotations;

namespace MvcEx0421.Model
{
    public class Book : User
    {
        [Required]//アノテーション
        [Key]
        [Display(Name = "書籍番号")]
        public int Id { get; set; }

        [Display(Name = "書籍名")]
        public string Name { get; set; }

        //コンストラクタの定義は必ず行う(変数には空を定義)
        public Book()
        {
            Id = 0;
            Name = "";
        }

        //Idが1の時佐藤さんが確定で入る場合はメソッドを定義しておくといい
        public Book(int satouNum = 1)
        {
            Id = BookId;
            Name = "漫画";
        }
    }
}


~~~

:::note info
#### アノテーション(属性)ー[Key][Display(Name = "書籍番号")]
Modelで定義したプロパティに対し、制限を付けることができる.NET Coreの機能

**アノテーション一覧**
https://qiita.com/mrpero/items/607c31895d77815a77cb
:::

#### マイグレーションファイルとは
DBの構成を定義し、DBの生成を一括して行うSQL群をまとめたファイル

:::note info

**マイグレーションファイルを自動生成する手順**
1. 必要なパッケージをインストールする
    - Sqliteを扱うため
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951099/23bd4147-b1c0-9fc6-f105-3121e8fe5968.png)
    - コマンドベースでDBをMigrationしたり、DBFileからDbContextクラスを**スキャフォールディング**することが出来ます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951099/f5b33d25-847c-ee85-0bbe-19d81fbe33f1.png)
**スキャフォールディングとは**
データモデルとなる型を元に、いわゆるCRUD（Create/Read/Upadate/Delete)と呼ばれる追加、読込、変更、削除を行う画面とそのコードを自動で生成する機能のことです

2. MyDbContext.csには下記を定義する
    - DBの接続
    - テーブル
    - テーブル間のリレーション
        - **MyDbContextの役割**
            - 定義したModelを、MyDbContextで各Modelの関係性と存在を定義すること
            - DBへの接続情報と接続処理を行うこと
            
3. マイグレーションファイルの作成
    - パッケージマネージャコンソールにて下記のコマンドを実行
        - EntityFrameworkCore\Add-Migration InitialCreate 
        - Add-Migration InitialCreate 
4. マイグレーションファイルの実行
    - パッケージマネージャコンソールにて下記のコマンドを実行
        - EntityFrameworkCore\Update-Database
        - Add-Migration InitialCreate 

<details>
<summary>サンプルコード（MyDbContext.cs）</summary>

~~~C#:MyDbContext.cs
using Microsoft.EntityFrameworkCore;
using MvcEx0421.Model;

namespace MvcEx0421
{
    public class MyDbContext : DbContext
    {
        public DbSet<Book> Books { get; set; }
        public DbSet<User> Users { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var str = $"Server=IPアドレス;" +
             $"Database=original;" +
             $"Uid=root;" +
             $"Pwd=Password";
            optionsBuilder.UseMySql(str
                , ServerVersion.AutoDetect(str)
            );
        }
    }
}

~~~
</div>
</details>

</div>
</details>

:::

### Serviceーバックエンド処理を担う役割
- DBからModelに値を入れる
- 対象のViewに遷移する（Get Post）
<details>
<summary>サンプルコード</summary>
<div>

~~~Index.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MvcEx0421.Pages
{
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
        
        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }

        public IActionResult OnGet()
        {
            return new RedirectResult("/LoginPage");
        }
        //public IActionResult OnGet()
        //{
        //    return new RedirectToPageResult("LoginPage");
        //}
    }
}
~~~

~~~C#:MyPage.cs
using System.Linq;
using Microsoft.EntityFrameworkCore;
//using System.Web.Mvc;
using Microsoft.AspNetCore.Mvc;
using MvcEx0421.Pages.Shared;
using MvcEx0421.Model;
using MvcEx0421.ViewModel;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MvcEx0421.Pages
{
    public class MyPage
    {
        private readonly ILogger<MyPage> _logger;

        public MyPage(ILogger<MyPage> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IActionResult Index()
        {
            return new ViewResult();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public void OnGet(MyDbContext DbContext, int Id){}
        
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult SignUp(string Id, string Name)
        {
            ///対象のテーブルのコンストラクタの定義
            MyPageVModel vmMyPage = new MyPageVModel();
            ///行の値を定義
            vmMyPage.Id = Id;
            vmMyPage.Name = Name;

            return new ViewResult();
        }
    }
}

~~~

~~~C#:LoginPage.cs
//using System.Web.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using MvcEx0421.Model;
using System.Data;

namespace MvcEx0421.Pages
{
    public class LoginPage
    {
        private readonly ILogger<LoginPage> _logger;
        public LoginPage(ILogger<LoginPage> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
            
        }

        public IActionResult OnPostLogIn(String Id, String Name)
        {
            ///DBにアクセスするためのコンストラクタの定義
            var _DbContext = new MyDbContext();

            var userExistence = _DbContext.Users.Any(x => x.Id == Id);
            var user = _DbContext.Users.Where(x => x.Id == Id);

            if (userExistence == true)
            {
                return new RedirectToActionResult("Mypage", "MyPage", user);
            }
            else
            {
                return new ViewResult();
            }
        }
    }
}

~~~

~~~C#:SignUp.cs
using System.Linq;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using MvcEx0421.Pages.Shared;
using MvcEx0421.Model;
using Microsoft.AspNetCore.Mvc;

namespace MvcEx0421.Pages
{
    public class SignUp
    {
        private readonly ILogger<SignUp> _logger;

        public SignUp(ILogger<SignUp> logger)
        {
            _logger = logger;
        }

        public void Index()
        {
        }

        public IActionResult OnPostMemberCreate(string Id, string Name)
        {
            ///DBにアクセスするためのコンストラクタの定義
            MyDbContext cx = new MyDbContext();
            ///対象のテーブルのコンストラクタの定義
            User user = new User();
            ///行の値を定義
            user.Id = Id;
            user.UserName = Name;

            ///Model OR ViewModelに値を挿入
            cx.Add(user);

            ///セーブする。
            cx.SaveChanges();

            if (user.UserName == "")
            {
                return new ViewResult();
            }
            else
            {
                return new RedirectResult("/LoginPage");
            }
        }
    }
}

~~~

</div>
</details>

</div>
</details>

### ViewModelー対象のView専用に作成するModel
<details>
<summary>サンプルコード</summary>
<div>

~~~C#:MypageVModel.cs
using Microsoft.AspNetCore.Mvc.RazorPages;
using MvcEx0421.Model;

namespace MvcEx0421.ViewModel
{
    public class MyPageVModel : PageModel
    {
        public string UserId { get; set; }
        public string UserName { get; set; }
        public string BookId { get; set; }
        public string BookName { get; set; }

        public MyPageVModel()
        {
            User user = new User();
            UserId = user.Id;
            UserName = user.UserName;

            Book book = new Book();
            BookId = book.Id;
            BookName = book.Name;
        }
    }
}

~~~
</div>
</details>


### ViewーWeb画面
<details>
<summary>サンプルコード</summary>
<div>

~~~ SignUp.cshtml
@page
@model ViewModel.SignUpVModel
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
</head>
<body>
    <div>
        <form method="POST" >
            <table border="1">
                <tr>
                    <th>Id</th>
                    <!-- name属性「name="name_box"」を設定する事で、遷移先で受け取り可能になる -->
                    <td><input type="text" id="id" name="id" /></td>
                </tr>
                <tr>
                    <th>name</th>
                    <td><input type="text" id="name" name="name" /></td>
                </tr>
            </table>
            <!-- 送信ボタンのtypeはsubmitを指定する -->
            <input type="submit" asp-page-handler="MemberCreate" value="登録" >
        </form>
    </div>
</body>
</html>

~~~

:::note info
asp-系の使い方
https://learn.microsoft.com/ja-jp/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-8.0
:::

</div>
</details>