I'm using IdentityDbContext
and I have a SeedData
class that I'm using inside the OnModelCreating
method to seed the database using the initial migrations as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//
//
SeedData seedData = new(_userManager);
seedData.SeedWebsiteAdmins(modelBuilder.Entity<WebsiteAdmin>());
seedData.SeedCompanyAdmins(modelBuilder.Entity<CompanyAdmin>());
//
//
}
This SeedData
class requires a parameter of type UserManager
inside its constructor because it needs to create the new users as follows:
public async void SeedWebsiteAdmins(EntityTypeBuilder<WebsiteAdmin> entity)
{
var superAdminLogin = new ApplicationUser()
{
Name = "Name",
Email = "Email",
UserType = UserType.WebsiteAdmin
};
var result = await _userManager.CreateAsync(superAdminLogin, "{password}");
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(superAdminLogin, RoleNames.WebsiteAdminRole);
}
var superAdmin = new WebsiteAdmin()
{
Id = SuperAdminId,
WebsiteAdminLoginId = superAdminLogin.Id,
MaxServiceDiscount = 100,
};
entity.HasData(superAdmin);
}
I've tried injecting the UserManager
inside the DbContext
constructor, but it's causing the following error:
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContext' while attempting to activate 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserOnlyStore`3[RepositoryProject.DomainAuth.ApplicationUser,Microsoft.EntityFrameworkCore.DbContext,System.Guid]'
How can I inject the UserManager
in the DbContext
constructor without causing any error?
Or is there a way to create the identity user without using the UserManager
so I can delete the dependency from the SeedData
class and hence I wouldn't need it inside the DbContext
?
Try this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var userManager = this.GetService<UserManager>();
...
One thing though, I would do this on your IdentityDbContext implementation using HasData as suggested in one of the comments above NOT in the DbContext OnModelCreating ie.
public MyIdentityDbContext : IdentityDbContext<ApplicationUser, IdentityRole, string> {
public MyIdentityDbContext(DbContextOptions<MyIdentityDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
SetupData(builder);
}
private void SetupData(ModelBuilder builder)
{
// Users
var defaultUsers = new List<ApplicationUser>() {
new ApplicationUser()
{
Id = "USER_HASH"
Name = "name",
Email = "[email protected]",
NormalizedEmail = "[email protected]",
UserName = "username",
NormalizedUserName = "NormalizedUserName",
UserType = UserType.WebsiteAdmin,
// Use your known hash here (the hash below is for Password123!)
PasswordHash = "PasswordHash",
// Use your hash here
SecurityStamp = "SecurityStamp",
AccessFailedCount = 0,
EmailConfirmed = true,
PhoneNumberConfirmed = true,
TwoFactorEnabled = false
}
};
builder.Entity<ApplicationUser>().HasData(defaultUsers);
// Roles
var defaultRoles = new List<IdentityRole>(){
new IdentityRole { Id = "ROLE_HASH", Name =
RoleNames.WebsiteAdminRole, NormalizedName =
RoleNames.WebsiteAdminRole.ToUpper() }
};
builder.Entity<IdentityRole>().HasData(defaultRoles);
// User roles
var defaultUserRoles = new List<IdentityUserRole<string>>(){
new IdentityUserRole<string>(){
Id = "USER_HASH",
RoleId = "ROLE_HASH"
}
};
builder.Entity<IdentityUserRole<string>>().HasData(defaultUsersRoles);
}
}
Note: The hash I have for the password above is with API set to use IdentityV3 ie.
builder.Services.Configure<PasswordHasherOptions>(options => options.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV3);
You can create your own password hash using
var passwordHasher = this.GetService<IPasswordHasher<IdentityUser>>();
var passwordHash = passwordHasher.HashPassword(user, "YourPassword");