播种Identity 2.0数据库

时间:2014-07-18 17:06:14

标签: asp.net-identity asp.net-identity-2

我有一个ASP.NET MVC 5项目(razor引擎),它具有带有个人用户帐户的Identity 2.0。我正在使用Visual Studio Professional 2013

我没有找到任何明确的例子(为什么它没有开箱即用?)我如何为Identity 2.0数据库播种,我看到的所有例子都有一半支持,因为他们不会说你必须在哪里实现它。

我使用了enable-migrations,它创建了一个带有Configuration.cs文件的Migrations文件夹。它有一个Seed方法覆盖,但是当我放置一个断点时,它注意到它永远不会被执行,实际上Identity数据库甚至没有用模式填充。

那么我必须做什么,以及第一次在数据库上创建Identity 2.0模式(连接字符串是否正确并且存在空数据库)。我如何装配种子?

在IdentityModels.cs上我有这个:     public class ApplicationDbContext:IdentityDbContext {         ublic ApplicationDbContext():base(" DefaultConnection",throwIfV1Schema:false)         {}

    public static ApplicationDbContext Create() {
         return new ApplicationDbContext();
    }

    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder) {
          base.OnModelCreating(modelBuilder);
          // to avoid the "has no keys" errors when running Update-Database on PM
          modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id).ToTable("AspNetRoles");
          modelBuilder.Entity<IdentityUser>().ToTable("AspNetUsers");
          modelBuilder.Entity<IdentityUserLogin>().HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey }).ToTable("AspNetUserLogins");
          modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId }).ToTable("AspNetUserRoles");
          modelBuilder.Entity<IdentityUserClaim>().ToTable("AspNetUserClaims");
     }
}    

在Migrations / Configuration.cs中(由PM&gt; Enable-Migrations添加)我有:

internal sealed class Configuration : DbMigrationsConfiguration<Models.ApplicationDbContext> {
    public Configuration() {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(Models.ApplicationDbContext context) {
         WriteReferenceData();
    }
}

在Application_Start()方法的Global.asax.cs文件中,我添加了这个:

System.Data.Entity.Database.SetInitializer<Models.ApplicationDbContext>(new System.Data.Entity.MigrateDatabaseToLatestVersion<Models.ApplicationDbContext, Migrations.Configuration>());

在IdentityConfig.cs中我也有这个DB Initializer,虽然它似乎是孤儿,因为我不知道在哪里插入它:

public class ApplicationDbInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<Models.ApplicationDbContext> {
    protected override void Seed(ApplicationDbContext context) {
        WriteReferenceData();
        base.Seed(context);
    }
}

最后,WriteReferenceData方法在其他类中或多或少地执行此操作:

System.Data.Entity.DbContextTransaction transaction = null;
try {
    System.Data.Entity.DbContext ctx = Models.ApplicationDbContext.Create();
    transaction = ctx.Database.BeginTransaction();
    CreateRoles(ctx);
    CreateUsers(ctx);
    CreateRoleAssociations(ctx);
    ctx.SaveChanges();
    transaction.Commit();
    succeeded = true;
}
catch (Exception ex) {
    if (transaction != null { transaction.Rollback(); transaction.Dispose(); }
    succeeed = false;
}
return succeeded;

5 个答案:

答案 0 :(得分:15)

EF有two different Seed methods。一个用于数据库初始化程序,另一个用于迁移。由于您已启用迁移,我将在此处描述如何使用迁移种子方法...

首先,即使您启用了迁移,默认情况下EF仍然使用CreateDatabaseIfNotExists数据库初始化程序。这意味着当您运行应用程序时,第一次访问ApplicationDbContext时,将调用初始化程序,如果表已经不存在,它将从Code First映射创建数据库表。您没有看到创建的模式,因为您可能没有访问过数据库上下文。在新的Web应用程序中,通常在您第一次注册用户或尝试登录时触发。

要为ASP.NET标识表提供种子,您需要做两件事。第一种是将种子逻辑添加到Configuration.cs中的种子方法中。第二种是通过在程序包管理器控制台中运行它或使用update-database数据库初始化程序来触发MigrateDatabaseToLatestVersion ...

以下是您可以在Seed方法中创建角色和用户的示例...

public Configuration()
{
    AutomaticMigrationsEnabled = true;

    // ...
}

protected override void Seed(MyProject.Web.Models.ApplicationDbContext context)
{
    if (!context.Roles.Any())
    {
        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);
        var role = new IdentityRole{
            Name = "Administrator"
        };
        roleManager.Create(role);
    }

    if (!context.Users.Any())
    {
        var userStore = new UserStore<ApplicationUser>(context);
        var userManager = new ApplicationUserManager(userStore);

        var user = new ApplicationUser {
            Email = "foo@bar.com",
            UserName = "SuperUser"
        };
        userManager.Create(user, "MySecretPassword1234");
        userManager.AddToRole(user.Id, "Administrator");
    }
}

完成此操作后,您可以从程序包管理器控制台运行Update-Database以将数据库迁移到最新架构并运行Seed方法。

或者您可以通过修改MigrateDatabaseToLatestVersion中的上下文来更改EF以使用IdentityModels.cs初始化程序...

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
        Database.SetInitializer<ApplicationDbContext>(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());
    }
}

现在,当您运行应用程序时,第一次使用数据库上下文时,它将运行update-database并播种它。

答案 1 :(得分:3)

我认为我可以解决为什么从不触发Seed的问题:因为仅在应用程序尝试连接数据库时调用Seed,而不是在应用程序启动时调用。

我创建了一些示例,我已成功使用您的代码,无论是否迁移。但是,由于您希望在启用迁移时使用它,下面是示例代码。

非常重要:要在Seed中实际查看断点,请运行应用程序,按Login并使用种子功能中的凭据来访问应用程序。如果您收到“用户名或密码无效”,请注意manager.PasswordValidator

中的IdentityConfig.cs :: Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context).媒体资源
  1. 在VS2013中创建一个新的ASP.NET MVC 5项目

  2. 使用Update-Package命令更新所有软件包。

  3. 启用-迁移

  4. 在迁移创建的Configuration.cs中添加以下代码:

    internal sealed class Configuration : DbMigrationsConfiguration
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }

    protected override void Seed(ApplicationDbContext context) { bool itWorks = WriteReferenceData(context); base.Seed(context); } private bool WriteReferenceData(ApplicationDbContext ctx) { DbContextTransaction transaction = null; bool succeeded = false; try { transaction = ctx.Database.BeginTransaction(); CreateRoles(ctx); CreateUsers(ctx); ctx.SaveChanges(); transaction.Commit(); succeeded = true; } catch (Exception ex) { if (transaction != null) { transaction.Rollback(); transaction.Dispose(); } succeeded = false; } return succeeded; } private void CreateRoles(ApplicationDbContext ctx) { // Out of the box // ctx.Roles.AddOrUpdate( // new IdentityRole { Name = "Administrator" }, // new IdentityRole { Name = "Guest" } // ); // Another approach var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(ctx)); var roleName = "Administrator"; //Create role if it does not exist if (!RoleManager.RoleExists(roleName)) { var roleresult = RoleManager.Create(new IdentityRole(roleName)); } } private void CreateUsers(ApplicationDbContext ctx) { // Out of the box approach // ctx.Users.AddOrUpdate( // new ApplicationUser { Email = "foo@xyz.com", UserName = "foo@xyz.com" } // ); // Another approach var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(ctx)); var user = new ApplicationUser() { UserName = "foo@xyz.com", Email="foo@xyz.com"}; var password = "Wh@tever777"; var adminresult = UserManager.Create(user, password); //Add User Admin to Role Administrator if (adminresult.Succeeded) { var result = UserManager.AddToRole(user.Id, "Administrator"); } } }
  5. 在Global.asax.cs :: Application_Start()中,添加以下行:

    Database.SetInitializer<ApplicationDbContext>(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());

  6. 运行!

  7. 如果您还需要禁用迁移的代码示例,请与我们联系。

答案 2 :(得分:2)

所以我们通过以下方式在我们的示例包中做类似的事情(使用我们的管理员用户播种数据库)

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    static ApplicationDbContext()
    {
        // Set the database intializer which is run once during application start
        // This seeds the database with admin user credentials and admin role
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

// This is useful if you do not want to tear down the database each time you run the application.
// public class ApplicationDbInitializer : DropCreateDatabaseAlways<ApplicationDbContext>
// This example shows you how to create a new database if the Model changes
public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
    protected override void Seed(ApplicationDbContext context) {
        DoYourSeedingHere(context);
        base.Seed(context);
    }

}

答案 3 :(得分:1)

要完成此问题..正如Corneliu Serediuc所说,您只需尝试在应用程序启动期间连接到数据库,例如,像这样(IdentityModel.cs):

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }


    public static ApplicationDbContext Create()
    {
        var ctx = new ApplicationDbContext();
        var runSeed = ctx.Roles.AnyAsync();

        return ctx;
    }

} 顺便说一句,Corneliu感谢你的代码示例,他们帮了我很多。

答案 4 :(得分:0)

如果您想使用CSV批量插入新帐户,可以使用此项目:https://github.com/Stonefinch/AspNetUserMaintenanceAzureSiteExtension

它也可以作为Azure站点扩展安装:https://www.siteextensions.net/packages/AspNetUserMaintenanceAzureSiteExtension/