Seed Roles and Users into a .NET Application at Startup
There are times when you want to seed some data into your .net app at startup; for example, roles, admin user, or even locations (such as your business operational countries). Whatever the case may be, you want some data to be available whenever the app is running.
Start by defining the roles your app needs in an enum (or whatever method makes sense for your app)
public enum Roles
{
Admin = 0,
User = 1,
}
Create a static DbInitializer class in your persistence layer and add the following method to seed roles
public static async Task SeedRoles(this IServiceProvider serviceProvider, ILogger logger)
{
logger.LogInformation("Seeding roles...");
var roleManager = serviceProvider
.GetRequiredService<RoleManager<IdentityRole>>();
// Check if roles already exist
if (await roleManager.Roles.AnyAsync())
{
logger.LogInformation("Roles already exist. Skipping seeding.");
return;
}
// Get the list of roles from Roles enum
var roles = Enum.GetValues(typeof(Roles))
.Cast<Roles>()
.Select(role => new IdentityRole(role.ToString()))
.ToList();
// Create each role
foreach (var role in roles)
{
var result = await roleManager.CreateAsync(role);
if (result.Succeeded)
{
logger.LogInformation("Role {RoleName} created successfully.", role.Name);
}
else
{
logger.LogError("Error creating role {RoleName}: {@Errors}",
role.Name, result.Errors);
}
}
logger.LogInformation("Roles seeding completed.");
}
To seed the default admin user, create a basic model to use for binding the user data
internal class SeedUser
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
Create a section in your appsettings.json file to provide the details for the user
"AppUser": {
"FirstName": "",
"LastName": "",
"Email": "",
"UserName": "",
"Password": ""
}
Add the logic for seeding the user and adding them to the role
public static async Task SeedUsers(this IServiceProvider serviceProvider, IConfiguration configuration, ILogger logger)
{
logger.LogInformation("Seeding default users...");
var userManager = serviceProvider
.GetRequiredService<UserManager<ApplicationUser>>();
// Check if users already exist
if (await userManager.Users.AnyAsync())
{
logger.LogInformation("Users already exist. Skipping seeding.");
return;
}
// Get seed user from configuration
var seedUser = configuration.GetSection("AppUser").Get<SeedUser>();
if (seedUser is null)
{
logger.LogError("Seed user configuration is missing.");
throw new InvalidOperationException("Seed user configuration is not set.");
}
// Create the admin user
var admin = new ApplicationUser
{
FirstName = seedUser.FirstName,
LastName = seedUser.LastName,
Email = seedUser.Email,
UserName = seedUser.UserName,
};
var result = await userManager.CreateAsync(admin, seedUser.Password);
if (result.Succeeded)
{
// Assign the user to the Admin role
await userManager.AddToRoleAsync(admin, Roles.Admin.ToString());
logger.LogInformation("Default user created and assigned to role {RoleName}.", Roles.Admin.ToString());
}
else
{
logger.LogError("Error creating default user: {@Errors}", result.Errors);
throw new InvalidOperationException("Failed to create default user. See logs for details.");
}
}
Create a scope in your Program.cs file after calling builder.Build(); for seeding the database (because EntityFramework Core requires it)
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
var configuration = services.GetRequiredService<IConfiguration>();
try
{
var logger = loggerFactory.CreateLogger("DatabaseSeeder");
await services.SeedRoles(logger); // Seed roles first
await services.SeedUsers(configuration, logger);
}
catch (Exception ex)
{
var logger = loggerFactory.CreateLogger("DatabaseSeeder");
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
NOTE: Always remember to seed roles first before seeding users.