.NETCore3.1+MariaDB & Identity導入


はじめに

MariaDB(MySQL)を使った.NETCore3.1+IdentityのDocumentが少ないので作成。

ゼロから構築していくエントリーとしますので、最初から全部書いていきます。
KestrelからNginxに橋渡ししてますが、Webサーバは本稿のキモとは関係がないでしょう。

構成

Architecture Name
Machine Azure
OS CentOS 8
Web Server Nginx
Framework .NETCore 3.1
DB Azure Database for MariaDB

手順

.NETCore 3.1 の導入

sudo su
yum update -y
yum install -y libunwind libicu lsof
yum list | grep dotnet
yum install -y dotnet-sdk-3.1.x86_64
dotnet --version

Projectの作成

mkdir /var/www/html -p
cd /var/www/html
dotnet new mvc --auth Individual -o TestProject

今回はMVCで立てます。

MariaDB用のPackageを導入

cd TestProject
dotnet add package Pomelo.EntityFrameworkCore.MySql

エディタでのSSH接続

以降に出てくるコマンド以外の編集作業はVisual Studio CodeあたりでSSH接続すれば非常に快適。
ググればエントリーは無限に出てきますので、ここでは割愛します。

Kestrelの構築

Program.cs

webBuilder.UseUrls("http://0.0.0.0:5000/"); //追記
webBuilder.UseStartup<Startup>();

/etc/systemd/system/kestrel-test.service(新規作成)

[Unit]
Description=Example .NET Web API App running on CentOS

[Service]
WorkingDirectory=/var/www/html/TestProject
ExecStart=/usr/bin/dotnet /var/www/html/TestProject/published/TestProject.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
#Environment=ConnectionStrings__DefaultConnection={Connection String}
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

コマンド実行

systemctl daemon-reload
systemctl enable kestrel-test.service
systemctl restart kestrel-test.service

nginxの構築

/etc/nginx/nginx.conf

server_name  write.your.ip.address;

location / {
    proxy_pass http://localhost:5000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection keep-alive;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}
nginx -s reload

SELinuxによるアクセス制御設定

setsebool -P httpd_can_network_connect 1

HTTPS Redirectionの一時停止(省略可)

Startup.cs

//app.UseHttpsRedirection();    //コメントアウト

MariaDBの構築

yum install mariadb -y
mysql -h write.mariadb.ip.address -u username -p
create database dbname;
exit

.NETCoreとMariaDBとの接続

appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=write.mariadb.ip.address;userid=username;password=yourpassword;database=dbname;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Startup.cs

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseMySql(
            Configuration.GetConnectionString("DefaultConnection")));

.NETCore Identityによる認証の実装

Identity関連TableのMigration File修正

MariaDB(MySql)の環境下においては、IdentityがDefaultで持っているMigation Fileを無修正で実行できない。
 ⇒nvarchar(MAX)やDateTimeOffset型がないため。

Data/Migrations/00000000000000_CreateIdentitySchema.cs
・DateTimeOffsetをひとまず<string>に書き換え。

たとえばこんなかんじ

// LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnd = table.Column<string>(nullable: true),

Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
nvarchar(MAX)をひとまずnvarchar(1024)で置換(そんなにいらないかもしれない)。
DateTimeOffsetをひとまず<string>nvarchar(64)に書き換え。
※DateTimeOffsetカラムについては、Defaultの設定だと何のデータもInsertされてこないのでErrorにはならない。

たとえばこんなかんじ

b.Property<string>("ConcurrencyStamp")
   .IsConcurrencyToken()
   .HasColumnType("nvarchar(1024)");

Migrationの実行

準備ができたらMigrationを実行する。

dotnet ef database update

Migrationの実行でエラーが出てしまった場合は、DB側に出来てしまったTable群を削除し、再実行する。
 ⇒Foreign制約がかかっているため、綺麗に同時消しができなかったりする。Tableを消すときの順番に注意。

なお、成功した場合は以下のようになる。

$ dotnet ef database update
Build started...
Build succeeded.
Done.

Migrationに成功した場合であっても、やり直したいと思うことがあるかもしれない。
その場合は、Migration Fileの編集+Table群のDropで再度Migrationを実行することもできる。
ただし、Migrationが一度完了となった旨の情報が__efmigrationshistoryTableに格納されているので、
Migrationの再実行をする前に、DB側で以下コマンドの実行が必要となる。

truncate table __efmigrationshistory;

 ⇒上記Truncateを実行しないと、いくらdotnet ef database updateしようとも、何も実行しないMigrationがDoneになるだけとなる。

Identity関連のスキャフォールディング

dotnet tool install -g dotnet-aspnet-codegenerator
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet aspnet-codegenerator identity -dc TestProject.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout"

最後の行にはProject名が刺さっているので、適宜変更されたい。


実行

恒久的な実行

既にNginxとKestrelを常時立ち上げるように設定していますので、あとはコンパイルするだけ。

dotnet publish -o published -r centos.8-x64 && systemctl restart kestrel-test.service

コンパイル中にブラウザからアクセスしてしまう等の原因により、Processがバインドされ、上記コマンドがエラーとなることがまれに良くある。
この問題はrebootすれば解決するが、いちいち再起動は地獄。
そんな時は、先にsystemctl restart kestrel-test.serviceを実行してやると回復する。
というか、なんなら最初から以下のコマンドをおすすめしておく。

systemctl restart kestrel-test.service && dotnet publish -o published -r centos.8-x64 && systemctl restart kestrel-test.service

ズボラ極まりないコマンドだが、こうかはばつぐんだ。

開発中の実行

開発中のデバッグ作業であれば、Visual Studio Codeのターミナルからdotnet runすれば非常に便利。
デバッグ用のConsole.WriteLineの出力も同じくターミナルのところに出力されるようになるので、開発ではどんどん使っていきましょう。
ただ、既に kestrel-test.serviceを走らせてしまっているので、これを一旦止める必要がある。

systemctl stop kestrel-test.service
dotnet run

おわり

これでブラウザ上のRegisterからユーザ登録ができると思います。
とっつきにくさ天元突破のMicrosoft公式Documentに頼らざるを得ない部分も多いので、辛みが深いですね。