Asp.Net Core Identity 多資料庫支援

2022-06-04 06:00:32

Asp.Net Core Identity 是.Net自帶的身份認證系統,支援使用者介面 (UI) 登入功能,並且管理使用者、密碼、組態檔資料、角色、宣告、令牌、電子郵件確認等等。使用Visual Studio建立帶有identity的專案時,使用SqlServer作為預設的資料庫,本文介紹如何改造為多種資料庫支援。

首先,使用Visual Studio 2022建立一個新的Asp.Net Core Web專案,名稱為TestIdentity,選擇身份認證型別為個人賬戶:

建立的專案結構如下:

在Data目錄下儲存的是身份認證的DbContext,名稱為ApplicationDbContext,還有基於SqlServer的遷移檔案。我們所要做的第一件事情是將SqlServer部分移動到另一個專案中,然後再增加對其它資料庫型別的支援。

現在我們在解決方案中建立一個新的類庫專案,名稱為IdentityEF,在這個專案中安裝包Microsoft.AspNetCore.Identity.EntityFrameworkCore。然後將ApplicationDbContext移動到這個專案中。

然後我們再建立另一個類庫專案,負責SqlServer資料庫的遷移,名稱為IdentityEF.SqlServer,在這個專案中安裝包Microsoft.EntityFrameworkCore.SqlServer和Microsoft.EntityFrameworkCore.Tools,還要增加對IdentityEF的專案參照,然後將TestIdentity中Data目錄下的Migrations子目錄移動到這個專案中:

然後在這個專案中增加新的類DbContextFactory,程式碼如下:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestIdentity.Data;

namespace IdentityEF.SqlServer
{
    public class DbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=aspnet-TestIdentity-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true",
              x => x.MigrationsAssembly("IdentityEF.SqlServer"));
            return new ApplicationDbContext(optionsBuilder.Options);
        }
    }
}

請注意,上面的資料庫名稱與TestIdentity專案中appsettings.json中定義的DefaultConnection是一樣的,這樣,生成的資料庫在TestIdentity中可以直接使用。

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-TestIdentity-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

再增加一個依賴注入擴充套件IdentityEFExtension,方便在Web應用中的參照:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestIdentity.Data;

namespace IdentityEF.SqlServer
{
    public static class IdentityEFExtension
    {
        public static IServiceCollection AddIdentityEFSqlServer(this IServiceCollection services, IConfiguration Configuration)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                x => x.MigrationsAssembly("IdentityEF.SqlServer")));
            return services;
        }
    }
}

到這裡,改造基本完畢,在Web應TestIdentity專案中,增加對這兩個專案的參照,然後改造Program.cs,將原有的部分註釋掉,增加AddIdentityEFSqlServer:

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

builder.Services.AddIdentityEFSqlServer(builder.Configuration);

現在,可以在包管理器中,使用Update-Database建立資料庫。首先,將IdentityEF.SqlServer專案設定為啟動專案,在包管理器中,將預設專案也設定為IdentityEF.SqlServer:


然後執行Update-Database,順利的化,資料庫就生成了。將啟動專案改回到TestIdentity,執行專案,我們可以註冊使用者並進行登入了。到這裡,針對SqlServer的部分已經從Web專案中分離,現在,我們增加對其它資料庫型別的支援,比如,我們增加Sqlite的支援。

建立一個新的類庫,名稱為IdentityEF.Sqlite,增加程式包Microsoft.EntityFrameworkCore.Sqlite和Microsoft.EntityFrameworkCore.Tools,還要增加對IdentityEF的專案參照,然後增加DbContextFactory:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using TestIdentityEF.Data;

namespace IdentityEF.Sqlite
{
    public class DbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
            optionsBuilder.UseSqlite("DataSource=mydatabase.db;",
                x => x.MigrationsAssembly("IdentityEF.Sqlite"));

            return new ApplicationDbContext(optionsBuilder.Options);
        }
    }
}

還增加依賴注入擴充套件:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestIdentity.Data;

namespace IdentityEF.Sqlite
{
    public static class IdentityEFExtension
    {
        public static IServiceCollection AddIdentityEFSqlite(this IServiceCollection services, IConfiguration Configuration)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlite(Configuration.GetConnectionString("IdentityConnection"),
                x => x.MigrationsAssembly("IdentityEF.Sqlite")));
            return services;
        }
    }
}

專案的結構如下:

現在,我們需要生成遷移檔案和資料庫。將專案IdentityEF.Sqlite設定為啟動專案,在程式包管理器中,將IdentityEF.Sqlite設定為預設專案:

在程式包管理器中執行:

Add-Migration init

如果一切順利,在專案檔案中會增加遷移檔案:

然後執行Update-Database,我們會發現,專案中多了db檔案:

最後,改造一下Web應用,使其支援Sqlite資料庫,並且可以通過組態檔進行切換。在專案中增加對IdentityEF.Sqlite的參照,然後修改Program.cs:

if (builder.Configuration["DbType"]=="SqlServer")
    builder.Services.AddIdentityEFSqlServer(builder.Configuration);
else
    builder.Services.AddIdentityEFSqlite(builder.Configuration);

在組態檔中使用DbType切換資料庫的型別:

{
  "ConnectionStrings": {
    //"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-TestIdentity-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true",
    "DefaultConnection": "DataSource=D:\\Asp.Net Core\\TestIdentityEF\\IdentityEF.Sqlite\\mydatabase.db"
  },
  "DbType": "Sqlite",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

完整的專案程式碼可以從github下載:https://github.com/zhenl/TestIdentityEF