ASP.NET Core MVCでIdentityをつかう。DB作成まで

# はじめに

Qiita初投稿です。
MVCでIdentityをつかってアプリケーションをつくるなかで手順などの備忘録です。

# 環境
・Windows 10
・Visual Studio2022
・MariaDB 10.9.3


# 目標
・IdentityUserを継承した独自ユーザモデルを作成
・独自ユーザモデルをもとにしたDB作成をおこなう

# 作業

## 新規プロジェクトの作成

いったんバージョン確認。
```
> dotnet --version
6.0.402
```
MyIdentityというソリューションをつくる
MyIdentityという名前のプロジェクトをMVCのIdentityオプションで作成します
```
> mkdir MyIdentity
> cd MyIdentity
> dotnet new sln
> dotnet new mvc --auth Individual -n MyIdentity
> dotnet sln add MyIdentity
```

[.NET default templates for dotnet new - .NET CLI | Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-new-sdk-templates#web-options)

コマンドラインからではなく、VisualStudioをぽちぽちしてもプロジェクトは作成できます。

## appsettings.jsonを変更
```diff:appsettings.json
{
  "ConnectionStrings": {
-    "DefaultConnection": "DataSource=app.db;Cache=Shared"
+    "DefaultConnection": "Server=localhost;Database=MyIdentity;user=root;password=root;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

```
VisualStudioからプロジェクトを作成した場合だとSqlServerに接続するようになってたが、どこかで設定する箇所があったかは不明です。
Database=<任意のDB名>があとでDB作成する際に作成される名称になります。

## 独自ユーザモデルの作成

```Models/CustomIdentityUser.cs
using Microsoft.AspNetCore.Identity;

namespace MyIdentity.Models
{
    public class CustomIdentityUser : IdentityUser
    {
        public bool IsDeleted { get; set; }
    }
}
```
IdentityUserを継承したモデルを作成します。
論理削除したいのでそういうカラムを用意しました。

## IdentityUserを置き換える

```diff:Program.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using MyIdentity.Data;
+ using MyIdentity.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();


- builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
+ builder.Services.AddDefaultIdentity<CustomIdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews();

var app = builder.Build();
```
IdentityUserを使用している箇所を、先ほど作成したCustomIdentityUserに変更します。
ちなみに.NET6以前は Startup.cs と Program.cs が存在していたのですが、.NET6以降はProgram.csに一本化されています。
参考ソースをネットで見つけたらStartup.csを変更する～とか書かれているものについては読み替えが必要になります。
[ASP.NET Core 5.0 から 6.0 への移行 | Microsoft Learn](https://learn.microsoft.com/ja-jp/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio)

## パッケージの追加
```
> dotnet add package Pomelo.EntityFrameworkCore.MySql
```
MariaDB(MySQL)を使用する際はこのパッケージが必要です。
Oracleの MySql.EntityFrameworkCore というパッケージもありますが、MySQLにしか対応してないみたいです。
また、評判も芳しくないようなので素直にこちらを使います。
[データベース プロバイダー - EF Core | Microsoft Learn](https://learn.microsoft.com/ja-jp/ef/core/providers/?tabs=dotnet-core-cli)

## MariaDBを使用するように変更する
```diff:Program.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
+ using Microsoft.Extensions.Options;
using MyIdentity.Data;
using MyIdentity.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
-     options.UseSqlite(connectionString));
+     options.UseMySql(connectionString,MySqlServerVersion.AutoDetect(connectionString)));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
```
UseSqliteしていたところをUseMySqlに変更します。
引数にはVersionも必要になります。

## ApplicationDbContextの編集

```diff:ApplicationDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
+ using MyIdentity.Models;

namespace MyIdentity.Data;


- public class ApplicationDbContext : IdentityDbContext
+ public class ApplicationDbContext : IdentityDbContext<CustomIdentityUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}
```
IdentityUserではなくCustomIdentityUserを使用するので、IdentityDbContextを修正します。

[ASP.NET Core での Identity モデルのカスタマイズ | Microsoft Learn](https://learn.microsoft.com/ja-jp/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-6.0)

## DBの作成
プロジェクトを作成したときに、以下のようにMigrationsフォルダに 00000000000000_CreateIdentitySchema.cs というファイルが作成されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211672/d61eb46d-07d0-05ec-8422-42932d7f703b.png)
このままDB作成コマンドを流すとこのmigrationファイルでMariaDBにDBと各Tableを作成しようとします（DBの作成は成功してテーブルの作成中でエラーになるはず）。
なので、00000000000000_CreateIdentitySchema.cs を削除してあらたにmigrationファイルを作成します。
それでもってDBを作成していきます。


### dotnet ef migrations remove
```
>dotnet ef migrations remove
Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.10 initialized 'ApplicationDbContext' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.2' with options: ServerVersion 10.9.3-mariadb
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (15ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='MyIdentity' AND TABLE_NAME='__EFMigrationsHistory';
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT `MigrationId`, `ProductVersion`
      FROM `__EFMigrationsHistory`
      ORDER BY `MigrationId`;
Removing migration '00000000000000_CreateIdentitySchema'.
Removing model snapshot.
Done.

```

これで最新のmigrationファイルを取り除きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211672/967b49be-009d-3bfd-e5ce-a0b67659d267.png)
先ほどのMigrationsフォルダごと消えます。

### dotnet ef migrations add [migration name]
```
>dotnet ef migrations add Init
Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.10 initialized 'ApplicationDbContext' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.2' with options: ServerVersion 10.9.3-mariadb
Done. To undo this action, use 'ef migrations remove'
```
[migration name]の部分は任意の名称をつけます。
Migrationsフォルダとその下に先ほどInitと名付けたmigrationファイルができています。
（Dataフォルダ直下ではなくなっているが動作に問題はない）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211672/aa2e006a-5909-fbc1-7ac4-befe93403e46.png)

ちなみに 20221022140745_Init.cs の中身はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211672/23484a32-8491-a482-dc0b-f0087cab91b5.png)

Up() と Down() があり、作成されたマイグレーションをDBに反映するとき順番にUp()したり、最新から任意のマイグレーションバージョンに戻すときに順番にDown()を適用したりする、という使われ方のはず。
基本的に、このファイルの中身を変更することはないです。

### dotnet ef database update
```
>dotnet ef database update
Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.10 initialized 'ApplicationDbContext' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.2' with options: ServerVersion 10.9.3-mariadb
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE DATABASE `MyIdentity`;
（中略）
Done.

```
接続先に対してmigrationファイルで定義されたとおりにDBとテーブルを作成しています。
以下はMariaDBをいれたときについてきたHeidiSQLで見たテーブル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211672/f98fef8f-f677-1d2a-159d-f8312a05d54f.png)
Identityに必要な各テーブルが作成されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211672/2829a295-a888-d5eb-899c-6b4dc6b3570c.png)
IdentityUserをカスタムしたCustomIdentityUserで定義したIsDeletedカラムが作成されています。

# おわりに
引き続きアプリケーション作成の備忘録を書いていきます。

※作成されたテーブルについて
WindowsだとMariaDB(MySQL)のデータベース名やテーブル名が小文字になるのは、なんらかの設定の問題だったはず…
大文字を含むDB名、テーブル名がつくれるようにしたい場合は、必要に応じて調べてください…
一応、次回以降でモデル名と関係なくテーブル名を小文字で定義するということをやります。