Asp.Net Core MVC + SQL Server で始めるTodoアプリ開発。

`ASP.NET Core` の学習メモです。今回は`ASP.NET Core MVC`について学んでいきます。

#前提

1.開発環境

|環境/ソフトウェア      | 内容                     |
|:-----------------|:----------------------|
|  OS        | Windows 10 Pro   |
|.NET Core SDK| 3.1|
|IDE| Visual Studio 2019|
|Browser|Google Chrome|
|DB|SQL Server 2019 Express|
|DB GUIツール|SSMS(Sql Server Management Studio)|

2.DL
 1. [VisualStudio](https://visualstudio.microsoft.com/ja/downloads/)
 2. [SQL Server](https://www.microsoft.com/ja-jp/sql-server/sql-server-downloads)
 3. [SSMS](https://docs.microsoft.com/ja-jp/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver15)

#Todoアプリ作成

##DB作成

`SSMS`と`SQLServer`との接続はこちらの記事を参照してください。
https://sql55.com/sql-server/connecting-to-database-engine.php

<img width="507" alt="ssms1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/659034a2-a001-334e-c605-40aef0521d75.png">

`SSMS`から**[データベース]**を右クリックし**[新しいデータベース]**を選択。

![新しいデータベース 2020_06_05 10_43_47 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/a40daf2f-d535-bc4b-f427-c7aef212097c.png)

データベース名はお好みで。今回は**[DotNetPractice]**にしました。
[OK]をクリックしたらデータベースが作成されていると思います。

##プロジェクト作成
###環境構築

* Visual Studioから**[新しいプロジェクト作成]**を選択。
* **[ASP.NET Core Webアプリケーション]**を選択し**[次へ]**をクリック。
* プロジェクト名を**「TodoApp」**とし、**[作成]**を選択。
* **[Web Application(Model-View-Controller)]**を選択し**[作成]**をクリック。

既定のテンプレが作業ディレクトリに作成されたらok.

###アプリ実行

実行する前にビルドしておきましょう。
タブバーから**[ビルド]**を選択し**[ソリューションのリビルド]**を選択しビルドを行う。

ビルドが完了したらアプリを実行します。
Visual Studioでは**IIS Express**からアプリの実行が可能です。

アドレスはもちろん`localhost:port#`が表示されます。

![Home Page - TodoApp - Google Chrome 2020_06_01 17_13_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/55275b6f-a3fc-07f7-9cee-c0d1344108ec.png)


##Model追加

###TodoItemモデル作成
アプリのモデルクラスは`Entity Framework Core(EF Core)`を使用してデータベースを扱います。

Visual Studioでは**[ソリューションエクスプローラー]**→**[Modelsフォルダ]**を選択し右クリック**<br>[追加]**→**[クラス]**

ファイル名は**[TodoItem.cs]**として作成する。

```C#:Models/TodoItem.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace TodoApp.Models
{
    public class TodoItem
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Discription { get; set; }
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
    }
}
```

TodoItemクラスには**Id**, **Title**, **Discription**, **ReleaseDate**が含まれている。

###NuGetパッケージを追加

タブから**[ツール]**→**[NuGetパッケージマネージャー]**→**[パッケージマネージャーコンソール]**を選択。
PMCを開いて以下コマンドを実行。

```shell
Install-Package Microsoft.EntityFrameworkCore.SqlServer
```

###DBコンテキストクラスを作成・登録

コンテキストクラスはEFCore機能(CRUD)のために必要。
作業ディレクトリに**Dataフォルダ**を作成します。
Dataフォルダ内に以下の**TodoContext.csファイル**を追加します。

```C#:Data/TodoAppContext.cs
using Microsoft.EntityFrameworkCore;
using TodoApp.Models;

namespace TodoApp.Data
{
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options) : base(options)
        {
        }
        public DbSet<TodoItem> TodoItem { get; set; }
    }
}
```

コンテキストファイルが作成出来たら**Startup.cs**に次の`using`ステートメントを追加。

```C#:Startup.cs

using TodoApp.Data;
using Microsoft.EntityFrameworkCore;
```

追記した**Startup.cs**の**[ConfigureServices]メソッド**にTodoContextを新規追加する。

```C#:Startup.cs

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddDbContext<TodoContext>(opt =>
            opt.UseSqlServer(Configuration.GetConnectionString("TodoContext")));
        }
```

###SQL Server接続

DB接続に必要な**appsettings.json**ファイルを編集します。

が、その前に先ほど作成した**DotNetPractice**データベース情報をVisual Studioから覗いてみましょう。

タブから**[表示]**→**[サーバーエクスプローラー]**を選択→**[データベースの接続]**を選択しクリック。

<img width="690" alt="vs1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/c045c2b0-1e3a-4e7b-4204-152b1f1869fc.png">

サーバー名を先ほどの**SSMS**で使用したローカルサーバを選択。

![TodoApp - Microsoft Visual Studio 2020_06_05 11_12_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/12b2397c-67f3-72a5-00e3-0d108332db76.png)



[OK]をクリックするとデータベースが接続されると思います。
あとはアプリに**接続文字列**を渡してあげるだけ。

接続文字列は先ほどのデータベースのプロパティから参照することができます。

<img width="953" alt="vs2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/e18ec243-fc0e-29ca-27a0-a78aadf6225b.png">




```json:appsetting.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "TodoContext": "ココに接続文字列を入力"
  }
}
```
これで接続は完了♪


###Initialデータ作成
データベース作成時の初期化データを作成します。
Modelフォルダ内に新しく**[SeedData.cs]**ファイルを作成してください。

```C#:Model/SeedData.cs
using System.Linq;
using TodoApp.Data;

namespace TodoApp.Models
{
    public class SeedData
    {
        public static void Initialize(TodoContext context)
        {
            context.Database.EnsureCreated();

            if (context.TodoItem.Any())
            {
                return;
            }

            context.TodoItem.AddRange(
                new TodoItem
                {
                    Title = "Shopping",
                    Discription = "tomato, carrot, pork, egg, flower",
                    IsComplete = false
                },
                new TodoItem
                {
                    Title = "Work",
                    Discription = "studying .NET Core",
                    IsComplete = false

                }
            );
            context.SaveChanges();
        }
    }
}

```
`Any()`でデータベースに値があれば**return**します。
なければSeedDataをデータベースに格納してくれます。



**[SeedData]**クラスを作成した後は、呼び出し処理を**[Program.cs]**ファイルに追記・変更します。

```C#:Program.cs

using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using TodoApp.Data;
using TodoApp.Models;

namespace TodoApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = BuildWebHost(args);

            using (var scope = host.Services.CreateScope())
            {
                var provider = scope.ServiceProvider;
                try
                {
                    var context = provider.GetRequiredService<TodoContext>();
                    SeedData.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = provider.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "データベース初期化中にエラーが発生しました。");
                }
            }



            host.Run();
        }


        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

```


ここまで出来たら一度`Model`の設定は終了です！お疲れ様でした。

##Controller・View追加

次はViewとコントローラーを作っていきますが、これは思ったより簡単です。
`ASP.NET Core`にある**[スキャフォールディング]**機能を使用します。

###スキャフォールディング

スキャフォールディングは、**CRUD(create,read,update,delete)**処理を行う画面のコードをデータモデルを元にして自動生成する機能です。

Visual Studioでは**[ソリューションエクスプローラー]**→**[Controllerフォルダ]**を選択し右クリック**[追加]**→**[新規スキャフォールディングアイテム]**を選択。


**[スキャフォールディングを追加]**ダイアログから**[Entity Framework を使用したビューがあるMVCコントローラー]**を選択し**[追加]**。

![TodoApp - Microsoft Visual Studio 2020_06_01 21_18_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/257fccd4-0476-0264-ca9f-b8b1538fa73b.png)

追加したタイミングで表示されるウィンドウは以下のように設定します。
![TodoApp - Microsoft Visual Studio 2020_06_05 13_24_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/579c130f-b9d9-8bf2-09fb-3b7d39daaf73.png)



設定が終わったら**[追加]**を選択しあとは勝手にファイルを生成してくれます。

※まだ**Migration**されていないのでDB内のテーブルはまだ作成されておらずデータはカラだと思います。最後にMigrationしてデータをアプリ側でもいじれるようにしましょう。

###Migration

データベースは`Entity Framework Core`のMigration機能をつかって作成します。PMCに以下のコマンドを入力してください。

```shell

Add-Migration InitialCreate
Update-Database
```
マイグレーションが実行されると作業ディレクトリに**「Migrations」フォルダ**が作成されていると思います。これは`TodoContext`クラスで指定されたモデルに紐づいて作成されています。


# アプリ実行

ここまででディレクトリは以下のようになっていると思います。

```
TodoApp/
     ├ Properties/
     ├ wwwroot/
     ├ 依存関係/
     ├ Controllers/
        └ HomeController.cs
        └ TodoItemsController.cs
     ├ Data/
        └ TodoContext.cs
     ├ Migrations/
     ├ Models/
        └ ErrorViewModel.cs
        └ SeedData.cs
        └ TodoItem.cs
     ├ Views/
        └ Home/
        └ Shared/
        └ TodoItems/
        └ _ViewImports.cshtml
        └ _ViewStart.cshtml
     ├ appsettings.json
     ├ Program.cs
     ├ Startup.cs

```

ここで一度アプリを開いてみましょう。
アドレスは`localhost:port/TodoItems/`で表示されます。

![Index - TodoApp - Google Chrome 2020_06_05 13_53_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579246/3affa62c-7975-762c-2900-9716f84a094e.png)

こんな感じにアプリが実行できていれば完成です！
後はCRUDでいろいろデータをいじってみて下さい♪



お疲れ様でした。

#まとめ。

今回`ASP.NET Core`と`SQL Server`を使用して簡単なTodoアプリを作成してみました。
初めてスキャフォールディングの機能を使ったときはびっくりしました。
~~「こんな簡単にCRUD作れるんだ…笑」~~

まだ`.NET Core`を完全に理解したわけではないのでここからいろいろ深堀できればと思います。
それでは。