How do I initialize database with default values in .net6 - c#

Till .net5 I've been Seeding data using the following in startup.cs file:
SeedData.Seed(_userManager, _roleManager);
And then in a seperate file SeedData.cs, the following code:
public static class SeedData
{
public static void Seed(UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager)
{
SeedRoles(roleManager);
SeedUsers(userManager);
}
private static void SeedUsers(UserManager<IdentityUser> userManager)
{
if(userManager.FindByNameAsync("admin#localhost.com").Result == null)
{
var user = new IdentityUser
{
UserName = "admin#localhost.com",
Email = "admin#localhost.com"
};
var result = userManager.CreateAsync(user, "P#ssword1").Result;
if(result.Succeeded)
{
userManager.AddToRoleAsync(user, "Administrator").Wait();
}
}
}
private static void SeedRoles(RoleManager<IdentityRole> roleManager)
{
if(!roleManager.RoleExistsAsync("Administrator").Result)
{
var role = new IdentityRole
{
Name = "Administrator",
};
var result = roleManager.CreateAsync(role).Result;
}
if(!roleManager.RoleExistsAsync("Employee").Result)
{
var role = new IdentityRole
{
Name = "Employee",
};
var result = roleManager.CreateAsync(role).Result;
}
}
}
Now, how do i do the same with .net6, since it has only program.cs file?

This is what I personally do:
I make an extension to IApplicationBuilder:
public static class ApplicationBuilderExtensions
{
public static async Task<IApplicationBuilder> PrepareDatabase(this IApplicationBuilder app)
{
using var scopedServices = app.ApplicationServices.CreateScope();
var serviceProvider = scopedServices.ServiceProvider;
var data = serviceProvider.GetRequiredService<NeonatologyDbContext>();
data.Database.Migrate();
await SeedAdministratorAsync(serviceProvider);
await SeedDoctorAsync(data, serviceProvider);
return app;
}
Here are the seedings:
private static async Task SeedDoctorAsync(NeonatologyDbContext data, IServiceProvider serviceProvider)
{
if (data.Doctors.Any())
{
return;
}
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var roleManager = serviceProvider.GetRequiredService<RoleManager<ApplicationRole>>();
var identityRole = new ApplicationRole()
{
Name = DoctorRoleName
};
await roleManager.CreateAsync(identityRole);
var city = await data.Cities.Where(x => x.Name == "Плевен").FirstOrDefaultAsync();
var doctor = new ApplicationUser()
{
Email = DoctorEmail,
UserName = DoctorEmail,
EmailConfirmed = true,
Doctor = new Doctor
{
FirstName = DoctorFirstName,
LastName = DoctorLastName,
PhoneNumber = DoctorPhone,
Address = Address,
Age = DoctorAge,
Biography = Biography,
CityId = city.Id,
City = city,
YearsOfExperience = YearsOfExperience,
Email = DoctorEmail
}
};
await userManager.CreateAsync(doctor, DoctorPassword);
await userManager.AddToRoleAsync(doctor, identityRole.Name);
doctor.Doctor.UserId = doctor.Id;
doctor.Doctor.Image = new Image()
{
RemoteImageUrl = "SomeURL"
};
await data.SaveChangesAsync();
}
private static async Task SeedAdministratorAsync(IServiceProvider serviceProvider)
{
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var roleManager = serviceProvider.GetRequiredService<RoleManager<ApplicationRole>>();
if (await roleManager.RoleExistsAsync(AdministratorRoleName))
{
return;
}
var identityRole = new ApplicationRole()
{
Name = AdministratorRoleName
};
await roleManager.CreateAsync(identityRole);
const string adminEmail = AdministratorEmail;
const string adminPassword = AdministratorPassword;
var adminUser = new ApplicationUser()
{
Email = adminEmail,
UserName = adminEmail,
EmailConfirmed = true
};
if (await userManager.IsInRoleAsync(adminUser, identityRole.Name))
{
return;
}
await userManager.CreateAsync(adminUser, adminPassword);
await userManager.AddToRoleAsync(adminUser, identityRole.Name);
}
And in the Program.cs I have:
app.PrepareDatabase()
.GetAwaiter()
.GetResult();
The following snippet works for me and seeds the data upon initialization of the application.

Related

I am having following error while doing nunit test for this method. How can I solve this issue?

I am calling createPatient method from my repository it saves the data to the database.
public async Task<PatientResponseDTO> RegisteredPatientAsync(RegisterPatientDTO registeredUser)
{
if (registeredUser.CareGiverId != Guid.Empty)
{
registeredUser.CareGiver = await _appCrudRepository.GetCareGiverById(registeredUser.CareGiverId);
}
var patient = MapDTOToPatient(registeredUser);
patient.Id = Guid.NewGuid();
patient.Password = _passwordHashService.HashPassword(registeredUser.Password);
var patientResult = await _appCrudRepository.GetPatientByPhoneNumber(registeredUser.PhoneNumber);
var careGiverResult = await _appCrudRepository.GetCareGiverByPhoneNumber(registeredUser.PhoneNumber);
if (patientResult != null || careGiverResult != null)
{
throw new RegisterUserExistingException($"This User already exist with phoneNumber {registeredUser.PhoneNumber}");
}
await _appCrudRepository.CreatePatient(patient);
var response = MapDTOToPatientResponse(patient);
return response;
}
[SetUp]
public void Setup()
{
_fixture = new Fixture();
_mockRepository = new MockRepository(MockBehavior.Loose);
_appCrudRepositoryMock = _mockRepository.Create<IAppCrudRepository>();
_passWordServiceMock = _mockRepository.Create<IPasswordHashService>();
_emailServiceMock = _mockRepository.Create<IEmailService>();
_userServiceMock = _mockRepository.Create<IUserService>();
_userService = _userServiceMock.Object;
_passWordHashService = _passWordServiceMock.Object;
_emailService = _emailServiceMock.Object;
_appCrudRepository = _appCrudRepositoryMock.Object;
_fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList().ForEach(b => _fixture.Behaviors.Remove(b));
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
}
[TearDown]
public void TearDown()
{
_mockRepository.VerifyAll();
}
[Test]
public async Task RegisterPatient_Should_Return_PatientResponseDTO()
{
// Arrange
var careGiverId = Guid.NewGuid();
var careGiver = _fixture.Build<CareGiver>().With(x => x.Id, careGiverId).Create();
var createRegisterPatientDTO = _fixture.Build<RegisterPatientDTO>()
.With(x => x.CareGiverId, careGiverId)
.With(x => x.CareGiver, careGiver)
.Create();
var Id = Guid.NewGuid();
var patientRecord = _fixture.Create<Patient>();
var PatientResponseDTO = new PatientResponseDTO()
{
Id = patientRecord.Id,
Active = patientRecord.Active,
DateOfBirth = patientRecord.DateOfBirth,
DailyGoal = patientRecord.DailyGoal,
FirstName = patientRecord.FirstName,
LastName = patientRecord.LastName,
Email = patientRecord.Email,
UserRole = patientRecord.UserRole,
PhoneNumber = patientRecord.PhoneNumber,
DailyLimit = patientRecord.DailyLimit
};
var Patient = new Patient
{
Id = Id,
FirstName = createRegisterPatientDTO.FirstName,
LastName = createRegisterPatientDTO.LastName,
Password = createRegisterPatientDTO.Password,
PhoneNumber = createRegisterPatientDTO.PhoneNumber,
Email = createRegisterPatientDTO.Email,
DailyGoal = createRegisterPatientDTO.DailyGoal,
DailyLimit = createRegisterPatientDTO.DailyLimit,
Active = createRegisterPatientDTO.Active,
DateOfBirth = createRegisterPatientDTO.DateOfBirth,
CareGiver = careGiver,
UserRole = createRegisterPatientDTO.UserRole,
DayLogs = null,
GenerateTokenCode = null,
TokenCodeGeneratedTime = DateTime.Now,
};
_appCrudRepositoryMock.Setup(x => x.CreatePatient(Patient)).ReturnsAsync(2);
// Act
var result = await _userService.RegisteredPatientAsync(createRegisterPatientDTO);
// Assert
result.Should().NotBeNull();
//result.Should().BeEquivalentTo(PatientResponseDTO);
}
I am having the following error Message: 
Expected result not to be .
TearDown : Moq.MockException : The mock repository failed verification due to the following:
MockIAppCrudRepository:1:
This mock failed verification due to the following:
IAppCrudRepository x => x.CreatePatient(Patient):
This setup was not matched.

AddToRolesAsync causing Invalid Operation the connection is closed

I am getting the oddest of errors when I attempt to assign roles to user the role is their in the db fine.
But the function used to assign roles is causing an exception
public static async Task<IdentityResult>
AssignRoles(IServiceProvider services,ApplicationUser user,
string email, string[] roles)
{
IdentityResult result = new IdentityResult();
UserManager<ApplicationUser> _userManager =
services.GetService<UserManager<ApplicationUser>>();
result = await _userManager.AddToRolesAsync(user, roles);
return result;
}
The exception that I am getting is after the AddToRolesAsync is called
Invalid Operation the connection is closed
Code I use to call above
public async static void CreateParent(IServiceProvider serviceProvider)
{
var context = new DBContext();//
serviceProvider.GetService<DBContext>();
string[] roles = new string[] { "Parent" };
foreach (string role in roles)
{
var roleStore = new RoleStore<IdentityRole>(context);
if (!context.Roles.Any(r => r.Name == role))
{
await roleStore.CreateAsync(new IdentityRole(role));
}
}
var user = new ApplicationUser
{
FirstName = "Parent",
LastName = "Two",
Email = "parenttwo#apps-mobileapp.com",
NormalizedEmail ="PARENTTWO#APPS-MOBILEAPP.COM",
UserName = "parenttwo#apps-MOBILEAPP.com",
NormalizedUserName = "PARENTTWO#APPS-MOBILEAPP.COM",
PhoneNumber = "+111111111111",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D")
};
var db = new DBContext();
if (!db.Users.Any(u => u.UserName == user.UserName))
{
var password = new PasswordHasher<ApplicationUser>();
var hashed = password.HashPassword(user, "Test12345!");
user.PasswordHash = hashed;
var userStore = new UserStore<ApplicationUser>(context);
var result = await userStore.CreateAsync(user);
}
await AssignRoles(serviceProvider,user, user.Email, roles);
await db.SaveChangesAsync();
}
But its the AddToRolesAsync it fails with the error mentioned above, I am calling it form the startup class as such?
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env,IServiceProvider
service)
{
SampleData.CreateParent(service);
}

AspNetUsers custom columns don't appear in intellisense

Am trying to create a user database that I can modify to suit what my users will need to submit when registering for my service, I've created the database and am able to modify it and include whatever columns I want but I can't seem to access them in my c# code, the only fields that appear are those native to AspNetUsers, I've tried looking at similar questions but I can't seem to grasp the concepts specific to what I need, anyone that can help me get some clarity on this cause am a bit new to working with IdentityUser.
//Registration/Login
public class Identify : IIdentify
{
private readonly UserManager<IdentityUser> _manager;
private readonly Mystery _jwtset;
private readonly DataContext _personality;
public Identify(UserManager<IdentityUser> userManager, Mystery jW, DataContext users)
{
_manager = userManager;
_jwtset = jW;
_personality = users;
}
public async Task<Authentication_result> RegisterAsync(string email, string password, string Username)
{
var exists = await _manager.FindByEmailAsync(email);
if (exists != null)
{
return new Authentication_result
{
Errors = new[] { "User with this email already exists" }
};
}
var newPerson = new IdentityUser()
{
Email = email,
UserName = Username
};
var Creation = await _manager.CreateAsync(newPerson, password);
if (!Creation.Succeeded)
{
return new Authentication_result
{
Errors = new[] { "Invalid user!" }
};
}
return Generate_Authentication_Result(newPerson);
}
public async Task<Authentication_result> LoginAsync(string email, string Password)
{
var exists = await _manager.FindByEmailAsync(email);
if (exists == null)
{
return new Authentication_result
{
Errors = new[] { "User does not exists" }
};
}
var pass_validation = await _manager.CheckPasswordAsync(exists, Password);
if (!pass_validation)
{
return new Authentication_result
{
Errors = new[] { "f78wrvep034rf wrong" }
};
}
return Generate_Authentication_Result(exists);
}
private Authentication_result Generate_Authentication_Result(IdentityUser newPerson)
{
var Tokenhandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtset.Secret);
var TokenDescripter = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, newPerson.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Email, newPerson.Email),
new Claim("id",newPerson.Id)
}),
Expires = DateTime.UtcNow.AddHours(2),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = Tokenhandler.CreateToken(TokenDescripter);
return new Authentication_result
{
Success = true,
Token = Tokenhandler.WriteToken(token)
};
}
}
//Controller for the above
public class IdentifyMe : Controller
{
private readonly IIdentify _identify;
public IdentifyMe(IIdentify identifying)
{
_identify = identifying;
}
[HttpPost(Api_Routes.Identity.Register)]
public async Task<IActionResult> Register(UserRegistration register)
{
if (!ModelState.IsValid)
{
return BadRequest(new Unauthenticated
{
Errors = ModelState.Values.SelectMany(x => x.Errors.Select(xx => xx.ErrorMessage))
});
}
var authresponce = await _identify.RegisterAsync(register.Email, register.Password, register.User_Name);
if (!authresponce.Success)
{
return BadRequest(new Unauthenticated
{
Errors = authresponce.Errors
});
}
return Ok(new Authenticated
{
Token = authresponce.Token
});
}
[HttpPost(Api_Routes.Identity.Login)]
public async Task<IActionResult> LoginAsync(User_login login)
{
var authresponce = await _identify.LoginAsync(login.email, login.Password);
if (!authresponce.Success)
{
return BadRequest(new Unauthenticated
{
Errors = authresponce.Errors
});
}
return Ok(new Authenticated
{
Token = authresponce.Token
});
}
}
//Domain object, these are the values I would like to be able to access
public class Users : IdentityUser
{
public string PreferredNet { get; set; }
public int Inactive { get; set; }
public int Active { get; set; }
public int Max_Return { get; set; }
public DateTime Time { get; set; }
}
//Other controller
public ActionResult <IEnumerable<Time_dto>> Getitem(string usernum, int amt, string user, string server)
{
var Total = caller.Getusers();
//This is my attempt to acces the domain object, pitcture below[![Intelisense does not display fields in domain object][1]][1]
var container=Total.Select(x=>x.)
var totalin = _digital.Map<IEnumerable<User_dto>>(Total).Count(x => x.PreferredNet == user);
var totalout= _digital.Map<IEnumerable<User_dto>>(Total).Count(x=>x.PreferredNet== server);
int factor = 1;
var HCD = caller.rates(factor, user, server);
var result = shift;
int retrive = caller.Total(amt, user, server, HCD);
var serials = caller.cards(retrive);
int differential = retrive > serials.Sum() ? retrive serials.Sum() : serials.Sum() - retrive;
int number = serials.Count();
IEnumerable<int> Real_cards=new List<int>();
}
```
[1]: https://i.stack.imgur.com/HEenG.png

How to seed an Admin user in EF Core 2.1.0?

I have an ASP.NET Core 2.1.0 application using EF Core 2.1.0.
How do I go about seeding the database with Admin user and give him/her an Admin role? I cannot find any documentation on this.
As user cannot be seeded in a normal way in Identity just like other tables are seeded using .HasData() of .NET Core 2.1.
Microsoft Recommendation: For data that requires calls to external API, such as ASP.NET Core Identity users creation it is recommended to use custom initialization logic.
Seed Roles in .NET Core 2.1 using code given below in ApplicationDbContext Class :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() });
}
Seed Users With Roles by Following the steps given below.
Step 1: New class creation
public static class ApplicationDbInitializer
{
public static void SeedUsers(UserManager<IdentityUser> userManager)
{
if (userManager.FindByEmailAsync("abc#xyz.com").Result==null)
{
IdentityUser user = new IdentityUser
{
UserName = "abc#xyz.com",
Email = "abc#xyz.com"
};
IdentityResult result = userManager.CreateAsync(user, "PasswordHere").Result;
if (result.Succeeded)
{
userManager.AddToRoleAsync(user, "Admin").Wait();
}
}
}
}
Step 2: Now Modify ConfigureServices method in Startup.cs class.
Before Modification:
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
After Modification:
services.AddDefaultIdentity<IdentityUser>().AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Step 3: Modify parameters of Configure Method in Startup.cs class.
Before Modification :
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//..........
}
After modification :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, UserManager<IdentityUser> userManager)
{
//..........
}
Step 4 : Calling method of our Seed (ApplicationDbInitializer) class:
ApplicationDbInitializer.SeedUsers(userManager);
Note: You can also Seed Roles just like users by Injecting the RoleManager along with UserManager.
Actually a User Entity can be seeded in OnModelCreating, one thing to consider: the IDs should be predefined. If type string is used for TKey identity entities, then there is no problem at all.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// any guid
const string ADMIN_ID = "a18be9c0-aa65-4af8-bd17-00bd9344e575";
// any guid, but nothing is against to use the same one
const string ROLE_ID = ADMIN_ID;
builder.Entity<IdentityRole>().HasData(new IdentityRole
{
Id = ROLE_ID,
Name = "admin",
NormalizedName = "admin"
});
var hasher = new PasswordHasher<UserEntity>();
builder.Entity<UserEntity>().HasData(new UserEntity
{
Id = ADMIN_ID,
UserName = "admin",
NormalizedUserName = "admin",
Email = "some-admin-email#nonce.fake",
NormalizedEmail = "some-admin-email#nonce.fake",
EmailConfirmed = true,
PasswordHash = hasher.HashPassword(null, "SOME_ADMIN_PLAIN_PASSWORD"),
SecurityStamp = string.Empty
});
builder.Entity<IdentityUserRole<string>>().HasData(new IdentityUserRole<string>
{
RoleId = ROLE_ID,
UserId = ADMIN_ID
});
}
ASP.Net Core 3.1
That's how I do it using the EntityTypeBuilder :
Role Configuration:
public class RoleConfiguration : IEntityTypeConfiguration<IdentityRole>
{
private const string adminId = "2301D884-221A-4E7D-B509-0113DCC043E1";
private const string employeeId = "7D9B7113-A8F8-4035-99A7-A20DD400F6A3";
private const string sellerId = "78A7570F-3CE5-48BA-9461-80283ED1D94D";
private const string customerId = "01B168FE-810B-432D-9010-233BA0B380E9";
public void Configure(EntityTypeBuilder<IdentityRole> builder)
{
builder.HasData(
new IdentityRole
{
Id = adminId,
Name = "Administrator",
NormalizedName = "ADMINISTRATOR"
},
new IdentityRole
{
Id = employeeId,
Name = "Employee",
NormalizedName = "EMPLOYEE"
},
new IdentityRole
{
Id = sellerId,
Name = "Seller",
NormalizedName = "SELLER"
},
new IdentityRole
{
Id = customerId,
Name = "Customer",
NormalizedName = "CUSTOMER"
}
);
}
}
User Configuration:
public class AdminConfiguration : IEntityTypeConfiguration<ApplicationUser>
{
private const string adminId = "B22698B8-42A2-4115-9631-1C2D1E2AC5F7";
public void Configure(EntityTypeBuilder<ApplicationUser> builder)
{
var admin = new ApplicationUser
{
Id = adminId,
UserName = "masteradmin",
NormalizedUserName = "MASTERADMIN",
FirstName = "Master",
LastName = "Admin",
Email = "Admin#Admin.com",
NormalizedEmail = "ADMIN#ADMIN.COM",
PhoneNumber = "XXXXXXXXXXXXX",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
BirthDate = new DateTime(1980,1,1),
SecurityStamp = new Guid().ToString("D"),
UserType = UserType.Administrator
};
admin.PasswordHash = PassGenerate(admin);
builder.HasData(admin);
}
public string PassGenerate(ApplicationUser user)
{
var passHash = new PasswordHasher<ApplicationUser>();
return passHash.HashPassword(user, "password");
}
}
Assigning Roles To Users:
public class UsersWithRolesConfig : IEntityTypeConfiguration<IdentityUserRole<string>>
{
private const string adminUserId = "B22698B8-42A2-4115-9631-1C2D1E2AC5F7";
private const string adminRoleId = "2301D884-221A-4E7D-B509-0113DCC043E1";
public void Configure(EntityTypeBuilder<IdentityUserRole<string>> builder)
{
IdentityUserRole<string> iur = new IdentityUserRole<string>
{
RoleId = adminRoleId,
UserId = adminUserId
};
builder.HasData(iur);
}
}
Finally in the DB Context class:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//If you have alot of data configurations you can use this (works from ASP.Net core 2.2):
//This will pick up all configurations that are defined in the assembly
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
//Instead of this:
modelBuilder.ApplyConfiguration(new RoleConfiguration());
modelBuilder.ApplyConfiguration(new AdminConfiguration());
modelBuilder.ApplyConfiguration(new UsersWithRolesConfig());
}
Here is how I did it in the end. I created a DbInitializer.cs class to do the seeding of all my data (including the admin user).
Here's the code for the methods relating to the seeding of the user accounts:
private static async Task CreateRole(RoleManager<IdentityRole> roleManager,
ILogger<DbInitializer> logger, string role)
{
logger.LogInformation($"Create the role `{role}` for application");
IdentityResult result = await roleManager.CreateAsync(new IdentityRole(role));
if (result.Succeeded)
{
logger.LogDebug($"Created the role `{role}` successfully");
}
else
{
ApplicationException exception = new ApplicationException($"Default role `{role}` cannot be created");
logger.LogError(exception, GetIdentiryErrorsInCommaSeperatedList(result));
throw exception;
}
}
private static async Task<ApplicationUser> CreateDefaultUser(UserManager<ApplicationUser> userManager, ILogger<DbInitializer> logger, string displayName, string email)
{
logger.LogInformation($"Create default user with email `{email}` for application");
ApplicationUser user = new ApplicationUser
{
DisplayUsername = displayName,
Email = email,
UserName = email
};
IdentityResult identityResult = await userManager.CreateAsync(user);
if (identityResult.Succeeded)
{
logger.LogDebug($"Created default user `{email}` successfully");
}
else
{
ApplicationException exception = new ApplicationException($"Default user `{email}` cannot be created");
logger.LogError(exception, GetIdentiryErrorsInCommaSeperatedList(identityResult));
throw exception;
}
ApplicationUser createdUser = await userManager.FindByEmailAsync(email);
return createdUser;
}
private static async Task SetPasswordForUser(UserManager<ApplicationUser> userManager, ILogger<DbInitializer> logger, string email, ApplicationUser user, string password)
{
logger.LogInformation($"Set password for default user `{email}`");
IdentityResult identityResult = await userManager.AddPasswordAsync(user, password);
if (identityResult.Succeeded)
{
logger.LogTrace($"Set password `{password}` for default user `{email}` successfully");
}
else
{
ApplicationException exception = new ApplicationException($"Password for the user `{email}` cannot be set");
logger.LogError(exception, GetIdentiryErrorsInCommaSeperatedList(identityResult));
throw exception;
}
}
My Program.cs looks like this:
public class Program
{
public static async Task Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
Console.WriteLine(services.GetService<IConfiguration>().GetConnectionString("DefaultConnection"));
try
{
var context = services.GetRequiredService<PdContext>();
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
var dbInitializerLogger = services.GetRequiredService<ILogger<DbInitializer>>();
await DbInitializer.Initialize(context, userManager, roleManager, dbInitializerLogger);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while migrating the database.");
}
}
host.Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
This is based on .NET 6 with Individual user accounts and then scaffolding Identity. The user is created and then gets a confirmed email based on Microsofts code.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-6.0&tabs=visual-studio#scaffold-identity-into-a-razor-project-with-authorization
You can then seed the role per #Zubair Rana answer.
https://stackoverflow.com/a/51571555/3850405
Program.cs:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbAndRunMigrations(host);
host.Run();
}
private static void CreateDbAndRunMigrations(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
var userStore = services.GetRequiredService<IUserStore<ApplicationUser>>();
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
DbInitializer.Initialize(context, userManager, userStore);
}
}
}
DbInitializer.cs:
public static class DbInitializer
{
public static void Initialize(ApplicationDbContext context, UserManager<ApplicationUser> userManager, IUserStore<ApplicationUser> userStore)
{
if (context.Users.Any())
{
return; // DB has been seeded
}
var user = Activator.CreateInstance<ApplicationUser>();
var email = "example#example.com";
var emailStore = (IUserEmailStore<ApplicationUser>)userStore;
//Will not be used - Has to use Forgot Password. Last characters used to make sure password validation passes
var password = GetUniqueKey(40) + "aA1!";
userStore.SetUserNameAsync(user, email, CancellationToken.None).Wait();
emailStore.SetEmailAsync(user, email, CancellationToken.None).Wait();
var result = userManager.CreateAsync(user, password).Result;
if (result.Succeeded)
{
var userId = userManager.GetUserIdAsync(user).Result;
var code = userManager.GenerateEmailConfirmationTokenAsync(user).Result;
userManager.ConfirmEmailAsync(user, code).Wait();
}
else
{
throw new Exception();
}
}
private static string GetUniqueKey(int size)
{
var chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!+?*~".ToCharArray();
byte[] data = new byte[4*size];
using (var crypto = RandomNumberGenerator.Create())
{
crypto.GetBytes(data);
}
StringBuilder result = new StringBuilder(size);
for (int i = 0; i < size; i++)
{
var rnd = BitConverter.ToUInt32(data, i * 4);
var idx = rnd % chars.Length;
result.Append(chars[idx]);
}
return result.ToString();
}
}
If you are referring to Identity users, the way we did was to add hardcoded values in DbContext.OnModelCreating:
builder.Entity<Role>().HasData(new Role { Id = 2147483645, Name = UserRole.Admin.ToString(), NormalizedName = UserRole.Admin.ToString().ToUpper(), ConcurrencyStamp = "123c90a4-dfcb-4e77-91e9-d390b5b6e21b" });
And user:
builder.Entity<User>().HasData(new User
{
Id = 2147483646,
AccessFailedCount = 0,
PasswordHash = "SomePasswordHashKnownToYou",
LockoutEnabled = true,
FirstName = "AdminFName",
LastName = "AdminLName",
UserName = "admin",
Email = "admin#gmail.com",
EmailConfirmed = true,
InitialPaymentCompleted = true,
MaxUnbalancedTech = 1,
UniqueStamp = "2a1a39ef-ccc0-459d-aa9a-eec077bfdd22",
NormalizedEmail = "ADMIN#GMAIL.COM",
NormalizedUserName = "ADMIN",
TermsOfServiceAccepted = true,
TermsOfServiceAcceptedTimestamp = new DateTime(2018, 3, 24, 7, 42, 35, 10, DateTimeKind.Utc),
SecurityStamp = "ce907fd5-ccb4-4e96-a7ea-45712a14f5ef",
ConcurrencyStamp = "32fe9448-0c6c-43b2-b605-802c19c333a6",
CreatedTime = new DateTime(2018, 3, 24, 7, 42, 35, 10, DateTimeKind.Utc),
LastModified = new DateTime(2018, 3, 24, 7, 42, 35, 10, DateTimeKind.Utc)
});
builder.Entity<UserRoles>().HasData(new UserRoles() { RoleId = 2147483645, UserId = 2147483646 });
I wish there was some better/cleaner way to do it.
Here's how I created an admin role and ensured it was added to my admin user in dotnet 6 with very few lines of code using EF core
In your db context class:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<IdentityRole>().HasData(
new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() }
);
}
In your Program.cs file:
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var userManager = services.GetRequiredService<UserManager<User>>();
var admin = await userManager.FindByEmailAsync("admin#admin.com");
if (admin != null)
{
if (!await userManager.IsInRoleAsync(admin, "Admin"))
await userManager.AddToRoleAsync(admin, "Admin");
}
}
app.Run();

ASP.NET Core 2 seeding roles and users

public class DbInitializer
{
public static async Task CreateAdmin(IServiceProvider service)
{
UserManager<AppUser> userManager = service.GetRequiredService<UserManager<AppUser>>();
RoleManager<IdentityRole> roleManager = service.GetRequiredService<RoleManager<IdentityRole>>();
string username = "Admin";
string email = "AdminG#example.com";
string pass = "Secrete90";
string role = "Admins";
if(await userManager.FindByNameAsync(username)== null)
{
if(await roleManager.FindByNameAsync(role)== null)
{
await roleManager.CreateAsync(new IdentityRole(role));
}
var user = new AppUser { UserName = username, Email = email };
var result = await userManager.CreateAsync(user, pass);
if (result.Succeeded) { await userManager.AddToRoleAsync(user, role); }
}
}
When I run this code on start up, I get an error about not being able to scope the code in the startup class.
DbInitializer.CreateAdmin(app.ApplicationServices).Wait();
In .NET Core 2 calling your seed logic needs to be moved to the Main method of the program.cs class.
Example Program.cs
public static void Main(string[] args) {
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope()) {
var services = scope.ServiceProvider;
var userManager = services.GetRequiredService<UserManager<AppUser>>();
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
DbInitializer.CreateAdmin(userManager, roleManager).Wait();
}
host.Run();
}
Updated DbInitializer
public class DbInitializer
{
public static async Task CreateAdmin(UserManager<AppUser> userManager, RoleManager<IdentityRole> roleManager)
{
string username = "Admin";
string email = "AdminG#example.com";
string pass = "Secrete90";
string role = "Admins";
if(await userManager.FindByNameAsync(username)== null)
{
if(await roleManager.FindByNameAsync(role)== null)
{
await roleManager.CreateAsync(new IdentityRole(role));
}
var user = new AppUser { UserName = username, Email = email };
var result = await userManager.CreateAsync(user, pass);
if (result.Succeeded) { await userManager.AddToRoleAsync(user, role); }
}
}

Categories