从Global.asax.cs调用时,Identity Framework种子方法不保存新创建的用户

时间:2014-02-07 22:55:37

标签: c# asp.net-mvc asp.net-identity

我正在尝试在应用程序启动期间在Identity框架中播种“admin”帐户。我们的大部分应用程序都没有通过代码优先的Entity框架模型进行设置,因此我需要在不扩展其中一个IDatabaseInitializer类的情况下执行此操作。我使用与这些数据库优先模型相同的数据库。

这是一个ASP.NET MVC 5应用程序。

Global.asax.cs中,我有以下相关代码。

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

连接字符串是Azure SQL服务器。用户名是电子邮件地址,密码是一串字符,包括爆炸。

IdentityContext类看起来像这样。

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()IdentityContext的扩展。它看起来像这样。

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

最后,CreateInitializer看起来像这样(虽然它没有被调用)。

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

好的,所有这一切都在这里,这是有效的:

1)应用程序启动成功创建了IdentityContext

的实例

2)Identity框架使用修改后的表名创建正确的表。

3)使用正确的参数调用SeedAdminAccount()

4)userManager.FindAsync()找不到用户(因为它不存在)。

5)SeedAdminAccount()继续其身体中的每个语句并成功返回。

这就是我被困的地方:

1)虽然看起来我的种子方法工作正常,但没有行保存到IdentityUser表或任何其他Identity框架表。

2)如果我使用控制器操作中的相同代码,则会成功创建用户并将其存储在IdentityUser表中。

我在这里缺少什么?我是否在应用程序启动期间使用了错误的上下文?是否有某种我无法看到的异常?

1 个答案:

答案 0 :(得分:8)

完全失去了,我决定检查userManager.CreateAsync()的返回值。我注意到Errors字段是非空的,错误是“指定的名称包含无效字符”。

事实证明,我忘了重载UserValidator以使用EmailUserValidator方法中的SeedAdminAccount()课程。

我也改变了我存储角色的方式。这就是我的种子方法现在的样子。

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