尝试在 .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
实体。
我对解决方案不满意....但我所做的只是按照正常的做事方式。所以首先,按照我认为合适的方式映射任何 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-migration
和 update-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
方法现在可以正确运行和播种。
我正在使用 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
实体。
我对解决方案不满意....但我所做的只是按照正常的做事方式。所以首先,按照我认为合适的方式映射任何 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-migration
和 update-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
方法现在可以正确运行和播种。