2014-02-07 5 views
5

Ich versuche, ein "Admin" -Konto im Identity-Framework beim Start der Anwendung zu erstellen. Der Großteil unserer Anwendung wird nicht über Code-First-Entity-Framework-Modelle eingerichtet. Daher muss ich dies tun, ohne eine der IDatabaseInitializer-Klassen zu erweitern. Ich verwende die gleiche Datenbank wie diese ersten Datenbankmodelle.Identity Framework Seed-Methode speichert neu erstellten Benutzer nicht, wenn von Global.asax.cs aufgerufen

Dies ist eine ASP.NET MVC 5-Anwendung.

In Global.asax.cs habe ich den folgenden relevanten Code.

using (var context = new IdentityContext(EnvironmentSettings.Current.DatabaseConnections.CreateDbConnection("Extranet").ConnectionString)) 
{ 
    context.SeedAdminAccount(EnvironmentSettings.DefaultAdminAccount.UserName, EnvironmentSettings.DefaultAdminAccount.Password).Wait(); 
} 

Die Verbindungszeichenfolge ist ein Azure SQL-Server. Der Benutzername ist eine E-Mail-Adresse und das Passwort ist eine Zeichenfolge, einschließlich eines Knalls.

Die Klasse IdentityContext sieht so aus.

public class IdentityContext : IdentityDbContext<IdentityUser> 
{ 
    public IdentityContext(string connectionString) : base(connectionString) 
    { 
     Debug.WriteLine(connectionString); 
     Initialize(); 
    } 

    void Initialize() 
    { 
     Database.Log = s => System.Diagnostics.Debug.WriteLine(s); 
     Database.SetInitializer<IdentityContext>(new CreateInitializer()); 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

     modelBuilder.Entity<IdentityUser>().ToTable("IdentityUser", "dbo"); 
     modelBuilder.Entity<IdentityRole>().ToTable("IdentityRole", "dbo"); 
     modelBuilder.Entity<IdentityUserClaim>().ToTable("IdentityUserClaim", "dbo"); 
     modelBuilder.Entity<IdentityUserLogin>().ToTable("IdentityUserLogin", "dbo"); 
     modelBuilder.Entity<IdentityUserRole>().ToTable("IdentityUserRole", "dbo"); 
    } 
} 

context.SeedAdminAccount() ist eine Erweiterung von IdentityContext. Es sieht aus wie das.

public static class IdentityContextExtensions 
{ 
    public static async Task SeedAdminAccount(this IdentityContext identityContext, string username, string password) 
    { 
     var userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(identityContext)); 

     //var user = await userManager.FindAsync(EnvironmentSettings.DefaultAdminAccount.UserName, EnvironmentSettings.DefaultAdminAccount.Password); 
     var user = await userManager.FindAsync(username, password); 

     if (user != null) return; 

     user = new IdentityUser() { UserName = username }; 

     var role = new IdentityUserRole { Role = new IdentityRole(Role.Admin) }; 
     user.Roles.Add(role); 

     await userManager.CreateAsync(user, password); 

     identityContext.SaveChanges(); 
    } 
} 

Und schließlich sieht CreateInitializer wie folgt aus (obwohl es nicht genannt wird).

public class CreateInitializer : CreateDatabaseIfNotExists<IdentityContext> 
{ 
    protected override async void Seed(IdentityContext context) 
    { 
     var user = new 
     { 
      EnvironmentSettings.DefaultAdminAccount.UserName, 
      EnvironmentSettings.DefaultAdminAccount.Password 
     }; 

     await context.SeedAdminAccount(user.UserName, user.Password); 

     base.Seed(context); 
    } 
} 

Okay, also mit all das aus dem Weg, hier ist, was funktioniert:

1) Der Anwendungsstart erfolgreich eine Instanz von IdentityContext schafft.

2) Identity Framework erstellt die korrekten Tabellen mit den geänderten Tabellennamen.

3) SeedAdminAccount() wird mit den richtigen Parametern aufgerufen.

4) userManager.FindAsync() findet den Benutzer nicht (weil es nicht existiert).

5) SeedAdminAccount() weiterhin in seinem Körper auf jede Anweisung aus und gibt erfolgreich.

Hier ist, wo ich bin stecken:

1) Obwohl es, dass meine Samen scheint Methode richtig funktioniert, werden keine Zeilen in die IdentityUser Tabelle gespeichert oder andere Rahmen Identität Tabellen.

2) Wenn ich den gleichen Code von einer Steueraktion zu verwenden, wird ein Benutzer erstellt und in der Tabelle erfolgreich IdentityUser gespeichert. hier

Was bin ich? Verwende ich beim Start der Anwendung den falschen Kontext? Gibt es eine Ausnahme, die ich nicht sehen kann?

+0

Versuchen Öffnung SQL Profiler und beobachten, welche Abfrage an die Datenbank während 'identityContext.SaveChanges() gesendet wird;' – danludwig

+0

Oh cool, habe ich nicht, dass es eine SQL Profiler war. Ich werde das überprüfen. Ich habe herausgefunden, was mein Problem war, trotz der Stunden, in denen ich mich umsehen musste. Ich werde bald meine Antwort posten. – aholmes

Antwort

8

zu einem vollständigen Verlust zu sein, habe ich beschlossen, den Rückgabewert von userManager.CreateAsync() zu überprüfen. Ich bemerkte, dass das Fehlerfeld nicht leer war, mit dem Fehler "Der angegebene Name enthält ungültige Zeichen".

Es stellte sich heraus, ich habe vergessen UserValidator zu überlasten meine EmailUserValidator Klasse im SeedAdminAccount() Methode zu verwenden.

Ich änderte auch, wie ich Rollen speichern. So sieht meine Samenmethode jetzt aus.

public static void SeedAdminAccount(this IdentityContext identityContext, string username, string password) 
{ 
    var userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(identityContext)); 
    userManager.UserValidator = new EmailUserValidator<IdentityUser>(userManager); 

    var user = userManager.Find(username, password); 

    if (user != null) return; 

    SeedUserRoles(identityContext); 

    user = new IdentityUser() { UserName = username }; 

    var result = userManager.Create(user, password); 

    if (result.Succeeded) 
    { 
     userManager.AddToRole(user.Id, Role.Administrator); 
    } 
    else 
    { 
     var e = new Exception("Could not add default account."); 

     var enumerator = result.Errors.GetEnumerator(); 
     foreach(var error in result.Errors) 
     { 
      e.Data.Add(enumerator.Current, error); 
     } 

     throw e; 
    } 
} 

public static void SeedUserRoles(this IdentityContext identityContext) 
{ 
    var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(identityContext)); 

    foreach(var role in Role.Roles) 
    { 
     var roleExists = roleManager.RoleExists(role); 

     if (roleExists) continue; 

     roleManager.Create(new IdentityRole(role)); 
    } 
} 
+0

Ich habe auch viel Zeit damit verbracht, herauszufinden, warum der Benutzer nicht erstellt wurde :) Anstatt nur den Rückgabewert zu überprüfen. Vielleicht wäre es in diesem Fall besser gewesen, eine Ausnahme zu werfen. –

+0

Danke, hat mir geholfen, mein Problem zu lösen: Ich habe versucht, einen Benutzer mit einem Passwort hinzuzufügen, das die Passwortanforderungen nicht erfüllt, so dass der Benutzer überhaupt nicht ohne vorherige Ankündigung erstellt wurde. – peter