Seed Users and Roles Data in ASP.NET Core Identity
ASP.NET Core identity allows you to implement authentication and
authorization for your web applications. While working with ASP.NET Core
Identity at times you need to create default user accounts and roles in the
system. In ASP.NET MVC you could have easily done this in Global.asax and
Application_Start event handler. In ASP.NET Core the process is bit different
since the application startup process is different. To that end this article
explains a way to seed such user and roles data in your applications.
Before you go any further ensure that you have a web application configured
to use ASP.NET Core Identity. I am going to assume that you have followed my
earlier article
here to
implement ASP.NET Core Identity in your web application. The article just
mentioned is for ASP.NET Core 1.x but most of the part is same under ASP.NET
Core 2.0. So, it should be an easy upgrade for you. Of course, you can use
your own implementation also.
If you followed my article mentioned above, you already have
MyIdentityDbContext, MyIdentityUser and MyIdentityRole classes ready with you.
Our aim is to create a few user accounts and a few roles when the application
runs for the first time. Obviously, we do this only if those users and roles
doesn't exists in the database yet.
In the following sections we discuss two ways of seeding the data :
- Using Configure() method
- Using Main() method
The former method is simple and straightforward with minimal coding. Just
like you inject objects in other parts of your application, you can inject them
into the Configure() method also. The later approach is bit complex and requires
you to shift the seeding operation to the Main() from Program.cs.
Ok. Let's get going!
Modify your Configure() method signature as shown below :
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
UserManager<MyIdentityUser> userManager,
RoleManager<MyIdentityRole> roleManager)
{
...
...
}
As you can see we now inject UserManager and RoleManager into the Configure()
method. This way you can use UserManager to create user accounts and RoleManager
to create roles at the application startup. Instead of writing code directly
inside the Configure() method, we will isolate it in a separate class and then
call it from here.
So, add a new class called MyIdentityDataInitializer into the project. The
following code shows the skeleton of this class :
public static class MyIdentityDataInitializer
{
public static void SeedData
(UserManager<MyIdentityUser> userManager,
RoleManager<MyIdentityRole> roleManager)
{
}
public static void SeedUsers
(UserManager<MyIdentityUser> userManager)
{
}
public static void SeedRoles
(RoleManager<MyIdentityRole> roleManager)
{
}
}
The MyIdentityDataInitializer class has three static methods - SeedRoles(),
SeedUsers() and SeedData(). If you wish to create both - users and roles - then
you would call SeedData(). You can also create only users or only roles using
the respective methods.
Now, let's see the code that goes inside these methods. This code should be
familiar to you because you already wrote something similar in the
AccountController (see my earlier article
here for
example).
The SeedRoles() creates desired default roles in the system and looks like
this :
public static void SeedRoles
(RoleManager<MyIdentityRole> roleManager)
{
if (!roleManager.RoleExistsAsync
("NormalUser").Result)
{
MyIdentityRole role = new MyIdentityRole();
role.Name = "NormalUser";
role.Description = "Perform normal operations.";
IdentityResult roleResult = roleManager.
CreateAsync(role).Result;
}
if (!roleManager.RoleExistsAsync
("Administrator").Result)
{
MyIdentityRole role = new MyIdentityRole();
role.Name = "Administrator";
role.Description = "Perform all the operations.";
IdentityResult roleResult = roleManager.
CreateAsync(role).Result;
}
}
The SeedRoles() method accepts RoleManager as its parameter. Inside, it
creates two roles in the system - NormalUser and Administrator. You should
change the role names and their description as per your need. Note that we first
check whether a role already exists or not. If it doesn't exist only then we
create it.
The SeedUsers() creates desired default user accounts and looks like this :
public static void SeedUsers
(UserManager<MyIdentityUser> userManager)
{
if (userManager.FindByNameAsync
("user1").Result == null)
{
MyIdentityUser user = new MyIdentityUser();
user.UserName = "user1";
user.Email = "user1@localhost";
user.FullName = "Nancy Davolio";
user.BirthDate = new DateTime(1960, 1, 1);
IdentityResult result = userManager.CreateAsync
(user, "password_goes_here").Result;
if (result.Succeeded)
{
userManager.AddToRoleAsync(user,
"NormalUser").Wait();
}
}
if (userManager.FindByNameAsync
("user2").Result == null)
{
MyIdentityUser user = new MyIdentityUser();
user.UserName = "user2";
user.Email = "user2@localhost";
user.FullName = "Mark Smith";
user.BirthDate = new DateTime(1965, 1, 1);
IdentityResult result = userManager.CreateAsync
(user, "password_goes_here").Result;
if (result.Succeeded)
{
userManager.AddToRoleAsync(user,
"Administrator").Wait();
}
}
}
The SeedUsers() method accepts a UserManager and creates two users - user1
and user2. Notice that we first check whether a user with the same name exists
or not. If it doesn't exist then we create it with default values of l, full
name and birth date. Change these values as per your requirement. Also notice
that the user accounts have been assigned certain default roles.
The SeedUsers() and SeedRoles() don't return any value. But you can change
the signature to return some success or failure status if you so wish.
The SeedData() basically calls SeedRoles() and SeedUsers() and looks like
this :
public static void SeedData
(UserManager<MyIdentityUser> userManager,
RoleManager<MyIdentityRole> roleManager)
{
SeedRoles(roleManager);
SeedUsers(userManager);
}
The SeedData() method accepts a UserManager and a RoleManager. Inside, it
calls SeedRoles() and SeedUsers(). Note that SeedRoles() is called first because
SeedUsers() assigns certain roles to the users being added and those roles must
exist in the system prior to adding the users.
Seeding data in Configure()
Finally, it's time to use the MyIdentityDataInitializer class. Open Startup
class, go to Configure() method and add this line of code :
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
UserManager<MyIdentityUser> userManager,
RoleManager<MyIdentityRole> roleManager)
{
...
app.UseAuthentication();
MyIdentityDataInitializer.SeedData(userManager, roleManager);
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
As you can see after calling UseAuthentication() we call SeedData() on
MyIdentityDataInitializer.
Run the application and see whether the users get created in the database or
not. The following figure shows these sample user accounts getting created in
the database :
Seeding data in Main()
In the preceding code you created default users and roles in the Configure()
method. You can also do that work in Main() method. You might want to use this
later approach if you are also seeding data for EF core (won't go into those
details here). The following code from Program.cs shows how the Main() code
looks like :
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var serviceProvider = scope.ServiceProvider;
try
{
var userManager = serviceProvider.
GetRequiredService<UserManager<MyIdentityUser>>();
var roleManager = serviceProvider.
GetRequiredService<RoleManager<MyIdentityRole>>();
MyIdentityDataInitializer.SeedData
(userManager, roleManager);
}
catch
{
}
}
host.Run();
}
Here, instead of injecting the UserManager and RoleManager into Configure()
you grab them from GetRequiredService() method. The userManager and
roleManager objects are then passed to SeedData() as before.
That's it for now! Keep coding !!