ASP.NET 5 MVC 6 and Entity Framework 7 issues - c#

We can't add Owin and Entity framework 7 together. As we do so then there will be ambiguity between Microsoft.AspNet.Identity.core 2.0.0.0 and Microsoft.AspNet.Identity 3.0.0 Beta1
And hence I am not able to implement role provider in my application to manage the user roles.
After facing this issue I removed Owin references and created UserManager using
Microsoft.AspNet.Identity 3.0.0 and EF 7 but UserManager.AddToRoleAsync(user, roleName) always throws exception as below:-
InvalidOperationException: The instance of entity type 'Mozaics.DAL.Models.ApplicationUser' cannot be tracked because another
instance of this type with the same key is already being tracked. For
new entities consider using an IIdentityGenerator to generate unique
key values.
Code snippet is like this.
public async Task<ActionResult> RoleAddToUser(string UserName, string RoleName)
{
var user = context.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var result = await UserManager.AddToRoleAsync(user, RoleName );
ViewBag.ResultMessage = "Role created successfully !";
var list = context.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
ViewBag.Roles = list;
return View("ManageUserRoles");
}

#sanjaypujari
Just try that one:
var user = await context.FindByNameAsync(UserName);
ApplicationUser appuser = (ApplicationUser)user;
var result = await UserManager.AddToRoleAsync(appuser, RoleName);
When executed like this, ApplicationUser shouldn't be tracked twice.
Same thing helps, too, if you want to update a ApplicationUser.

I run to this issue. One solution that worked for me was that getting the user via the UserManager and then adding the role:
instead of
var user = context.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var result = await UserManager.AddToRoleAsync(user, RoleName );
use the following
var user = await UserManager.FindByNameAsync(UserName);
var result = await UserManager.AddToRoleAsync(user, RoleName );

Related

How to add a IdentityUser IdentityResult error in ASP.Net Core for a unique email address

My "User" class inherits from "IdentityUser" and I want to make the EmailAddress unique. BUT instead of creating a unique property like this
builder.Entity<User>()
.HasIndex(u => u.Email).IsUnique();
in the model builder that throws an exception when I try to register a duplicate email address in the method below, I'd like it to return a IdentityResult error, just like it does when I have a duplicate username. Some how Identity forgot to include a uniqueness for the email field!?
My register method where "result.Succeeded" is false if the username is taken/used and an IEnumerable of IdentityErrors, in "result.errors". I'd like to get the same type of error from a duplicate email. Is this possible?
[HttpPost("register")]
public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
{
var userToCreate = _mapper.Map<User>(userForRegisterDto);
var result = await _userManager.CreateAsync(userToCreate, userForRegisterDto.Password);
var userToReturn = _mapper.Map<UserForDetailedDto>(userToCreate);
if (result.Succeeded)
{
return CreatedAtRoute("GetUser", new { controller = "Users", id = userToCreate.Id }, userToReturn);
}
return BadRequest(result.Errors);
}
This is already supported, using RequireUniqueEmail, which defaults to false. Here’s an example of how to set it to true, taken from the docs and modified accordingly:
services.Configure<IdentityOptions>(options =>
{
options.User.RequireUniqueEmail = true;
});
You can achieve the same thing with the call to AddIdentity (or whichever variation you’re using). Here's an example of that approach:
services.AddIdentity<User, Role>(options =>
{
options.User.RequireUniqueEmail = true;
})

How to get user claims after signin through SignInManager in ASP .NET CORE Identity?

I have an ASP .NET Core 2.0 project in which I am using Microsoft's Identity framework for authentication/authorization. I have the following method that validates the user against username and password and returns claims count. The user I am trying to login is found in database but it's claims are being returned 0 here - in the database the claims do exist against the user (see the image).
[HttpPost("login")]
public async Task<object> Login([FromBody] LoginDto model)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, false);
if (result.Succeeded)
{
var appUser = _signInManager.UserManager.Users.SingleOrDefault(r => r.Email == model.Email);
var userClaims = await _signInManager.UserManager.GetClaimsAsync(appUser); // this is returning 0 claims
return Ok(HttpContext.User.Claims.Count());
}
throw new ApplicationException("INVALID_LOGIN_ATTEMPT");
}
The answers on the possible duplicate question did not solve my problem.
For UserManager.GetClaimsAsync, it will query claims from AspNetUserClaims instead of AspNetUserRoles. You could check this by GetClaimsAsync
return await UserClaims.Where(uc => uc.UserId.Equals(user.Id)).Select(c => c.ToClaim()).ToListAsync(cancellationToken);
In general, we could try HttpContext.User.Claims to retrive the claims for the user, but it will work for sub-request instead of current login request. If you move this HttpContext.User.Claims to Home Index action, it will return the expected result.
For getting claims in Login, I suggest you try
var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(appUser);
var claims = claimsPrincipal.Claims.ToList();

Asp.NET Identity Roles not working when attempting to add Role to User

I am currently adding Roles to our Database using the RoleManager with the CreateAsync(newRoleName) Method - which works correctly. But when I try to query that Role, it always returns that it doesn't exist (even though I can see it in the database).
Can anyone provide some insight on why I am not able to use the Role?
var roleExists = roleManager.RoleExistsAsync(role);
if (!roleExists.Result)
{
var newRole = new IdentityRole(role)
{
Name = role,
NormalizedName = role.ToUpper(),
};
var roleCreated = roleManager.CreateAsync(newRole);
Thread.Sleep(500); // Used to get result back first.
var roleExistsYet = roleManager.RoleExistsAsync(role);
if (!roleExists.Result)
{
// ALWAYS Returns [False]
}
}
The initial problem came about when we were creating a new User with the UserManager, and the following method would result in an error
var roleAddResult = userManager.AddToRoleAsync(newUser, "TestRole123");
Exception Error: Role [TESTROLE123] does not exist.
Note: I can see the entry for the Role 'TestRole123' (or any other role) in the Database in the table dbo.AspNetRoles.
Any insight or help is appreciated.
Environment: Visual Studio 2017, Asp.NET Core, C#
One of the issues I see - you need to use keyword await in front of *Async() methods:
var roleExists = await roleManager.RoleExistsAsync(role);
and
var roleCreated = await roleManager.CreateAsync(newRole);
etc. This will remove your need to do Thread.Sleep(500); - most likely the problem is with this line.
If you can't do async methods, use non-async versions of the methods:
var roleCreated = roleManager.Create(newRole);
I don't know how you declared your rolemanager, but following code works for me. It's configured in startup.cs and automatically creates a superuser if the roles haven't been created. Perhaps this can help you?
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
if (!roleManager.RoleExists("SuperUser"))
{
roleManager.Create(new IdentityRole("SuperUser"));
//superuser
var user = new ApplicationUser
{
UserName = " Name",
Email = "Email",
Firstname = "Firstname",
Lastname = "Lastname"
};
var pass = "AwesomePasswordOverHere";
var chkUser = await userManager.CreateAsync(user, pass);
//make superuser
if (chkUser.Succeeded)
{
await userManager.AddToRoleAsync(user.Id, "SuperUser");
}
}

userManager.AddToRoleAsync() - Error: role does not exist

I'm creating a user registration system using .NET Core, Identity Core, and MVC Core. I'm able to create users and create roles in the database.
Here's the form on the view that lets me select a user and select a role to add:
#using (Html.BeginForm("AddRoleToUser", "Roles"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>
Username : #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")
Role Name: #Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")
</p>
<input type="submit" value="Save" />
}
These drop-down lists are populated with users and roles that already exist in the database. They allow me to select Users , and the name of a role that I've already created. For example, I have a role with the name "admin", this form lets me select the string "admin".
Here's the action that handles adding a role to a user:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddRoleToUser(string UserName, string RoleName)
{
try
{
ApplicationUser user = _db.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
await _userManager.AddToRoleAsync(user, RoleName);
PrepopulateDropDownMenus();
ViewBag.ResultMessage = "Role created successfully!";
return View("Manage", "Roles");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View("Manage");
}
}
The action never adds the role to the user, and the exception reads "Role "ADMIN" does not exist." with no inner exception. I've tried turning the RoleName in the action parameters to all-caps, but it still does not find the role. I've also tried using the role ID instead of the name, which was also unsuccessful.
This exact code worked when I built this app using Identity 3.0 with MVC 6. It seems like something has changed in moving over to Identity Core.
Any thoughts?
Edit
Here's the code I'm using to populate the drop-down lists in RolesController via the Viewbag:
private void PrepopulateDropDownMenus()
{
var rolesList = _db.Roles.OrderBy(r => r.Name).ToList().Select(rr => new SelectListItem { Value = rr.Name.ToString(), Text = rr.Name }).ToList();
var usersList = _db.Users.OrderBy(u => u.UserName).ToList().Select(uu => new SelectListItem { Value = uu.UserName.ToString(), Text = uu.UserName }).ToList();
ViewBag.Roles = rolesList;
ViewBag.Users = usersList;
}
Here's how I add Identity in Startup.cs in the ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddEntityFramework()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
}
Here's the route in RolesController.cs I use to create a new role in the database:
[HttpPost]
public IActionResult Create(string rolename)
{
_db.Roles.Add(new IdentityRole()
{
Name = rolename
});
_db.SaveChanges();
ViewBag.ResultMessage = "Role created successfully!";
return RedirectToAction("Index");
}
I can't post comments yet to ask you, so, does your error say user admin does not exist, or role does not exist? I tried to duplicate your code on my end, and if the user doesn't exist you'll get a "user can't be null" error. However, if the role doesn't exist, you'll get a "Role [role] does not exist" error.
I assume that you already have the role added into your database? Here is some code I used in my seed method that essentially does what you want, minus using the views to do it:
// Add the Admin role to the database
IdentityResult roleResult;
bool adminRoleExists = await _roleManager.RoleExistsAsync("Admin");
if (!adminRoleExists)
{
_logger.LogInformation("Adding Admin role");
roleResult = await _roleManager.CreateAsync(new IdentityRole("Admin"));
}
// Select the user, and then add the admin role to the user
ApplicationUser user = await _userManager.FindByNameAsync("sysadmin");
if (!await _userManager.IsInRoleAsync(user, "Admin"))
{
_logger.LogInformation("Adding sysadmin to Admin role");
var userResult = await _userManager.AddToRoleAsync(user, "Admin");
}
EDIT
The way you're adding roles right now leaves the NormalizedName field in the Role table null, which I believe is used by the framework for adding roles to users. Try one of the following to add a role to the database instead of what you're currently doing:
var result = await _roleManager.CreateAsync(new IdentityRole(rolename));
Or this may also work (haven't tested this one though):
[HttpPost]
public IActionResult Create(string rolename)
{
_db.Roles.Add(new IdentityRole()
{
Name = rolename,
NormalizedName = rolename.ToUpper()
});
_db.SaveChanges();
ViewBag.ResultMessage = "Role created successfully!";
return RedirectToAction("Index");
}
Make sure when you are creating an AspNetRole the NormalizedName should not be null in order for the UserManager to work properly.
NormalizedName should be upper-case using .ToUpper()
Adding it straight to the database is a bad idea and violates every concept of encapsulation, and NormalizedName is not something you should be computing yourself.
See this answer
Replace this code:
var roleStore = new RoleStore<IdentityRole>(context);
await roleStore.CreateAsync(new IdentityRole(role));
with following:
var roleManager = services.GetService<RoleManager<IdentityRole>>();
await roleManager.CreateAsync(new IdentityRole(role));
This is the thing: if you are using major versions of identity (for example 6.0), the table AspNetRoles contains a Column named NormalizedName, if the string is null or differes from the role name written in capital letters you wont't be able to find the role name. You may insert manually (MMSMI) the string or delete per procedure all roles and recreate them.

How to create ApplicationUser by UserManager in Seed method of ASP .NET MVC 5 Web application

I can create users in the old way:
var users = new List<ApplicationUser> {
new ApplicationUser{PasswordHash = hasher.HashPassword("TestPass44!"), Email = "informatyka4444#wp.pl", UserName = "informatyka4444#wp.pl", SecurityStamp = Guid.NewGuid().ToString()},
new ApplicationUser{PasswordHash = hasher.HashPassword("TestPass44!"), Email = "informatyka4445#wp.pl", UserName = "informatyka4445#wp.pl", SecurityStamp = Guid.NewGuid().ToString()}
};
users.ForEach(user => context.Users.AddOrUpdate(user));
context.SaveChanges();
but I want to do it the ASP.NET MVC 5.1 way using UserManager. I peeked how the Register POST method looks in AccountController:
public async Task<ActionResult> Register(RegisterViewModel model) {
if (ModelState.IsValid) {
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded) { [...]
so I tried do the same:
var user = new ApplicationUser() { Email = "informatyka4444#wp.pl",
UserName = "informatyka4444#wp.pl"};
IdentityResult result = UserManager.CreateAsync(user, "abcwq12312!P");
but I get this:
also If I just type UserManager. VS2013 does not shows any methods on the list.
So how to add user in this way?
EDIT1:
Ok so to create user CreateAsync is unnecessary the problem was somewhere else. One should use ApplicationUserManager not UserManager(this one did not add anything to the database).
var store = new UserStore<ApplicationUser>(context);
var manager = new ApplicationUserManager(store);
var user = new ApplicationUser() { Email = "informatyka4444#wp.pl", UserName = "informatyka4444#wp.pl" };
manager.Create(user, "TestPass44!");
I dont understand the error you are showing, unless you are providing a custom TUser or TKey in which case would be like :
IdentityResult user = await UserManager.CreateAsync<CustomUser, CustomKey>(user, "abcwq12312!P");
and passing user as your CustomUser instead of ApplicationUser and maybe int if your CustomKey is an int instead of string. (CreateAsync can infer types, I posted there to show them explicitly)
The other problem I see is you are not awaiting the task, you must also add await like :
IdentityResult user = await UserManager.CreateAsync(user, "abcwq12312!P");
Hope this helps.
EDIT:
For completeness I will post the full answer from this question but there is your answer. : Unable to access CreateAsync in User Manager
var result = await UserManager.CreateAsync(user, register.Password);
The UserManager in the above statement is not a Class as I've
expected. Its a property of type UserManager<ApplicationUser>.
So, at the beginning just declared a property as
public UserManager<ApplicationUser> UserManager { get; private set; }
And now I can use the Async version for creating users. The
following statement works.
var result = await UserManager.CreateAsync(user, register.Password);
I will also flag for possible duplicate.

Categories