I'm following this article to delete a user in Identity 2.0 http://www.asp.net/mvc/tutorials/mvc-5/introduction/examining-the-details-and-delete-methods
However, I need to delete all related records in AspNetUserRoles first and then delete the user.
I found an example which is written in Identity 1.0 and some of methods used inside this example don't exist.
// POST: /Users/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public async Task<ActionResult> DeleteConfirmed(string id) { if (ModelState.IsValid) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var user = await context.Users.FindAsync(id); var logins = user.Logins; foreach (var login in logins) { context.UserLogins.Remove(login); } var rolesForUser = await IdentityManager.Roles.GetRolesForUserAsync(id, CancellationToken.None); if (rolesForUser.Count() > 0) { foreach (var item in rolesForUser) { var result = await IdentityManager.Roles.RemoveUserFromRoleAsync(user.Id, item.Id, CancellationToken.None); } } context.Users.Remove(user); await context.SaveChangesAsync(); return RedirectToAction("Index"); } else { return View(); } }
I cannot find IdentityManager
from anywhere, and context.Users
doesn't have FindAsync()
method either.
How can I properly delete a User and its related records in Identity 2.0?
To delete a user you should use the DeleteAsync method which accepts a user object as a parameter. To get the roles a user is member of Identity gives you the GetRolesAsync method where you pass in the ID of the user.
ASP.NET Identity is the membership system for authentication and authorization of the users by building an ASP.NET application. ASP.NET Identity is the membership system for authentication and authorization of the users by building an ASP.NET application.
I think the classes you're looking for are the UserManager and the RoleManager. In my opinion they are the better way instead of going against the context directly.
The UserManager defines a method RemoveFromRoleAsync which gives you the ability to remove the user (identified by his key) from a given role. It also defines several Find methods, such as FindAsync, FindByIdAsync, FindByNameAsync, or FindByEmailAsync. They all can be used to retrieve a user. To delete a user you should use the DeleteAsync method which accepts a user object as a parameter. To get the roles a user is member of Identity gives you the GetRolesAsync method where you pass in the ID of the user. Also I see that you're trying to remove a login from a user. For this purpose you should use the RemoveLoginAsync method.
All in all your code would look similar to the following one:
// POST: /Users/Delete/5 [HttpPost, ActionName("Delete")] [ValidateAntiForgeryToken] public async Task<ActionResult> DeleteConfirmed(string id) { if (ModelState.IsValid) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var user = await _userManager.FindByIdAsync(id); var logins = user.Logins; var rolesForUser = await _userManager.GetRolesAsync(id); using (var transaction = context.Database.BeginTransaction()) { foreach (var login in logins.ToList()) { await _userManager.RemoveLoginAsync(login.UserId, new UserLoginInfo(login.LoginProvider, login.ProviderKey)); } if (rolesForUser.Count() > 0) { foreach (var item in rolesForUser.ToList()) { // item should be the name of the role var result = await _userManager.RemoveFromRoleAsync(user.Id, item); } } await _userManager.DeleteAsync(user); transaction.Commit(); } return RedirectToAction("Index"); } else { return View(); } }
You'll need to adjust this snippet to your needs, because I don't have an idea how your IdentityUser implementation looks like. Remember to declare the UserManager as needed. An example how you could do this can be found when you create a new project in Visual Studio using Individual Accounts.
I need to invoke DeleteUser from a number of places so I added a static method to AccountController (see below). I'm still learning about MVC, so should be grateful for comments, in particular 1) use of IdentityResult as a return code 2) wisdom of extending AccountController in this way 3) approach for putting password (cleartext) into the Model to validate the action (see sample invocation).
public static async Task<IdentityResult> DeleteUserAccount(UserManager<ApplicationUser> userManager, string userEmail, ApplicationDbContext context) { IdentityResult rc = new IdentityResult(); if ((userManager != null) && (userEmail != null) && (context != null) ) { var user = await userManager.FindByEmailAsync(userEmail); var logins = user.Logins; var rolesForUser = await userManager.GetRolesAsync(user); using (var transaction = context.Database.BeginTransaction()) { foreach (var login in logins.ToList()) { await userManager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey); } if (rolesForUser.Count() > 0) { foreach (var item in rolesForUser.ToList()) { // item should be the name of the role var result = await userManager.RemoveFromRoleAsync(user, item); } } rc = await userManager.DeleteAsync(user); transaction.Commit(); } } return rc; }
Sample invocation - form passes the user's password (cleartext) in Model:
// POST: /Manage/DeleteUser [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> DeleteUser(DeleteUserViewModel account) { var user = await GetCurrentUserAsync(); if ((user != null) && (user.PasswordHash != null) && (account != null) && (account.Password != null)) { var hasher = new Microsoft.AspNetCore.Identity.PasswordHasher<ApplicationUser>(); if(hasher.VerifyHashedPassword(user,user.PasswordHash, account.Password) != PasswordVerificationResult.Failed) { IdentityResult rc = await AccountController.DeleteUserAccount( _userManager, user.Email, _Dbcontext); if (rc.Succeeded) { await _signInManager.SignOutAsync(); _logger.LogInformation(4, "User logged out."); return RedirectToAction(nameof(HomeController.Index), "Home"); } } } return View(account); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With