尝试在 .net 核心代码中迁移表

Trying to migrate tables in code for .net core

我正在使用 Aspnet.Identity 设置 IdentityServer4。 我遵循了一个教程,该教程展示了如何在代码中创建数据库和种子。我有一个看起来像这样的方法:

public static void SeedIdentityServerDatabase(this IApplicationBuilder app)
{
    using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        var serviceProvider = scope.ServiceProvider;
        var persistedGrantDbContext = serviceProvider.GetRequiredService<PersistedGrantDbContext>();
        var configurationDbContext = serviceProvider.GetRequiredService<ConfigurationDbContext>();

        persistedGrantDbContext.Database.Migrate();
        configurationDbContext.Database.Migrate();

        CreateIdentityResources(configurationDbContext);
        CreateApiResources(configurationDbContext);
        CreateClients(configurationDbContext);
    }
}

这没有问题,并创建了我的数据库以及 IdentityServer4.

所需的表/数据

我现在 reading the IdentityServer documentation 使用 AspNet.Identity 来实现,但它显示 MVC 而不是 Api 并且我想继续这样做。

所以我将 DbContext 更新为这个

public class DatabaseContext : IdentityDbContext<User>
{
    // ReSharper disable once SuggestBaseTypeForParameter
    public DatabaseContext(DbContextOptions<DatabaseContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }
}

还有我的用户class:

public class User : IdentityUser
{
}

我的创业公司现在有这个:

services.Configure<Config>(Configuration.GetSection("ConnectionStrings"));

var buildServiceProvider = services.BuildServiceProvider();
var config = buildServiceProvider.GetService<IOptions<Config>>();

services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(config.Value.ConnectionString));
services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<DatabaseContext>()
    .AddDefaultTokenProviders();

我尝试将我的种子方法更新为:

public static void SeedIdentityServerDatabase(this IApplicationBuilder app)
{
    using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        var serviceProvider = scope.ServiceProvider;
        var persistedGrantDbContext = serviceProvider.GetRequiredService<PersistedGrantDbContext>();
        var configurationDbContext = serviceProvider.GetRequiredService<ConfigurationDbContext>();
        var databaseContext = serviceProvider.GetRequiredService<DatabaseContext>();

        persistedGrantDbContext.Database.Migrate();
        configurationDbContext.Database.Migrate();
        databaseContext.Database.Migrate();

        CreateIdentityResources(configurationDbContext);
        CreateApiResources(configurationDbContext);
        CreateClients(configurationDbContext);
        CreateUsers(serviceProvider);
    }
}

private static void CreateUsers(IServiceProvider provider)
{
    const string email = "test.test@test.com";
    var userManager = provider.GetRequiredService<UserManager<User>>();
    var administrator = userManager.FindByEmailAsync(email).Result;

    if (administrator != null) return;

    administrator = new User {UserName = email, Email = email, EmailConfirmed = true};
    var result = userManager.CreateAsync(administrator, "password").Result;

    if (!result.Succeeded)
        throw new Exception(result.Errors.First().Description);

    result = userManager.AddClaimsAsync(administrator, new[]
    {
        new Claim(JwtClaimTypes.Name, "Test Test"),
        new Claim(JwtClaimTypes.GivenName, "Test"),
        new Claim(JwtClaimTypes.FamilyName, "Test"),
        new Claim(JwtClaimTypes.Email, email),
        new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean)
    }).Result;

    if (!result.Succeeded)
        throw new Exception(result.Errors.First().Description);
}

当它到达 CreateUsers 方法时,它失败说明:

SqlException: Invalid object name 'AspNetUsers'.

这是它创建的表:

有人知道我做错了什么吗?

如果没有看到您的 CreateUsers 方法的代码很难说,但默认情况下许多 UserManager/SignInManager 方法似乎寻找 AspNetUsers默认情况下 table(除非您指定不同的 table 名称)。要继续使用默认值,您可以将其添加到 DatabaseContext class:

OnModelCreating 方法中
builder.Entity<User>(b => b.ToTable("AspNetUsers"));

否则,您的 Migrate 命令可能会创建 "Users" table 而 UserManager/SignInManager 不会知道。如果你想让 table 被称为 "Users" 没关系,只需将上面的更改为:

builder.Entity<User>(b => b.ToTable("Users"));

这样,UserManager/SignInManager 就会知道 table 用于 User 实体。

参考:Identity model customization in ASP.NET Core

我对解决方案不满意....但我所做的只是按照正常的做事方式。所以首先,按照我认为合适的方式映射任何 AspNetIdentity 表:

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    // Customize the ASP.NET Identity model and override the defaults if needed.
    // For example, you can rename the ASP.NET Identity table names and more.
    // Add your customizations after calling base.OnModelCreating(builder);

    builder.Entity<User>(m => m.ToTable("Users"));
    builder.Entity<IdentityRole>(m => m.ToTable("Roles"));
    builder.Entity<IdentityRoleClaim<string>>(m => m.ToTable("RoleClaims"));
    builder.Entity<IdentityUserClaim<string>>(m => m.ToTable("UserClaims"));
    builder.Entity<IdentityUserLogin<string>>(m => m.ToTable("UserLogins"));
    builder.Entity<IdentityUserRole<string>>(m => m.ToTable("UserRoles"));
    builder.Entity<IdentityUserToken<string>>(m => m.ToTable("UserTokens"));
}

然后调用 add-migration:

add-migration Init -Context DatabaseContext

其次是update-database

update-database -Context DatabaseContext

因为 commands in the documentation set up 2 DbContexts,我现在有多个,这就是为什么我必须在 add-migrationupdate-database 中指定上下文。

一旦我 运行 这两个命令,我就将我的种子方法更改为:

public static void SeedIdentityServerDatabase(this IApplicationBuilder app)
{
    using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        var serviceProvider = scope.ServiceProvider;
        var persistedGrantDbContext = serviceProvider.GetRequiredService<PersistedGrantDbContext>();
        var configurationDbContext = serviceProvider.GetRequiredService<ConfigurationDbContext>();

        persistedGrantDbContext.Database.Migrate();
        configurationDbContext.Database.Migrate();

        CreateIdentityResources(configurationDbContext);
        CreateApiResources(configurationDbContext);
        CreateClients(configurationDbContext);
        CreateUsers(serviceProvider);
    }
}

如您所见,我删除了 databaseContext.Database.Migrate(); 调用,因为它不再需要了。

CreateUsers 方法现在可以正确运行和播种。