koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

MySql.EntityFrameworkCore で ASP.NET Identity

.NET(Entity Framework Core)を使うならSQL Serverを使っておけ、というのが正直なところなのだけれど、MySQLを使ってみたいと思うこともあるだろう。

ので試した。ASP.NETにはASP.NET Identityという認証ライブラリがあって、Webアプリケーション作成時にチェックボックスを入れるだけでその基本的な構成が行われる。僕が一番好きなIdentiyです。

が、そうすると当然ながらSQL Server向けになっており、MySQLで使うにはちょっと手を加えなくてはならない。

とりあえずユーザー登録とログインができるようになるためにやったことをメモしておく。

Entity Framework Coreのコードファーストマイグレーションを使うのが前提です。

.NET 5 で MySQL を使う

Connector/NET 8.0.23でサポートされているようだ。

dev.mysql.com

  • Microsoft.EntityFrameworkCore.SqlServer パッケージを削除(使わないので)
  • MySql.EntityFrameworkCore パッケージを追加(使うので)
    • 2021-2-18現在プレリリースなのでパッケージマネージャではプレリリース版にチェックを入れないと出てこない
  • UseSqlServerUseMySQL に変更

Update-Database Errror

とりあえずUpdate-Databaseしてみたらエラーした。

Unable to create an object of type 'ApplicationDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

これは僕の構成が悪いのかもしれないが、何が悪いのか調べるのは面倒くさかったのでIDesignTimeDbContextFactoryを実装してしのいだ。

code:ApplicationDbContextFactory.cs
 using Microsoft.EntityFrameworkCore;
 using Microsoft.EntityFrameworkCore.Design;
 
 namespace Application1.Data
 {
     public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
     {
         public ApplicationDbContext CreateDbContext(string[] args)
         {
             var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
             optionsBuilder.UseMySQL("server=localhost;database=application1;user=root;password=root-password");
 
             return new ApplicationDbContext(optionsBuilder.Options);
         }
     }
 }

ASP.NET Identiy 対応(2021-02-19追記分)

先にこの後書いた対応をしていたけれど、追加でMigrationを作っていくと不整合が起きていった。生成されたマイグレーションを置換するのはやめて、ちゃんとEntityの定義を変えてあげたほうがよさそうだった。

  1. 既定のDBContextで使われるEntityのProperty属性を指定やる
  2. カスタマイズした各EntityのProperty属性を指定する

どちらかをしてやればいい。

1の場合は以下のような感じになる。これでもともと存在するMigrationファイルを削除した後単に Add-Migration すればキー長超過するテーブルがなくなった。

{
    public class ApplicationDbContext : IdentityDbContext
    {
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity<IdentityUser>(b => b.Property(p => p.Id).HasMaxLength(128));
            builder.Entity<IdentityRole>(b => b.Property(p => p.Id).HasMaxLength(128));
            builder.Entity<IdentityUserLogin<string>>(b =>
            {
                b.Property(p => p.LoginProvider).HasMaxLength(128);
                b.Property(p => p.ProviderKey).HasMaxLength(128);
            });
            builder.Entity<IdentityUserToken<string>>(b =>
            {
                b.Property(p => p.LoginProvider).HasMaxLength(128);
                b.Property(p => p.Name).HasMaxLength(128);
            });
        }
    }
}

2の場合は自分で定義したEntity(ApplicationUserとかApplicationRoleとか)に同様にPropertyの属性を指定してやればいい。

ASP.NET Identiy 対応

さしあたってこれでユーザー登録とログインは可能だった。

  • 既定のMigration構成はSQL Server向けなので削除する。
    • Webアプリケーション作成時の認証を有効にした時にスキャフォルドされるやつ。
  • 改めて Add-Migration する。
  • そのままだとプライマリキー長を超過しているスキーマになるので適当に長さを変える。
    • ※この置換対応はやめたほうがいい。前の項に追記したようにちゃんとEntityのProperty属性をしてしたほうが無難。
    • 767 -> 256 にしてみた。
    • MySQLのバージョンでキー長の制限が違っていたり、文字コードで1文字のバイト数が違ったりするだろうから適当に。

ググれよ

先の対応をしてからググったらそりゃ例はあった。

使ってる.NET 5ではなくパッケージが古い(MySql.Data.EntityFrameworkCore)版だったので先にググっていたら同じ手法では動かなかったかもしれない。

結果オーライ。

もっとちゃんとググると公式な.NET 5ドキュメントも見つかるかもしれないが、それを試すには今日はもう遅すぎる。