当我有两个 DbContext a) IdentityDbContext & b) AppDbContext 时如何播种用户、角色

How to seed users, roles when I have TWO DbContext, a) IdentityDbContext & b) AppDbContext

通常我会将播种用户的代码放在 OnModelCreating() one DbContext 中不是问题。

最近建议将identity's DbContextApp's DbContext分开,这增加了两个 DbContext 和一些混乱。

  1. public UseManagementDbContext(DbContextOptions<UseManagementDbContext> options) : base(options) // security/users 分离
  2. public AppDbContext(DbContextOptions<MyDbContext> options) : base(options)

But when you have two separate DbContexts, How do I seed the user / role data?

  1. IdentityDbContext -- 这具有播种的所有 <IdentityUser> 上下文

  2. AppDbContext -- 这没有 <IdentityUser> 上下文,但我的迁移使用此上下文。


能否请您帮助如何播种用户和角色数据,并且是迁移或启动等的一部分


更新:使用核心6样本,@Zhi Lv - 我如何改造program.cs my seedData when the app is fired up

我的 Program.cs 最初是从 ASP Core 3.1 模板创建的,它看起来像这样,我应该重构什么,(奇怪的是 link at MS, there are no class name brackets ,那么我的种子从哪里设置和调用?

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

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

要播种用户和角色数据,您可以创建静态 class,如下所示:

//required
//using Microsoft.AspNetCore.Identity;
//using Microsoft.EntityFrameworkCore;
public static class SeedRoles
{
    public static void Initialize(IServiceProvider serviceProvider)
    {
        using (var context = new ApplicationDbContext(serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
        {
            string[] roles = new string[] { "Owner", "Administrator", "Tests2", "Editor", "Buyer", "Business", "Seller", "Subscriber" };

            var newrolelist = new List<IdentityRole>();
            foreach (string role in roles)
            {  
                if (!context.Roles.Any(r => r.Name == role))
                {
                    newrolelist.Add(new IdentityRole(role));
                }
            }
            context.Roles.AddRange(newrolelist);
            context.SaveChanges();
        }
    }
}

注意: 在我的应用程序中,我使用Asp.net 6,数据库上下文是ApplicationDbContext,你可以将其更改为你的。

然后,在program.cs文件中,可以在var app = builder.Build();行之后调用种子角色方法,代码如下:

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

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()    //enable Identity Role
    .AddEntityFrameworkStores<ApplicationDbContext>() ;
builder.Services.AddControllersWithViews();

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    SeedRoles.Initialize(services);
}

结果如下,运行申请后,会播种数据:

由于您使用了两个 DBcontext,您还可以创建多个静态方法来播种数据。

更多详细信息,您可以查看official document and sample

更新:

要播种用户,可以使用UserManager在seed方法中创建用户,代码如下:

public static class SeedUsers
{
    public static async Task InitializeAsync(IServiceProvider serviceProvider)
    {
        using (UserManager<IdentityUser> _userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>())
        {

            var userlist = new List<SeedUserModel>()
            {
                new SeedUserModel(){ UserName="John@hotmail.com",Password= "Abc12345!" },
                new SeedUserModel(){UserName ="David@hotmial.com", Password="Abc12345!"}
            };

             
            foreach (var user in userlist)
            {
                if (!_userManager.Users.Any(r => r.UserName == user.UserName))
                {
                    var newuser = new IdentityUser { UserName = user.UserName, Email = user.UserName };
                    var result = await _userManager.CreateAsync(newuser, user.Password);
                }
            }
     
        }
    }
}

截图是这样的:

[注意] 从截图中我们可以看到,EmailConfirmed 列默认为False。如果启用了Email Confirm操作,需要将值修改为True,才能登录成功。

更新二:

对于以前的版本:例如Asp.net 5或Asp.net core 3.1,您可以在Program.cs中添加种子初始化器,代码如下:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            try
            {
                SeedData.Initialize(services);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred seeding the DB.");
            }
        }

        host.Run();

    }

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

参考:Add the seed initializer.