2014-07-18 95 views
10

我有一個ASP.NET MVC 5項目(剃鬚刀引擎),它具有身份2.0個人用戶帳戶。我正在使用Visual Studio Professional 2013種子標識2.0數據庫

我還沒有找到任何明確的示例(爲什麼它不是開箱即用?)如何爲Identity 2.0數據庫創建種子,並且我看到的所有示例都有一半支持,因爲它們不要說在哪裏你必須實現這一點。

我使用了使用Configuration.cs文件創建Migrations文件夾的enable-migrations。它有一個Seed方法覆蓋,但是當我放置一個斷點時,它會注意到它永遠不會被執行,事實上,Identity數據庫甚至不會被模式填充。

因此,我必須做什麼以便第一次在數據庫上創建Identity 2.0模式(連接字符串正確且存在空數據庫)。我如何裝配播種?

在IdentityModels.cs我有這樣的: 公共類ApplicationDbContext:IdentityDbContext { ublic ApplicationDbContext():基地( 「DefaultConnection」,throwIfV1Schema:假) {}

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"); 
    } 
}  

在遷移/配置。 CS(由PM添加>啓用的遷移),我有這樣的:在我加入這個的Application_Start()方法

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

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

在我的Global.asax.cs文件:

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

而在IdentityConfig.cs我有這個DB初始化程序以及雖然它似乎是孤兒,因爲我不知道在哪裏插上這樣的:

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; 

回答

14

EF有two different Seed methods。一個用於數據庫初始化程序,另一個用於遷移。由於您已啓用遷移,因此我將在此處描述如何使用遷移種子方法執行此操作...

首先,即使已啓用遷移,默認情況下EF仍使用CreateDatabaseIfNotExists數據庫初始值設定項。這意味着當你運行你的應用程序時,第一次訪問ApplicationDbContext時,初始化程序會被調用,如果這些表已經不存在,它將從Code First映射中創建數據庫表。您沒有看到創建的模式,因爲您可能沒有訪問數據庫上下文。在新的Web應用程序中,這通常會在您第一次註冊用戶或嘗試登錄時觸發。

要種子ASP.NET身份表,您需要執行兩項操作。首先是在Configuration.cs中將種子邏輯添加到Seed方法。第二種方法是觸發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 = "[email protected]", 
      UserName = "SuperUser" 
     }; 
     userManager.Create(user, "MySecretPassword1234"); 
     userManager.AddToRole(user.Id, "Administrator"); 
    } 
} 

完成上述操作後,就可以從包管理器控制檯運行Update-Database將數據庫遷移到最新的架構和運行種子法。

或者你也可以改變EF通過修改IdentityModels.cs上下文中使用MigrateDatabaseToLatestVersion初始化...

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

現在,當你運行應用程序,第一時間數據庫上下文中使用它會運行update-database並種下它。

+0

不知怎的,既不是DB初始化的越來越調用。核心Identity 2.0數據庫模式在應用程序運行時也未被創建。 –

+0

當您嘗試註冊帳戶時會發生什麼? –

+0

那麼,我真正想要的是沒有遷移的「原始」種子,但是因爲我有遷移這樣做。我做了添加遷移初始化,但是當我通過更新數據庫關注它時,出現了一些錯誤,例如「EntityType'IdentityUserRole'沒有定義密鑰。」 –

3

我想我可以解決謎題,爲什麼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 = "[email protected]", UserName = "[email protected]" } // ); // Another approach var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(ctx)); var user = new ApplicationUser() { UserName = "[email protected]", Email="[email protected]"}; var password = "[email protected]"; 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. 運行!

如果您還需要禁用遷移的代碼示例,請告訴我。

+0

我決定擺脫Migrations,因爲它不適用於應用程序無權創建/刪除數據庫的共享虛擬主機。所以,我試圖用非遷移方法來做種子。 –

+0

好的!你還需要一個可用的代碼示例嗎? –

+0

嗨Corneliu,如果你不介意我想看到一個例子,使這個與遷移禁用; o) –

2

所以,我們做我們的樣品包裝以下面的方式類似(種子與我們的管理員用戶DB)

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); 
    } 

} 
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; 
    } 

} 順便說一句,科爾內留感謝您的代碼示例,他們幫了我很多。