Create user in ASP.NET Core - c#

I try to add list of users with seedata. But only the Admin is added from this list, which is the first in the list. Maybe you know another method?
if (!_roleManager.RoleExistsAsync(SD.Role_Admin).GetAwaiter().GetResult())
{
_roleManager.CreateAsync(new IdentityRole(SD.Role_Admin)).GetAwaiter().GetResult();
_roleManager.CreateAsync(new IdentityRole(SD.Role_User)).GetAwaiter().GetResult();
// Create Admin
_userManager.CreateAsync(new ApplicationUser
{
UserName = "admin#gmail.com",
Email = "admin#gmail.com",
Name = "Admin",
PhoneNumber = "+380000000000",
StreetAddress = "Street 2",
State = "State",
PostalCode = "100000",
City = "City Name"
}, "Admin123*").GetAwaiter().GetResult();
ApplicationUser user = _db.ApplicationUsers.FirstOrDefault(u => u.Email == "admin#gmail.com");
_userManager.AddToRoleAsync(user, SD.Role_Admin).GetAwaiter().GetResult();
// Create User1
_userManager.CreateAsync(new ApplicationUser
{
UserName = "user#gmail.com",
Email = "user#gmail.com",
Name = "User",
PhoneNumber = "+3801111111",
StreetAddress = "Street 2",
State = "State",
PostalCode = "10000",
City = "Cuty Name"
}, "User123*").GetAwaiter().GetResult();
ApplicationUser user1 = _db.ApplicationUsers.FirstOrDefault(u => u.Email == "user#gmail.com");
_userManager.AddToRoleAsync(user1, SD.Role_User).GetAwaiter().GetResult();
}
I get this error :
It will be interesting to hear the opinion of other methods of seedusers

You should always the async and await keywords when using Async methods and use them all the way up, otherwise you should not use them.
You are calling an asynchronous operation and blocking on it synchronously with task.GetAwaiter().GetResult() which not only makes it very complicated but also not asynchronous and may lead to deadlocks.
What you might solve your issue is to change the seeding method to async and await the Add and Create methods.

Related

_UserManager.CreateAsync() returns sucess but does not save the user on database

I am building a web app in .Net Core 3.0 and everything is running smooth but I found a small issue:
I have a method to create a user in a controller that runs well, saves the user and its all ok.
But I have the need to have another method in another controler that can also create users, and this method is copy / paste from the other working method that works, uses the same UserManager that is IOC'ed, it returns sucess, but at the end the user is not in the database.
This has to be in another method as this one if for creating users for other people, where the password is auto generated. The password passes and does not give any error on the createAsync() and it complies with the settings in the startup.cs file
I have changed the method, tryed to stimulate the EF context, to check if it was something on it, but no....
[HttpPut]
[Authorize(Roles = "Admin")]
[Route("CreateEmployee")]
public async Task<IActionResult> CreateEmployee([FromQuery]string email)
{
var user = new IdentityUser { UserName = email, Email = email };
var pw = UserHelper.GenerateRandomPassword(10);
var userResult = await _UserManager.CreateAsync(user, pw);
var resultRole = await _UserManager.AddToRoleAsync(user, "Employee");
var code = await _UserManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
EmailSender sender = new EmailSender();
await sender.SendWelcomeEmailAsync("Email Header",
new NewUserData { ConfirmUrl = callbackUrl, Password = pw, Email = email, Username = $"" });
}
Inspecting the object userResult :
userResult .succeded = true
uuserResult er.Errors.Count = 0
Inspecting the object resultRole :
resultRole.succeded = true
resultRole.Errors.Count = 0

Why ChangePhoneNumber always returns wrong code?

I'm trying to restore password using UserManager and GenerateChangePhoneNumberTokenAsync method.
After trying to confirm that token by ChangePhoneNumberAsync but each time I receive the error about wrong code.
I tried different conditions and each time receiving the same error.
Generating token
var token = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.Username);
Confirming token
var verified = await _userManager.ChangePhoneNumberAsync(user, model.Phone, model.Token);
Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.SignIn.RequireConfirmedPhoneNumber = true;
config.Tokens.ChangePhoneNumberTokenProvider = "Phone";
})
Phone and username are the same.
var user = new ApplicationUser
{
Email = $"{_templateCustomerEmail}{(_context.Users.Count() + 1)}#{_appSettings.Domain}",
DateSignUp = DateTime.UtcNow,
FullName = model.FullName,
Id = Guid.NewGuid().ToString(),
PhoneNumber = model.Username,
EmailConfirmed = true,
PhoneNumberConfirmed = false,
UserName = model.Username
};
I expected really easy set up of these stuff. Unfortunately faced with kind a dummy issue.
Maybe issue is in method names or something else.
You have to call SetPhoneNumberAsync method before GenerateChangePhoneNumberTokenAsync. this is very important point.
I don't know how is your code.
this works.
await _userManager.SetPhoneNumberAsync(user, $"{model.CountryCode}{model.PhoneNumber}");
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
this does not work.
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
await _userManager.SetPhoneNumberAsync(user, $"{model.CountryCode}{model.PhoneNumber}");
Because it is using SecurityStamp for validation so every update query changes it.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.generatechangephonenumbertokenasync?view=aspnetcore-2.2
GenerateChangePhoneNumberTokenAsync takes a user and the phone number. You're giving it user and username, so when you try to change it (confirm the token), you're trying to match a phone number to a username which doesn't match so it gives an error.

Prevent collision on multiple database calls in Web API

I have a table of random unique number that they served as account Id for a user.
This scenario will use in Register method of Web API to get first unique Number and attached it into a user and after a successful creation, the fetched unique Number will be removed from database:
public async Task<ActionResult> Register([FromBody] RegisterDto model)
{
//get the first unique number from the database
var UniqueNumber = _context.UniqueNumbers.First();
var user = new User
{
UserName = model.Email,
Email = model.Email,
PhoneNumber = model.PhoneNumber,
FirstName = model.FirstName,
LastName = model.LastName,
UserProfile = new UserProfile()
{
AccountNumber = UniqueNumber.Number,
},
};
//creating user
var createResult = await _userManager.CreateAsync(user, model.Password);
if (!createResult.Succeeded) return BadRequest(new { isSucceeded = createResult.Succeeded, errors = createResult.Errors });
//Delete the fetched UniqueId from the database
_context.UniqueNumbers.Remove(UniqueNumber);
_context.SaveChanges();
return Ok(new
{
isSucceeded = true
});
}
My question is how do I prevent collision in multiple calls on API since it may return same unique number for multiple calls?
On EF Core and Microsoft SQL Server you should simply use a SEQUENCE object to generate your keys. See Sequences - EF Core
If really, really want to proceed with your original design you could use FromSql to run a DELETE … OUTPUT, something like:
var UniqueNumber = _context.UniqueNumbers.FromSql("delete top (1) from UniqueNumbers output deleted.*").Single();

Identity: Why is user.roles empty?

I have a method that gets all the users that i have in my db, simply put i do this:
var allUsers = context.Users.ToList();
What i can't figure it out is that when i debug the roles property it is empty:
but in dbo.UserRoles:
What am I missing here?
EDIT:
My registration method:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
UserManager.AddToRole(user.Id, model.UserRole.ToString());
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return PartialView("~/Views/Account/Register.cshtml",model);
}
EDIT 2:
When getting the roles like this:
var roles = context.Roles.ToList();
I can see all the roles and I can also see which users have the specific role:
EDIT 3:
Tried turning lazyloading off and on
this.Configuration.LazyLoadingEnabled = true;
this.Configuration.LazyLoadingEnabled = false;
Still doesn't give me the roles data.
You have to load related entities you want to use with Include like this :
var allUsers = context.Users.Include(u => u.Roles).ToList();
Then you should be able to access user roles.
More info about that topic here
So far I have not been able to solve this they way I want. I made a work arround that works:
I created a method that got me each individual user role like so:
public string GetRole(string userId)
{
var role = UserManager.GetRoles(userId);
return role[0];
}
and in my original Getuser method i called the my recently developed method:
public UserModel GetUsers()
{
var allUsers = context.Users.Include("Roles").ToList();
var model = new UserModel
{
Users = allUsers.Select(x => new OverWatchUser
{
Email = x.Email,
EmailConfirmed = x.EmailConfirmed,
FirstName = x.FirstName,
LastName = x.LastName,
OrgId = x.OrgId,
Role = GetRole(x.Id)
}).ToList()
};
return model;
}
This gives me the data I want but I consider this a dirty fix and I hope someone out there has a proper solution to the problem.
You can use context.Roles instead of context.Users as follows and filter the target user roles. The trick is to filter the target user roles in the where method.
string Id="the_required_user_Id";
var roles = context.Roles
.Include(r => r.Users)
.Where(r => (r.Users.Select(u => u.UserId).Contains(Id)))
.ToList();
This worked fine for me, hopefully this helps someone

How to create a user and get the newly created ID with ASP.NET Identity

I am new to the ASP.NET Identity framework and am trying to do some things that I used to do in the older FormsAuthentication framework.
What I want to do is allow an administrative user to create a new user using the existing Register view (or similar) from within the app. Once this is complete, I would like to relationally associate that user (possibly using the ID that is generated) to other areas of the system.
How do I get access to the ID that is generated when calling UserManager.CreateAsync()?
EDIT: I am wanting existing users with "administrative" roles to create users from within the system in a User Management area. The answers below so far have explained how to get the ID for the "current" user which is not what I am looking for.
Using the IdentityUser or using a class that inherits from IdentityUser, makes the model having an UserId attribute. Using following code, passing the user to the method, will fill up the Id.
var user = model.GetUser();
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
result = UserManager.AddToRole(user.Id, "User");
The model.GetUser() returns an object of the ApplicationUser or IdentityUser
public ApplicationUser GetUser()
{
var user = new ApplicationUser
{
UserName = UserName,
FirstName = FirstName,
LastName = LastName,
Email = Email,
...
};
return user;
}
The accepted answer was not clear to me so I thought I would share this.
If you look at the source for the IdentityUser class you will find the following.
public class IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
{
/// <summary>
/// Constructor which creates a new Guid for the Id
/// </summary>
public IdentityUser()
{
this.Id = Guid.NewGuid().ToString();
}
... code omitted
}
As you can see, when creating a new IdentityUser instance the constructor generates a new GUID and populates the Id field.
This means if you create a new instance of a derived class such as ApplicationUser a new Id will still automatically be generated for you.
So, after you check that the user has been successfully added you can safely use the Id in the ApplicationUser class for your data association.
Example.
var user = new ApplicationUser
{
UserName = "franko",
FirstName = "Frank",
LastName = "Ouimette",
Email = "franko#emailservice.com"
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded){
result = UserManager.AddToRole(user.Id, "User");
// User added successfully, you can safely use the Id now.
var id = user.Id;
}
What worked for me was something slightly different:
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var user = new ApplicationUser() { Email = "informatyka4444#wp.pl", UserName = "informatyka4444#wp.pl" };
var result = manager.Create(user, "TestPass44!");
if (result.Succeeded)
{
string newId = user.Id;
}
Some extension methods have been added to the Identity framework, including this one:
public static string GetUserId(this IIdentity identity);
After performing the sign-in, you should be able to retrieve the ID easily enough:
await SignInAsync(user, isPersistent: false);
var id = this.User.Identity.GetUserId()
This thread is already a few years old, but I encountered this problem and needed to find another solution because I do not use the provided Guids, but a standard integer ID, provided by the database (auto-incremented index).
The problem that I had was that if I created the user with UserManager.CreateAsync, the user object wasn't updated with the ID. I then created a related object for that user, and since the ID wasn't updated, Entity Framework tried to save the user to the database another time which resulted in a primary key violation.
To solve the problem, I needed to read/update the user object like so:
var user = new User
{
UserName = UserName,
FirstName = FirstName,
LastName = LastName,
Email = Email,
...
};
var result = await UserManager.CreateAsync(user, model.Password);
// At this point, the user has been created, but the ID not set
// Read the full user record from the database
user = db.Users.Where(u => u.Email == user.Email).FirstOrDefault();
// At this point, the user has the correct ID set, we are good to go...
In the event for user created, add:
string user = RegisterUser.UserName; or to use later
Session["user"] = RegisterUser.UserName;

Categories