During seeding data, this error occurs:
These are the steps:
public static async Task SeedUsersAndRolesAsync(IApplicationBuilder applicationBuilder)
{
using (var serviceScope = applicationBuilder.ApplicationServices.CreateScope())
{
var roleManager = serviceScope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
if (!await roleManager.RoleExistsAsync(UserRoles.Admin))
{
await roleManager.CreateAsync(new IdentityRole(UserRoles.Admin));
}
if (!await roleManager.RoleExistsAsync(UserRoles.User))
{
await roleManager.CreateAsync(new IdentityRole(UserRoles.User));
}
var userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var adminUser = await userManager.FindByEmailAsync(AdminInfo.FirstGmail);
if (adminUser is null)
{
var newAdminUser = new ApplicationUser()
{
FullName = AdminInfo.FirstFullName,
UserName = AdminInfo.FirstUsername,
Email = AdminInfo.FirstGmail,
EmailConfirmed = true
};
await userManager.CreateAsync(newAdminUser, AdminInfo.FirstPassword);
await userManager.AddToRoleAsync(newAdminUser, UserRoles.Admin);
}
var simpleUser = await userManager.FindByEmailAsync(AdminInfo.SecondGmail);
if (simpleUser is null)
{
var newSimpleUser = new ApplicationUser()
{
FullName = AdminInfo.SecondFullName,
UserName = AdminInfo.SecondUsername,
Email = AdminInfo.SecondGmail,
EmailConfirmed = true
};
await userManager.CreateAsync(newSimpleUser, AdminInfo.SecondPassword);
await userManager.AddToRoleAsync(newSimpleUser, UserRoles.User);
}
}
}
This is the custom ApplicationUser class:
public class ApplicationUser : IdentityUser
{
[Display(Name = "Full Name")]
public string FullName { get; set; }
}
And the program.cs looks like this:
builder.Services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<AppDbContext>();
builder.Services.AddMemoryCache();
builder.Services.AddSession();
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
And finally used the seeding class in the program.cs:
AppDbInitializer.Seed(app);
AppDbInitializer.SeedUsersAndRolesAsync(app).Wait();
app.Run();
But that error happened when I tried to run the app.
After using break point in "SeedUsersAndRolesAsync" class, I understand the error is happening in this line:
await userManager.AddToRoleAsync(newAdminUser, UserRoles.Admin);
And this is the inner exception:
- InnerException {"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_AspNetUserRoles_AspNetUsers_UserId\". The conflict occurred in database \"MovieTicketDB\", table \"dbo.AspNetUsers\", column 'Id'.\r\nThe statement has been terminated."} System.Exception {Microsoft.Data.SqlClient.SqlException}
Please help me to find my mistake, thanks in advance.
You are trying to add some Users for a Role that still doesn't exist in the database... Try to save changes before adding the Role for the User.
In which module do I do the seeding of the db? I want to add roles and users if they do not exist yet.
In NET Core I would use the startup file in this way:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
using (IServiceScope serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
var roleManager = serviceScope.ServiceProvider.GetService<RoleManager<IdentityRole>>();
var userManager = serviceScope.ServiceProvider.GetService<UserManager<User>>();
DbSeeder.Seed(Configuration, dbContext, roleManager, userManager);
}
}
and in my class DBSeeder:
public static class DbSeeder
{
public static void Seed(IConfiguration configuration,
ApplicationDbContext dbContext,
RoleManager<IdentityRole> roleManager,
UserManager<User> userManager)
{
if (!dbContext.Users.Any()) CreateUsers(configuration, dbContext, roleManager, userManager).GetAwaiter().GetResult();
}
private static async Task CreateUsers(IConfiguration configuration,
ApplicationDbContext dbContext,
RoleManager<IdentityRole> roleManager,
UserManager<User> userManager)
{
string role_Administrator = "Administrator";
string role_RegisteredUser = "RegisteredUser";
if (!await roleManager.RoleExistsAsync(role_Administrator))
{
await roleManager.CreateAsync(new IdentityRole(role_Administrator));
}
if (!await roleManager.RoleExistsAsync(role_RegisteredUser))
{
await roleManager.CreateAsync(new IdentityRole(role_RegisteredUser));
}
var user_Admin = new User()
{
SecurityStamp = Guid.NewGuid().ToString(),
UserName = "Admin",
Email = configuration["ContactUs"],
DisplayName = "Admin",
EmailConfirmed = true
};
if (await userManager.FindByNameAsync(user_Admin.UserName) == null)
{
await userManager.CreateAsync(user_Admin, "Pass4Admin");
await userManager.AddToRoleAsync(user_Admin, role_RegisteredUser);
await userManager.AddToRoleAsync(user_Admin, role_Administrator);
}
await dbContext.SaveChangesAsync();
}
Hey This is probably a newbie question but I honestly can't find the problem after hours of searching for answers.
I am trying to create two roles and an admin user by seeding the database. I get no compilation errors but after running the application I couldn't login so I checked the database and noticed that the roles were created successfully but not the admin user.
Here is the class that I use for seeding:
public class Initialize
{
public static async Task InitializeAsync(ApplicationDbContext context, IServiceProvider serviceProvider)
{
var RoleManager = serviceProvider.GetRequiredService < RoleManager<IdentityRole>>();
UserManager<ApplicationUser> userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
string[] rolenames = { "Admin","Member"};
IdentityResult roleResult;
foreach (var roleName in rolenames) {
var roleExist = await RoleManager.RoleExistsAsync(roleName);
if (!roleExist)
{
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
}
}
string username = "admin";
string email = "admin#example.com";
string password = "Secret123";
string role = "Admin";
if (await userManager.FindByEmailAsync(username) == null)
{
ApplicationUser user = new ApplicationUser
{
UserName = username,
Email = email
};
IdentityResult result = await userManager
.CreateAsync(user, password);
if (result.Succeeded)
{
await userManager.AddToRoleAsync(user, role);
}
}
}
}
My ConfigureServices :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add application services.
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc();
}
And Here is my Program.cs :
public class Program
{
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ApplicationDbContext>();
Initialize.InitializeAsync(context, services).Wait();
}
catch(Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "Error seeding");
}
}
host.Run();
}
Any help is appreciated :)
Try look at userManager -> Store -> Users -> Results Views -> Message after access via serviceProvider.GetRequiredService. You can have some error message about it here.
If it contains a message:
"Cannot create a DbSet for 'ApplicationUser' because this type is not
included in the model for the context."
you must changed ApplicationContext class inherit from IdentityDbContext and it should be works fine.
I am working in a new MVC5 application that I built specifically to test this.
I have two db contexts. The configuration.cs for the ApplicationDbContext is as follows:
using FB.DOMAIN.Authentication;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Data.Entity.Migrations;
namespace FB.DAL.Migrations.ApplicationDbContext
{
internal sealed class Configuration : DbMigrationsConfiguration<DataContexts.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\ApplicationDbContext";
}
protected override void Seed(DataContexts.ApplicationDbContext context)
{
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
if (!roleManager.RoleExists("Admin"))
{
roleManager.Create(new IdentityRole("Admin"));
}
var user = new ApplicationUser { UserName = "james#world.com" };
if (userManager.FindByName("james#world.com") != null) return;
var result = userManager.Create(user, "Password123!");
if (result.Succeeded)
{
userManager.AddToRole(user.Id, "Admin");
}
}
}
}
Shouldn't the above code seed my database with a user? Sadly it doesn't! When I query the AspNetUsers table, it is blank!
What am I doing wrong? :(
I couldn't get two separate contexts talking. So I followed LukeP's solution here.
A single context that houses all my related domain logic.
I have been playing about with the new MVC 5, I have a few models, controller and views setup using code first migrations.
My question is how do I seed users and roles? I currently seed some reference data in my Seed method in Configuration.cs. But it looks to me that the user and roles tables are not created until something first hits the AccountController.
I currently have two connection strings so I can separate my data from my authentication into different databases.
How can I get the user, roles, etc tables populate along with my others? And not when the account controller is hit?
Here is example of usual Seed approach:
protected override void Seed(SecurityModule.DataContexts.IdentityDb context)
{
if (!context.Roles.Any(r => r.Name == "AppAdmin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "AppAdmin" };
manager.Create(role);
}
if (!context.Users.Any(u => u.UserName == "founder"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser {UserName = "founder"};
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "AppAdmin");
}
}
I used package-manager "update-database". DB and all tables were created and seeded with data.
It's a small addition, but to anyone having the "UserId not found." message when trying to seed: (Tom Regan had this question in the comments, and I was stuck on it myself for a while)
This means that the manager.Create(user, "ChangeItAsap!") was not successful.
This might have a different reason, but for me it was because my password was not succeeding its validation.
I had a custom passwordvalidator, which was not being called when seeding the database, so the validation rules i was used to (minlength 4 instead of default 6) did not apply. Make sure your password (and all other fields for that matter) is passing validation.
This is my method base on Valin answer, I have added roles in db and added password for user. This code is placed in Seed() method in Migrations>Configurations.cs.
// role (Const.getRoles() return string[] whit all roles)
var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
for (int i = 0; i < Const.getRoles().Length; i++)
{
if (RoleManager.RoleExists(Const.getRoles()[i]) == false)
{
RoleManager.Create(new IdentityRole(Const.getRoles()[i]));
}
}
// user
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var PasswordHash = new PasswordHasher();
if (!context.Users.Any(u => u.UserName == "admin#admin.net"))
{
var user = new ApplicationUser
{
UserName = "admin#admin.net",
Email = "admin#admin.net",
PasswordHash = PasswordHash.HashPassword("123456")
};
UserManager.Create(user);
UserManager.AddToRole(user.Id, Const.getRoles()[0]);
}
Here i have an very easy,clean and smooth solution.
protected override void Seed(UserContext context)
{
//Step 1 Create the user.
var passwordHasher = new PasswordHasher();
var user = new IdentityUser("Administrator");
user.PasswordHash = passwordHasher.HashPassword("Admin12345");
user.SecurityStamp = Guid.NewGuid().ToString();
//Step 2 Create and add the new Role.
var roleToChoose = new IdentityRole("Admin");
context.Roles.Add(roleToChoose);
//Step 3 Create a role for a user
var role = new IdentityUserRole();
role.RoleId = roleToChoose.Id;
role.UserId = user.Id;
//Step 4 Add the role row and add the user to DB)
user.Roles.Add(role);
context.Users.Add(user);
}
protected override void Seed(ApplicationDbContext context)
{
SeedAsync(context).GetAwaiter().GetResult();
}
private async Task SeedAsync(ApplicationDbContext context)
{
var userManager = new ApplicationUserManager(new UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context));
var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole, int, ApplicationUserRole>(context));
if (!roleManager.Roles.Any())
{
await roleManager.CreateAsync(new ApplicationRole { Name = ApplicationRole.AdminRoleName });
await roleManager.CreateAsync(new ApplicationRole { Name = ApplicationRole.AffiliateRoleName });
}
if (!userManager.Users.Any(u => u.UserName == "shimmy"))
{
var user = new ApplicationUser
{
UserName = "shimmy",
Email = "shimmy#gmail.com",
EmailConfirmed = true,
PhoneNumber = "0123456789",
PhoneNumberConfirmed = true
};
await userManager.CreateAsync(user, "****");
await userManager.AddToRoleAsync(user.Id, ApplicationRole.AdminRoleName);
}
}
Looks like they changes the way authentication works in MVC5, changed my Global.asax.cs to the following did the trick!
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Threading.Tasks;
using MvcAuth.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System.Threading;
using Microsoft.AspNet.Identity.EntityFramework;
namespace MvcAuth
{
public class MvcApplication : System.Web.HttpApplication
{
async Task<bool> AddRoleAndUser()
{
AuthenticationIdentityManager IdentityManager = new AuthenticationIdentityManager(
new IdentityStore(new ApplicationDbContext()));
var role = new Role("Role1");
IdentityResult result = await IdentityManager.Roles.CreateRoleAsync(role, CancellationToken.None);
if (result.Success == false)
return false;
var user = new ApplicationUser() { UserName = "user1" };
result = await IdentityManager.Users.CreateLocalUserAsync(user, "Password1");
if (result.Success == false)
return false;
result = await IdentityManager.Roles.AddUserToRoleAsync(user.Id, role.Id, CancellationToken.None);
return result.Success;
}
protected async void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
bool x = await AddRoleAndUser();
}
}
}
write this code in your Migration Configuration.
note: Use ApplicationDbContext in Configuration Class.
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
}
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
context.Roles.AddOrUpdate(p =>
p.Id,
new IdentityRole { Name = "Admins"},
new IdentityRole { Name = "PowerUsers" },
new IdentityRole { Name = "Users" },
new IdentityRole { Name = "Anonymous" }
);
}
}