Suggested Videos
Part 74 - ASP.NET Core client side validation | Text | Slides
Part 75 - ASP.NET core remote validation | Text | Slides
Part 76 - Custom validation attribute in asp.net core | Text | Slides
In this video we will discuss how to extend the built-in IdentityUser class in ASP.NET Core.
Why should we extend IdentityUser class
The built-in IdentityUser class has very limited set of properties like Id, Username, Email, PasswordHash etc. The source code of this class is shown below.
What if I want to store additional data about the user like Gender, City, Country etc. The built-in IdentityUser class does not have these properties. To store custom user data like Gender, City, Country etc, extend the IdentityUser class.
Extend IdentityUser Class
You can name the class that extends the IdentityUser class anything you want, but it is customary to name it ApplicationUser. In the example below, ApplicationUser class extends the IdentityUser class. We have included just one custom property City, but you can include as many properties as you want.
Find all references of IdentityUser class and replace it with our custom ApplicationUser class. The easiest way to do this is to, right click on the IdentityUser class and then select "Find All References" from the context menu. Navigate to each reference in the list and replace IdentityUser class with ApplicationUser class.
Specify ApplicationUser class as the generic argument for the IdentityDbContext class
This is how the IdentityDbContext class knows it has to work with our custom user class (in this case ApplicationUser class) instead of the default built-in IdentityUser class.
Generate a new migration to add columns to AspNetUsers table
The above command generates the required migration code to add City column to AspNetUsers table.
Next, apply the migration to the database using the following command
Extending IdentityUser - Add-Migration Not Working
If ApplicationUser class (the class that extends IdentityUser class) is not specified as the generic argument for IdentityDbContext class, Add-Migration command does not work. It does not generate the required migration code to add the additional columns to the AspNetUsers identity table.
To fix this, specify ApplicationUser class as the generic argument for IdentityDbContext class.
If you get the following exception, the most likely cause is somewhere with in your application you are still using IdentityUser class instead of the ApplicationUser class.
In Visual Studio, search for IdentityUser class throughout your application using CTRL + SHIFT + F
Replace IdentityUser class with ApplicationUser class and rerun the project.
Storing custom data in AspNetUsers table
We register a new user using the following Register view.
To be able to store data for the custom City column in AspNetUsers table we need to alter
This is the model class for the Register view. Modify it to include City property.
Register View
On the Register view, include a field to capture a value for City.
AccountController - Register action
Part 74 - ASP.NET Core client side validation | Text | Slides
Part 75 - ASP.NET core remote validation | Text | Slides
Part 76 - Custom validation attribute in asp.net core | Text | Slides
In this video we will discuss how to extend the built-in IdentityUser class in ASP.NET Core.
Why should we extend IdentityUser class
The built-in IdentityUser class has very limited set of properties like Id, Username, Email, PasswordHash etc. The source code of this class is shown below.
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
{
public IdentityUser() { }
public IdentityUser(string userName) : this()
{
UserName = userName;
}
[PersonalData]
public virtual TKey Id
{ get; set; }
[ProtectedPersonalData]
public virtual string UserName { get; set; }
public virtual string NormalizedUserName { get; set; }
[ProtectedPersonalData]
public virtual string Email { get; set; }
public virtual string NormalizedEmail { get; set; }
[PersonalData]
public virtual bool EmailConfirmed { get; set; }
public virtual string PasswordHash { get; set; }
public virtual string SecurityStamp { get; set; }
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();
[ProtectedPersonalData]
public virtual string PhoneNumber { get; set; }
[PersonalData]
public virtual bool PhoneNumberConfirmed { get; set; }
[PersonalData]
public virtual bool TwoFactorEnabled { get; set; }
public virtual
DateTimeOffset? LockoutEnd { get; set; }
public virtual bool LockoutEnabled { get; set; }
public virtual int AccessFailedCount { get; set; }
public override string
ToString()
=> UserName;
}
What if I want to store additional data about the user like Gender, City, Country etc. The built-in IdentityUser class does not have these properties. To store custom user data like Gender, City, Country etc, extend the IdentityUser class.
Extend IdentityUser Class
You can name the class that extends the IdentityUser class anything you want, but it is customary to name it ApplicationUser. In the example below, ApplicationUser class extends the IdentityUser class. We have included just one custom property City, but you can include as many properties as you want.
public class ApplicationUser : IdentityUser
{
public string City { get; set; }
}
Find all references of IdentityUser class and replace it with our custom ApplicationUser class. The easiest way to do this is to, right click on the IdentityUser class and then select "Find All References" from the context menu. Navigate to each reference in the list and replace IdentityUser class with ApplicationUser class.
Specify ApplicationUser class as the generic argument for the IdentityDbContext class
This is how the IdentityDbContext class knows it has to work with our custom user class (in this case ApplicationUser class) instead of the default built-in IdentityUser class.
public class AppDbContext :
IdentityDbContext<ApplicationUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{ }
public DbSet<Employee> Employees { get; set; }
protected override void
OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Seed();
}
}
Generate a new migration to add columns to AspNetUsers table
Add-Migration Extend_IdentityUser
The above command generates the required migration code to add City column to AspNetUsers table.
public partial class Extend_IdentityUser : Migration
{
protected override void
Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "City",
table: "AspNetUsers",
nullable: true);
}
protected override void
Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "City",
table: "AspNetUsers");
}
}
Next, apply the migration to the database using the following command
Update-Database
Extending IdentityUser - Add-Migration Not Working
If ApplicationUser class (the class that extends IdentityUser class) is not specified as the generic argument for IdentityDbContext class, Add-Migration command does not work. It does not generate the required migration code to add the additional columns to the AspNetUsers identity table.
To fix this, specify ApplicationUser class as the generic argument for IdentityDbContext class.
public class AppDbContext :
IdentityDbContext<ApplicationUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{ }
public DbSet<Employee> Employees { get; set; }
protected override void
OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Seed();
}
}
If you get the following exception, the most likely cause is somewhere with in your application you are still using IdentityUser class instead of the ApplicationUser class.
No service for type 'Microsoft.AspNetCore.Identity.SignInManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' has been registered.
In Visual Studio, search for IdentityUser class throughout your application using CTRL + SHIFT + F
Replace IdentityUser class with ApplicationUser class and rerun the project.
Storing custom data in AspNetUsers table
We register a new user using the following Register view.
To be able to store data for the custom City column in AspNetUsers table we need to alter
- RegisterViewModel class
- Register View
- Register action in the AccountController
This is the model class for the Register view. Modify it to include City property.
public class RegisterViewModel
{
// Other Properties
public string City { get; set; }
}
{
// Other Properties
public string City { get; set; }
}
Register View
On the Register view, include a field to capture a value for City.
@model
RegisterViewModel
@{
ViewBag.Title = "User Registration";
}
<h1>User
Registration</h1>
<div class="row">
<div class="col-md-12">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
@*Other Fields*@
<div class="form-group">
<label asp-for="City"></label>
<input asp-for="City" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</div>
AccountController - Register action
- Populate City property of ApplicationUser instance which is then passed to the CreateAsync() method of UserManager class.
- The data in the ApplicationUser instance is then saved to the AspNetUsers table by the IdentityDbContext class.
[HttpPost]
[AllowAnonymous]
public async
Task<IActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new
ApplicationUser
{
UserName = model.Email,
Email = model.Email,
City = model.City
};
var result = await
userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await signInManager.SignInAsync(user, isPersistent: false);
return RedirectToAction("index", "home");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
return View(model);
}
what if we want more than one identity user, like identity for student, identity for instructor.. how can we do that?
ReplyDelete