Updating a user with Asp.Net Identity - username exists - c#

I am struggling a bit with Asp.net Identity and updating a user. When I run the code below succeed is false and the error message is that the user with username exists. Which is - of course - obvious because you are updating a user, not creating a new one.
I have tried to remove the username without much success, I was then told that the Name (I believe it meant Username) could not be empty.
Snip of code below.
public async Task<ActionResult> Edit(RegisterViewModel model)
{
var user = new User()
{
UserName = model.UserName, FirstName = model.FirstName, LastName = model.LastName, Email = model.EmailAddress,
ApplicationId = Utilities.ApplicationUtilities.GetApplicationId()
};
var userContext = new ApplicationDbContext();
var userStore = new UserStore<User>(userContext);
var userManager = new UserManager<User>(userStore);
var result = await userManager.UpdateAsync(user);
if (result.Succeeded)
{
var selectedRole = model.SelectedRole;
if (!userManager.IsInRole(user.Id, selectedRole.Id))
{
// We are removing the user from the old role. He / she cannot have two or more roles
userManager.RemoveFromRole(user.Id, model.OldRole);
// Now we are adding the user to the new role
userManager.AddToRole(user.Id, selectedRole.Id);
userManager.Update(user);
}
userContext.SaveChanges();
// await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "UserManager");
}
The solution based on the input from Jonesy became something like this:
/*
* Some more information /Just in case someone else does the same
* mistakes I did...
*/
model.OldRole = "User"; // Name of old role - not ID of old role
model.SelectedRoleId = "Administrator"; // Name of new role, not ID of new role
// This test is here just to check if the model is valid or not
// By adding this part, you can check what is possibly wrong with your model
if (!ModelState.IsValid)
{
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new {x.Key, x.Value.Errors})
.ToArray();
}
// Creating the ApplicationDbContext object
var userContext = new ApplicationDbContext();
// Getting the list of users (I tried using Find here, but got errors)
var userList = userContext.Users.ToList();
// Decided to use First or Default. You also have to use double
// equal-characters(=) otherwise you will get errors
var user = userList.FirstOrDefault(u => u.UserName == model.UserName);
// Checking that we really found the user to update
if (user != null)
{
// populate the user object
user.UserId = model.UserId;
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Email = model.EmailAddress;
}
// creating the UserStore object
var userStore = new UserStore<User>(userContext);
// ... and the userManager object
var userManager = new UserManager<User>(userStore);
// Do the update - I believe this is on the userManager-object
// and not in the database
var result = await userManager.UpdateAsync(user);
// If we get an error, we return to list of Users
// (You should log the error and also return the user to the form)
if (!result.Succeeded) return RedirectToAction("Index", "UserManager");
// Do the actual update in the database
userContext.SaveChanges();
// If the old role and the selected role is the same, we don't
// have to update
if (model.OldRole == model.SelectedRoleId) return RedirectToAction("Index", "UserManager");
// Get the selected role (sort of not needed, but here for clarity)
string selectedRole = model.SelectedRoleId;
// We are removing the user from the old role.
// In our application a user cannot have two or more roles
userManager.RemoveFromRole<User, string>(user.UserId, model.OldRole);
// Now we are adding the user to the new role
userManager.AddToRole<User, string>(user.UserId, selectedRole);
// We are updating the userManager-object
userManager.Update(user);
// And storing the information in the database
userContext.SaveChanges();
// Returning the user to the list of users
return RedirectToAction("Index", "UserManager");

use your dbContext to pull the user to update, instead of creating a new one:
var user = userContext.Find(model.UserName);
or you may need
var user = userContext.FirstOrDefault(u => u.UserName = model.UserName && u.Email = model.EmailAddress);
if(user != null)
{
//update user
}

this is an old one but just wanted to post my solution to the same update issue
var user = UserManager.FindByEmail(model.Email);
user.Address = model.Address;
user.City = model.City;
user.State = model.State;
var result = await UserManager.UpdateAsync(user);
you can also manage roles
user.Roles.Add(Role);
user.Roles.Remove(Role);

Related

Get user roles before returning to client ASP.NET Core

I need to create a controller that will get and delete all users and a certain user, respectively and I've figured out the part to get the users, add them to a list and return the list. But I struggle with the get roles part. Initially I tried a Linq Select and that works just fine (and looks decent) for simply getting the roles but doesn't work for getting the roles for that specific user as well. I've also tried a much worse methods: getting all the users from db in a list, foreach the list and for every iteration in the foreach, create a new object of the type I want to return and assign the role for that user to the respective object property. Doesn't work AND it's ugly.
TL;DR : is this the proper way to get roles in a select and does the 'Role' property need to be IList 100%?
Here's my GetRoles method:
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public IActionResult GetUsers()
{
var userDbList = _userManager.Users.ToList();
if (userDbList is null) return BadRequest(AppResources.UsersDoNotExist);
// my initial select. GetUsersModel is just a model for the object
// I return and contains Name, Email, UserName and Role. As you can see,
// the method is async but I get a cannot implicitly convert System.Collections
// .Generic.IList<string> to string (I suspect I need to set Role as a List<string>?)
var userList = userDbList.Select(async user => new GetUsersModel
{
Name = $"{user.FirstName} {user.LastName}",
UserName = user.UserName,
Email = user.Email,
Role = await _userManager.GetRolesAsync(user)
});
/*var userList = new List<GetUsersModel>();
foreach (var user in userDbList)
{
userList.Add(new GetUsersModel
{
Name = $"{user.FirstName} {user.LastName}",
UserName = user.UserName,
Email = user.Email,
Role = await _userManager.GetRolesAsync(user)
});
}*/
return Ok(userList);
}
I have a similar method for deleting a user, only I first check request data and remove the user if everything's ok and then create a list to include in an object (along with a message if the removal was successful) to return.
When you use async lambda in a select, this return IEnumerable<Task<T>>. In you case, the variable userList is type of IEnumerable<Task<GetUsersModel>>. You need to wait all tasks and get the result like :
public IActionResult GetUsers()
{
var userDbList = _userManager.Users.ToList();
if (userDbList is null) return BadRequest(AppResources.UsersDoNotExist);
IEnumerable<Task<GetUsersModel>> userListTasks = userDbList.Select(async user => new GetUsersModel
{
Name = $"{user.FirstName} {user.LastName}",
UserName = user.UserName,
Email = user.Email,
Role = await _userManager.GetRolesAsync(user)
});
IEnumerable<GetUsersModel> userList = userListTasks.Select(t => t.Result);
return Ok(userList);
}
If the method UserManager.GetRolesAsync isn't thread safe, then :
public IActionResult GetUsers()
{
var userDbList = _userManager.Users.ToList();
if (userDbList is null) return BadRequest(AppResources.UsersDoNotExist);
IEnumerable<GetUsersModel> userList = userDbList.Select(user => new GetUsersModel
{
Name = $"{user.FirstName} {user.LastName}",
UserName = user.UserName,
Email = user.Email,
Role = _userManager.GetRolesAsync(user).Result
});
return Ok(userList);
}

Delete user from default mvc application database

I am trying to delete an already existing user from a database, which was created automatically when creating MVC application.
The database consists of tables:
AspNetUsers
AspNetUserRoles
AspNetUserLogins
AspNetUserClaims
AspNetRoles
In my code it looks like this:
var user = new ApplicationUser { UserName = model.email, Email = model.email };
var context = new ApplicationDbContext();
context.Users.Attach(user);
context.Users.Remove(user);
context.SaveChangesAsync();
return RedirectToAction("OperationSuccess", "Account");
I have also tried this:
var user = new ApplicationUser { UserName = model.email, Email = model.email };
var context = new ApplicationDbContext();
UserManager.DeleteAsync(user);
But it doesn't help at all. The application itselt does not break and does not show any errors, but the user is still in the database. How do I delete it?
Try this code:
public async Task<IdentityResult> DeleteUser(string email)
{
var user = UserManager.Users.FirstOrDefault(x => x.Email == email);
if(user == null) return null;
var result = await UserManager.DeleteAsync(user); //here result has two properties Errors and Succeeded.
return result;
}
Also, your code is not working because you are creating the object yourself and assigning only two properties yourself in spite of fetching the data from database.
Hi I think you have some versioning problem and its seems that you need to give one extra paramater to the DeleteAsync method.
Kindly refer the below link, since they had same kind of issue and resolved it.
https://stackoverflow.com/a/24594440/3397630
Hope it may give you some idea for your solution too.
Thanks
Karthik
Hope below code will help you to fix your problem
[HttpPost]
public async Task<ActionResult> Delete(string userId)
{
// Check for for both ID and exit if not found
if (String.IsNullEmpty(userId))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var user = UserManager.Users.SingleOrDefault(u => u.Id == Userid);
// Look for user in the UserStore
// If not found, exit
if (user == null)
{
return HttpNotFound();
}
var results = await UserManager.DeleteAsync(user); // Remove user from UserStore
// If the statement is a success
if (results.Succeeded)
{
// Redirect to Users page
return RedirectToAction("Index", "Users");
}
else
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
}

How to insert a dependent record when using UserManager Identity to create users?

I'm using the Identity with UserManager Pattern.
When I need to create a new user, my Register action of Account controller has this code
var user = new WebUser() { UserName = model.Email, Email = model.Email, CreatedOn = DateTime.Now, FullName = model.Email, EmailConfirmed = true };
IdentityResult result = await RegisterService.CreateAsync(user, model.Password);
if (!result.Succeeded && ((string[])result.Errors).Length > 0)
{
foreach (var erro in result.Errors)
{
ModelState.AddModelError("", erro);
}
return BadRequest(ModelState);
}
else if (!result.Succeeded)
return InternalServerError();
For now it works, but my rule needs something specific. Every user in my database need to have a record in other table. How can I implement it?
I feel like wrong putting into the controller the rule like "if succeeded create a record into another table" because I'll need a transaction scope in the controller. It's sounds dirty to me.
Can someone help me?

How can I test methods which needs user to be logged

I'm testing some code which needs user to be logged in. When I'm trying to log in with AccountController, it's looks like everything is working, but at AccountController (IPrincipal) User is still null. How can I properly log in (or better, can I mock it somehow)?
public async Task SetupAsync()
{
var context = new DataContext();
var manager = new UserManager(new UserStore(context));
var accountController = new AccountController(manager);
var mockAuthenticationManager = new Mock<IAuthenticationManager>();
mockAuthenticationManager.Setup(am => am.SignOut());
mockAuthenticationManager.Setup(am => am.SignIn());
accountController.AuthenticationManager = mockAuthenticationManager.Object;
var user = new LoginViewModel
{
Email = "user#wp.pl",
Password = "useruser",
RememberMe = false
};
if (manager.FindByEmail("user#wp.pl") == null)
{
await manager.CreateAsync(new User { Email = "user#wp.pl", UserName = "user#wp.pl" }, "useruser");
}
await accountController.Login(user, "home/index");
_calendarController = new CalendarController(context);
}
Here I got User null exception:
public ClaimsPrincipal CurrentUser
{
get { return new ClaimsPrincipal((System.Security.Claims.ClaimsPrincipal)this.User); }
}
Edit: At return line, I have still User property null. This is sample from AccountController:
var user = await _userManager.FindAsync(model.Email, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToAction("index", "calendar");
}
You should mock your _userManager, and use a mock setup for when the method FindAsync is called. Then you return a fake user you can use later in the code
Figured it out on my own, probably not elegant solution but I'm happy anyway. #andreasnico your answer helped, thanks.
I'm mocking my custom ClaimsPrincipal, and setting up UserId - that's what I really needed.
var mockCp = new Mock<IClaimsPrincipal>();
mockCp.SetupGet(cp => cp.UserId).Returns(user.Id);
_calendarController.CurrentUser = mockCp.Object;

Correct way of setting the role for user when he is registered with Identity

I have a question, I'm new to identity, but still i would like to know what would be the correct way of assigning role to a user when he is registering?
I have here a code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
IdentityRole role = new IdentityRole("Admin");
await RoleManager.CreateAsync(role);
// Store Gender as Claim
user.Claims.Add(new IdentityUserClaim() { ClaimType = ClaimTypes.Gender, ClaimValue = "Male" });
//user.Roles.Add(new IdentityUserRole() { RoleId=role.Id, UserId=user.Id });
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//await UserManager.AddToRoleAsync(user.Id, "Admin");
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
This is just a test code, but basically if i use method UserManager.AddToROleAsync( ...) it works, BUT, it only happens after the user is added, so basically i do twice the roundtrip to database.
I tried doing it with user.Roles.Add(...) but i get an error when running it.
So my question would be what is the most efficient and correct way of doing it?
I don't know if there's a better way. I normally to it the same way as you do, first creating the role (if it doesn't exist), then creating the user, and as a last step adding the user to the role.
To use user.Roles.Add(...) the role must be present. The reason is the database (in this case Entity Framework and SQL Server). When looking closer at the Identity database you'll see that there is a relationship between the AspNetRoles and AspNetUsers table through the AspNetUserRoles table which has the UserId and the RoleId as a key. That means you can't add a user to a role when the user does not exist yet (and vice versa). So in my opinion you have to do twice the roundtrip (if you don't directly work on the context).
This works fine (Asp.Net Core Identity):
var role = await this.roleManager.FindByNameAsync( "Admin" );
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var userRole = new IdentityUserRole<int> {
RoleId = role.Id,
};
user.Roles.Add(userRole );
var result = await this.userManager.CreateAsync( user, model.Password);

Categories

Resources