how to delete users including roles and users from AspnetRoleUsers - asp.net-core

I am making a project using asp.net core 3.1 and I can't find the right source of deleting users including roles in Asp.net core 3.1 using Web.api
This is the code I have tried but seems like not appropriate but haven't tried yet. Do you have any ideas of how to realize that?
I want to appropriately check the error using Web Api functions such as statuscode or any error messages to the frontend.
[HttpPost, ActionName("Delete")]
public async Task<ActionResult> DeleteUser(string id)
{
var user = await _userManager.FindByIdAsync(id);
var rolesForUser = await _userManager.GetRolesAsync(user);
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);
}
}
await _userManager.DeleteAsync(user);
return OkResult(result);
}

You don't need to loop the roles and delete , you can use RemoveFromRolesAsync :
public virtual Task<IdentityResult> RemoveFromRolesAsync(TUser user, IEnumerable<string> roles);
And each operation will return IdentityResult which could be used to check the operation status :
if (User.Identity.IsAuthenticated)
{
try
{
var user = await _userManager.FindByIdAsync(id);
var roles= await _userManager.GetRolesAsync(user);
var result = await _userManager.RemoveFromRolesAsync(user, roles);
if (result.Succeeded)
{
var resultdelete = await _userManager.DeleteAsync(user);
if (result.Succeeded)
{
return Ok();
}
else
{
List<string> errors = new List<string>();
foreach (var error in result.Errors)
{
errors.Add(error.Description);
}
return BadRequest(errors);
}
}
else
{
List<string> errors = new List<string>();
foreach (var error in result.Errors)
{
errors.Add(error.Description);
}
return BadRequest(errors);
}
}
catch (Exception exception)
{
List<string> errors = new List<string>() { exception.Message };
return StatusCode(StatusCodes.Status500InternalServerError, errors);
}
}
But use database stored procedures with transaction is always a good choice .

Related

Couldn't avoid NullReferenceException in Action Filter (ASP.NET Core)

I'm writing an action filter for setting LastAccessDate user property. On retrieving user's record from DB, i'm getting NullReferenceException. How to get rid of this exception? Here is my Action Filter:
public class LogActivity : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
var id = int.Parse(resultContext.RouteData.Values["id"].ToString());
var repo = resultContext.HttpContext.RequestServices.GetService<UserRepo>();
Console.WriteLine(id);
// var user = await repo.GetRespondent(id);
var user= repo.GetRespondent(id).Result; <========= Here Exception occurs
if (user != null)
{
user.LastAccessDate = DateTime.Now;
await repo.SaveAll();
}
}
}
Here is my UserRepo repository's get method:
public async Task<User> GetRespondent(int id)
{
var user= await _context.User.FirstOrDefaultAsync(u => u.Id == id);
if (user!= null)
return user
return null;
}
Replace this line
var user= repo.GetRespondent(id).Result; <========= Here Exception occurs
with
var user = await repo.GetRespondent(id);

change phone number in asp identity

I have problem with updating of phone number in my ASP net core application.
All fields except phone number are saving in DB. I tried 3 different ways to update phone:
set manualy
use UserManager.SetPhoneNumberAsync()
use UserManager.ChangePhoneNumberAsync() with token generation
All of them are not working. And there are no any errors. Help me please
[HttpPost][AllowAnonymous]
public async Task UpdateLogin(UpdateAccountRequest request)
{
try {
var user = await UserService.FindExistingUserAsync(request.CurrentEmail, request.CurrentPhoneNumber);
var account = user.Accounts.SingleOrDefault(x = > x.AccountId == request.AccountId);
account.FirstName = request.PatientFirstName;
account.LastName = request.PatientLastName;
var changePhoneNumberToken = await UserManager.GenerateChangePhoneNumberTokenAsync(user, request.UpdatedPhoneNumber);
var changePhoneResult = await UserManager.ChangePhoneNumberAsync(user, request.UpdatedPhoneNumber, changePhoneNumberToken);
if (!changePhoneResult.Succeeded) {
return StatusCode(StatusCodes.Status500InternalServerError, changePhoneResult.Errors);
}
var updateResult = await UserManager.UpdateAsync(user);
if (!result.Succeeded) {
return StatusCode(StatusCodes.Status500InternalServerError);
}
return Ok("User updated");
}
catch (Exception ex) {
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
}
Problem disappeared. Loks like DB was not updated

Update existing table row in the same method that uses HttpPost to add a new entry

I have a web game that uses .NetCore Entity Framework.
I have one method that uses HttpPost to create a new Monster in the database.
This method also needs to add a foreign key, the new MonsterId, to an existing Dungeon in the table called DungeonList.
I got the part where the method creates a new Monster correctly.
However I'm not sure how to insert the new MonsterId into the appropriate Dungeon of DungeonList.
I'm not exactly sure how to get the Id of the Dungeon.
Should I pass in the DungeonId from the frontend?
I'm really confused.
Here is what I have so far but I am not sure where to go from here.
I'd love some advice...thank you!
[HttpPost]
public async Task<ActionResult<MonsterList>> PostMonsterList(MonsterList monsterList)
{
monsterList.MonsterId = Guid.NewGuid();
_context.MonsterList.Add(monsterList);
var dungeonListRef = new DungeonList();
if(dungeonListRef.MonsterId == null)
{
// ????
}
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (MonsterListExists(monsterList.MonsterId))
{
return Conflict();
}
else
{
throw;
}
}
_context.DungeonList.Add(dungeonListRef);
return CreatedAtAction("GetMonsterList", new { id = monsterList.MonsterId }, monsterList);
}
Add Dungeon drop down list in your "Add new Monster" page. Send drop down list's dungeonID to PostMonsterList function.
[HttpPost]
public async Task<ActionResult<MonsterList>> PostMonsterList(Guid dungeonId, MonsterList monsterList)
{
Guid newMonsterId = Guid.NewGuid();
monsterList.MonsterId = newMonsterId;
_context.MonsterList.Add(monsterList);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (MonsterListExists(monsterList.MonsterId))
{
return Conflict();
}
else
{
throw;
}
}
var dungeonList = _context.DungeonList.Where(x => x.DungeonId == dungeonId).FirstOrDefault();
dungeonList.MonsterId = newMonsterId;
_context.DungeonList.Update(dungeonList);
await _context.SaveChangesAsync();
return CreatedAtAction("GetMonsterList", new { id = monsterList.MonsterId }, monsterList);
}

how to delete identity users on delete cascade?

I am building an application using ASP.NET CORE 3.1 and built identity using built in funcations. When I delete or update I want to delete users and related entities from aspnetuserroles and aspnetusers.
I made an update users but seems verbose and I cannot make it work yet with a postman error.
Error
405 Method not allowed
I can sort this error out but I think the code is too verbose. Do you have any examples or a better way to do this?
Postman request
{
"email":"user#gmail.com",
"password":"Passw0rd",
"username":"user4",
"roles":["user"],
"firstname":"user",
"lastname":"Lee",
"phonenumber":"12345"
}
postman url
https://localhost:4200/api/accounts/05ce20c6-e2c4-4d40-b364-85c03206d562
Update Users
[Route("accounts/{id}")]
[HttpPut]
public async Task<IActionResult> UpdateUser(string id, [FromBody] RegistrationViewModel model)
{
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
var user = await _userManager.FindByIdAsync(id);
if (user == null)
{
return NotFound();
}
var userRoles = await _userManager.GetRolesAsync(user);
IdentityResult roleRemoveResult = await _userManager.RemoveFromRolesAsync(user, userRoles);
if (!roleRemoveResult.Succeeded)
{
ModelState.AddModelError("", "Failed to remove roles");
return BadRequest(ModelState);
}
IdentityResult roleAddResult = await _userManager.AddToRolesAsync(user, model.Roles);
if (!roleAddResult.Succeeded)
{
ModelState.AddModelError("", "Failed to add roles");
return BadRequest(ModelState);
}
//finished the role removing and assinging new roles
IdentityResult passwordResult = await _userManager.ChangePasswordAsync(user, user.PasswordHash, model.Password);
user.Email = model.Email;
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.PhoneNumber = model.PhoneNumber;
user.UserName = model.UserName;
IdentityResult updateUser = await _userManager.UpdateAsync(user);
if (!updateUser.Succeeded)
{
ModelState.AddModelError("", "Failed to update a user");
return BadRequest(ModelState);
}
var newUser = new User_Role_ViewModel();
newUser.Id = id;
newUser.Email = model.Email;
newUser.FirstName = model.FirstName;
newUser.LastName = model.LastName;
newUser.UserName = model.UserName;
newUser.Roles = model.Roles;
newUser.PhoneNumber = model.PhoneNumber;
return Ok(newUser);
}

Invalid token in reset password of Asp.Net web api

I'm working on a project using Asp.NET web api, and my authentication system is based on identity 2.0. When user sends the ResetPassword form, he gets "Invalid token"
this is my forgotpassword method
public async Task<HttpResponseMessage> ForgotPassword(ForgotPasswordViewModel model)
{
if (!ModelState.IsValid)
{
HttpError error = new HttpError(ModelState, false);
error.Message = Resource.No_Item_Found_Message;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
HttpError error = new HttpError();
error.Message = Resource.Process_Failed;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
var provider = new DpapiDataProtectionProvider("ECommerceWebApp");
UserManager.UserTokenProvider = new DataProtectorTokenProvider<ECommerceUser, string>(provider.Create("UserToken"));
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
code = HttpUtility.UrlEncode(code);
try
{
// var callbackUrl = new Uri(Url.Link("ResetPasswordRoute", new { userId = user.Id, code = code, newPassword = model.Password }));
var callbackUrl = Url.Link("Default", new { Controller = "Account", action = "ResetPassword", userId = user.Id, code = code });
await UserManager.SendEmailAsync(user.Id, "تغییر رمز عبور در IRI1", "<div style='font-family:tahoma;direction:rtl;text-align:right;font-size:12px;'>" + "<h3>اولین و بزرگترین مرکز دادوستد بدون واسطه در ایران و کشورهای همسایه</h3>لطفاً با کلیک بر روی گزینۀ تغییر رمز به صفحۀ مربوطه بروید : <br/><br/>تغییر رمز عبور <br/><br/><br/><a href='iri1.com'>Iri1 Web Sites</a>" + "</div>");
}
catch (Exception ex)
{
HttpError error = new HttpError();
error.Message = ex.Message;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
return Request.CreateResponse(Resource.Reset_Password_Message_Client);
}
and this is my ResetPassword method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
var code = HttpUtility.UrlDecode(model.Code);
var result = await UserManager.ResetPasswordAsync(user.Id, code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
AddErrors(result);
return View();
}
I still get invalid token error
I've just begun learning Identity Authentication and have no way to run samples from the Internet(I've got no visual studio). But I've noticed this method from GidHub samples, which seems to me to be wrong:
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
return code == null ? View("Error") : View();
}
In my humble opinion this method should do this:
return code == null ? View("Error") : View(new ResetPasswordViewModel{Code = code});
And thus the hidden field in ResetPassword view contains the Code. When the user clicks the submit button this code will be posted with the email and password to the httppost ResetPassword action where you can access the code thus: model.Code
Now I hope you've got a valid token