Create IdentityUserRole in a request - c#

I'm trying to create the IdentityRole in a request, but I can't apply it to the database. Here's the code:
if (registerUser.Admin)
{
var role = await _roleManager.FindByIdAsync("Administrador");
if(role != null)
{
var userRole = new IdentityUserRole<string>
{
UserId = user.Id,
RoleId = role.Id
};
}
}
else
{
var role = await _roleManager.FindByIdAsync("25F3226654FD457E99C35B9A62B9CE3C");
if (role != null)
{
var userRole = new IdentityUserRole<string>
{
UserId = user.Id,
RoleId = role.Id
};
}
}
OBS: It's worth mentioning, when I look for these Roles I can't find them by name, but by id with you.
I will attach how I create this Role:
builder.Entity<IdentityRole>().HasData(new IdentityRole { Id="6596B380EC604E9A8708924CCCD717EC", Name= "Administrador" });
builder.Entity<IdentityRole>().HasData(new IdentityRole { Id = "25F3226654FD457E99C35B9A62B9CE3C", Name = "DefaultUser" });
Along with the code above, I created a "standard" user, and I can pass the Role to him, here's the code:
builder.Entity<IdentityUserRole<string>>().HasData(new IdentityUserRole<string> { UserId = "0CD0E173758F4492B41EDD4A51D36BA5", RoleId = "6596B380EC604E9A8708924CCCD717EC" });
So it means that I am not able to do such a process in the request only, any idea how I can do this?

Related

Seeding Users and Roles in Entity Framework Core 3

I'm changing the way i seed data on my app using entiy framework core. Previous to 2.1 version you cannot set the identity key value so I started migrating my code but now i have a problem with seeding Users and Roles from the Identity. How can i access userManager or RoleManager on my DbContext file or modelbinder extension?
Here is how i seed users and roles using a class and inject it in program.cs
public class DbInitializer
{
public static async Task Seed(ApplicationDbContext context, UserManager<User> userManager, RoleManager<Role> roleManager)
{
#region Identity
string[] roles = new string[] { "Developer", "Super Administrator", "Administrator", "User" };
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
await roleManager.CreateAsync(new Role(role));
}
}
var user = new User
{
Name = "test",
Email = "test#test.com",
NormalizedEmail = "TEST#TEST.COM",
UserName = "test",
NormalizedUserName = "TEST",
EmailConfirmed = true,
PhoneNumberConfirmed = false,
SecurityStamp = Guid.NewGuid().ToString("D")
};
if (!context.Users.Any(u => u.UserName == user.UserName))
{
var password = new PasswordHasher<User>();
var hashed = password.HashPassword(user, "development");
user.PasswordHash = hashed;
var result = await userManager.CreateAsync(user);
}
await AssignRoles(userManager, user.UserName, roles);
#endregion
}
public static async Task<IdentityResult> AssignRoles(UserManager<User> userManager, string userName, string[] roles)
{
User user = await userManager.FindByNameAsync(userName);
var result = await userManager.AddToRolesAsync(user, roles);
return result;
}
}
program file
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var isDevelopment = environment == Environments.Development;
if (isDevelopment)
{
using var scope = host.Services.CreateScope();
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ApplicationDbContext>();
var roleManager = services.GetRequiredService<RoleManager<Role>>();
var userManager = services.GetRequiredService<UserManager<User>>();
await DbInitializer.Seed(context, userManager, roleManager);//<---Do your seeding here
}
catch (Exception ex)
{
Log.Error(ex, "An error occurred while seeding the database.");
}
}
now i want to start using this instead after version 2.1
public static class ModelBuilderExtensions
{
public static void Seed(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>().HasData(
new Author
{
AuthorId = 1,
FirstName = "William",
LastName = "Shakespeare"
}
);
modelBuilder.Entity<Book>().HasData(
new Book { BookId = 1, AuthorId = 1, Title = "Hamlet" },
new Book { BookId = 2, AuthorId = 1, Title = "King Lear" },
new Book { BookId = 3, AuthorId = 1, Title = "Othello" }
);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Seed();
}
If you inherited from IdentityDbContext then you can get the users table by
modelBuilder.Entity<Users>().HasData(
new User
{
}

ASP.NET MVC 5 database update

I was initializing my website Users and Roles data in IdentityConfig.cs file and when I added a new model than mapping it to the database using code-first add-migration and update-database command, I get an empty database:
public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
InitializeIdentityForEF(context);
base.Seed(context);
}
// Create User=aadmin2018#mail.com with Admin2018#mail.com in the Admin role
public static void InitializeIdentityForEF(ApplicationDbContext db)
{
var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
const string name = "admin2018#mail.com";
const string password = "Admin2018#mail.com";
const string roleName = "Admin";
// Create role Admin if it does not exist
var role = roleManager.FindByName(roleName);
if (role == null)
{
role = new IdentityRole(roleName);
var roleresult = roleManager.Create(role);
}
var user = userManager.FindByName(name);
if (user == null)
{
user = new ApplicationUser
{
UserName = name,
Email = name,
FirstName = "Admin",
LastName = "Admin",
DateOfBirth = new DateTime(2015, 1, 1),
Address = new Address
{
AddressLine1 = "1 Admin Street",
Town = "Town",
County = "County",
Postcode = "PostCode"
}
};
var result = userManager.Create(user, password);
result = userManager.SetLockoutEnabled(user.Id, false);
}
// Add user admin to Role Admin if not already added
var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name))
{
var result = userManager.AddToRole(user.Id, role.Name);
}
// Create users role
const string userRoleName = "Users";
role = roleManager.FindByName(userRoleName);
if (role == null)
{
role = new IdentityRole(userRoleName);
var roleresult = roleManager.Create(role);
}
}
}
What should I change to the code so those data return to the database?

'Conflicting changes detected. This may happen when trying to insert multiple entities with the same key.' Entity Framework Code-First Migrations

I'm getting this message when trying to update-database.
This is my Configuration.cs file with the seeder:
internal sealed class Configuration : DbMigrationsConfiguration<MiracleMachine.data.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
context.Props.AddOrUpdate(
p => p.PropName,
new Prop() { PropName = "sharpie" },
new Prop() { PropName = "coin" },
new Prop() { PropName = "playing cards" },
new Prop() { PropName = "coffee mug" },
new Prop() { PropName = "phone" },
new Prop() { PropName = "keys" },
new Prop() { PropName = "sunglasses" },
new Prop() { PropName = "headphones" },
new Prop() { PropName = "ring" },
new Prop() { PropName = "lighter" }
);
context.SaveChanges();
context.Theories.AddOrUpdate(
t => t.TheoryId,
new Theory()
{
TheoryId = 0,
TheoryName = "Production",
TheoryDescription = "Make it appear out of nowhere!"
},
new Theory()
{
TheoryId = 1,
TheoryName = "Vanish",
TheoryDescription = "Make it vanish into thin air!"
},
new Theory()
{
TheoryId = 2,
TheoryName = "Transportation",
TheoryDescription = "Make it vanish, and then reappear somewhere impossible!"
},
new Theory()
{
TheoryId = 3,
TheoryName = "Transformation", // This uses TWO props
TheoryDescription = "Cause one of these items to change into the other item!"
},
new Theory()
{
TheoryId = 4,
TheoryName = "Multiplication",
TheoryDescription = "Magically duplicate this item again and again!"
},
new Theory()
{
TheoryId = 5,
TheoryName = "Penetration", // This uses TWO props
TheoryDescription = "Cause the two items to inexplicably pass through each other"
},
new Theory()
{
TheoryId = 6,
TheoryName = "Restoration",
TheoryDescription = "Destroy the item in some way. Restore it."
},
new Theory()
{
TheoryId = 7,
TheoryName = "Levitation",
TheoryDescription = "Make the item float in mid-air!"
});
context.SaveChanges();
//////////////////////////////////////////// The following seeds user data
// ApplicationUser table seeder
UserStore<ApplicationUser> userStore = new UserStore<ApplicationUser>(context);
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(userStore);
RoleStore<Role> roleStore = new RoleStore<Role>(context);
RoleManager<Role> roleManager = new RoleManager<Role>(roleStore);
if (!roleManager.RoleExists("Admin"))
roleManager.Create(new Role { Name = "Admin" });
if (!roleManager.RoleExists("User"))
roleManager.Create(new Role { Name = "User" });
IdentityResult result = null; // Sets the result to null. Used for error checking.
/////////// Admin (1)
ApplicationUser admin1 = userManager.FindByName("MagicRawb");
if (admin1 == null)
{
admin1 = new ApplicationUser
{
FirstName = "Rob",
LastName = "Greenlee",
UserName = "magicrawb",
Email = "magicrawb#test.com"//,
//Gender = Gender.Male
};
}
result = userManager.Create(admin1, "asdfasdf");
if (!result.Succeeded)
{
string error = result.Errors.FirstOrDefault();
throw new Exception(error);
}
userManager.AddToRole(admin1.Id, "Admin"); // Add user1 to Admin role
admin1 = userManager.FindByName("magicrawb"); // Assign user1 data to variable user1
/////////// Admin (2)
ApplicationUser admin2 = userManager.FindByName("admin2");
if (admin2 == null)
{
admin2 = new ApplicationUser
{
FirstName = "Bekah",
LastName = "Sells",
UserName = "admin2",
Email = "admin2#test.com"//,
// Gender = Gender.Female
};
}
result = userManager.Create(admin2, "asdfasdf");
if (!result.Succeeded)
{
string error = result.Errors.FirstOrDefault();
throw new Exception(error);
}
userManager.AddToRole(admin2.Id, "Admin"); // Add user1 to Admin role
admin1 = userManager.FindByName("admin2"); // Assign user1 data to variable user1
/////////// User (1)
ApplicationUser user1 = userManager.FindByName("user1");
if (user1 == null)
{
user1 = new ApplicationUser
{
FirstName = "Lance",
LastName = "Burton",
UserName = "user1",
Email = "user1#test.com"//,
//Gender = Gender.Male
};
}
result = userManager.Create(user1, "asdfasdf");
if (!result.Succeeded)
{
string error = result.Errors.FirstOrDefault();
throw new Exception(error);
}
userManager.AddToRole(user1.Id, "User"); // Add user1 to Admin role
user1 = userManager.FindByName("user1"); // Assign user1 data to variable user1
/////////// User (2)
ApplicationUser user2 = userManager.FindByName("user2");
if (user2 == null)
{
user2 = new ApplicationUser
{
FirstName = "David",
LastName = "Stone",
UserName = "user2",
Email = "user2#test.com"
//Gender = Gender.Male
};
}
result = userManager.Create(user2, "asdfasdf");
if (!result.Succeeded)
{
string error = result.Errors.FirstOrDefault();
throw new Exception(error);
}
userManager.AddToRole(user2.Id, "User"); // Add user1 to Admin role
user2 = userManager.FindByName("user2"); // Assign user1 data to variable user1
context.SaveChanges();
}
}
}
First I was using AddOrUpdate by PropId and TheoryId, but wasn't actually setting the Id's. I thought this might be the problem and changed it. I've tried deleting the migrations and the ApplicationDbContext and redoing it completely (as per another similar question I found on here) and I'm still getting the same error.
EDIT : Maybe I should include the DbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
this.Configuration.LazyLoadingEnabled = false;
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public IDbSet<Prop> Props { get; set; }
public IDbSet<Theory> Theories { get; set; }
public IDbSet<NewTrick> NewTricks { get; set; }
}

Assigning a role by using a string >> Violation of PRIMARY KEY constraint

I have the following code:
var roleEditionCNT = new Role { ApplicationName = "TTT", RoleName = "EDITION_CNT" };
var roleEditionKCD = new Role { ApplicationName = "TTT", RoleName = "EDITION_KCD" };
var roleEditionInterne = new Role { ApplicationName = "TTT", RoleName = "EDITION_INTERNE" };
var roleConsultationInterne = new Role { ApplicationName = "TTT", RoleName = "CONSULTATION_INTERNE" };
var roleConsultationExterne = new Role { ApplicationName = "TTT", RoleName = "CONSULTATION_EXTERNE" };
var roleAdministrator = new Role { ApplicationName = "TTT", RoleName = "ADMINISTRATOR" };
new List<Role>
{
roleEditionCNT,
roleEditionKCD,
roleEditionInterne,
roleConsultationInterne,
roleConsultationExterne,
roleAdministrator
}.ForEach(b => context.Roles.AddOrUpdate(m => m.RoleName, b));
Then I can do:
var myUser = new User
{
Company = "DELTOY",
FirstName = "BRYAN",
LastName = "KENETH",
Roles = new List<Role> { roleEditionCNT }
};
Now I would like to modify the way I assign roles like this:
var myUser = new User
{
Company = "DELTOY",
FirstName = "BRYAN",
LastName = "KENETH",
Roles = new List<Role> { new Role { ApplicationName = "TTT", RoleName = "EDITION_CNT" } }
};
This code compiled successfully but at runtime I got the error:
Violation of PRIMARY KEY constraint 'PK_Roles'. Cannot insert
duplicate key in object 'dbo.Roles'
By simply modifying the above code, it seems the system is trying to add a new record to the table Roles. How can I simply assign Role but not using the variable. I prefer to give rolename with a string.
Any idea?
In the second example you are trying to add a User with a new Role as opposed to assigning it to an existing Role. The Role you are trying to add already exists in the Roles table.
You can get the Role object into a variable like.
var role = context.First(p => p.RoleName == "EDITION_CNT");
and then assign it to the new User.
var myUser = new User
{
Company = "DELTOY",
FirstName = "BRYAN",
LastName = "KENETH",
Roles = new List<Role> { role }
};

Entity Framework Deep Query Many to Many

New to Entity Framework, trying to figure out some stuff. I have tables as listed below:
Users
---------
UserID
UserName
Roles
---------
RoleID
RoleName
UserRoles
---------
UserRoleID
UserID
RoleID
I am using a repository pattern. here's an example of a repository (they're all essentially the same)
public class RoleRepository : IRoleRepository
{
private AuthorizationContext context = new AuthorizationContext();
public IQueryable<Role> Roles
{
get
{
return this.context.Roles;
}
}
public bool Save(Role pRole)
{
if (pRole.RoleID == 0 || pRole.RoleID == null)
{
context.Roles.Add(pRole);
}
context.SaveChanges();
return true;
}
public bool Delete(Role pRole)
{
context.Roles.Remove(pRole);
context.SaveChanges();
return true;
}
}
Now, I want to test to see if a user (by UserName) belongs to a role (by RoleName). How can I query? I expected it to be something like this, but it doesn't work:
public bool IsUserInRole(string username, string roleName)
{
var repo = new UserRepository();
var user = repo.Users.FirstOrDefault(u => u.NetID == username && u.UserRoles.FirstOrDefault(r => r.Role.Name == roleName));
}
How can I query to see if the user belongs to the role? I would prefer to use predicates if possible.
I would use the .Any function like this:
public static bool IsUserInRole(string username, string roleName)
{
using(var roleRepository = new RoleRepository())
{
return roleRepository.Roles.Any(r => r.RoleName == roleName && r.UserRoles.Any(ur => ur.User.UserName == username));
}
}
Here is a sample Console Application:
class Program
{
static void Main(string[] args)
{
var users = new List<string> { "A", "B", "C", "D" };
var roles = new List<string> { "User", "Admin", "Superuser"};
//User A has roles: User, Admin, Superuser
Debug.Assert(IsUserInRole(users[0], roles[0]) == true);
Debug.Assert(IsUserInRole(users[0], roles[1]) == true);
Debug.Assert(IsUserInRole(users[0], roles[2]) == true);
//User B has roles: User, Admin
Debug.Assert(IsUserInRole(users[1], roles[0]) == true);
Debug.Assert(IsUserInRole(users[1], roles[1]) == true);
Debug.Assert(IsUserInRole(users[1], roles[2]) == false);
//User C has roles: User
Debug.Assert(IsUserInRole(users[2], roles[0]) == true);
Debug.Assert(IsUserInRole(users[2], roles[1]) == false);
Debug.Assert(IsUserInRole(users[2], roles[2]) == false);
//User D has no roles
Debug.Assert(IsUserInRole(users[3], roles[0]) == false);
Debug.Assert(IsUserInRole(users[3], roles[1]) == false);
Debug.Assert(IsUserInRole(users[3], roles[2]) == false);
Debugger.Break();
}
public static bool IsUserInRole(string username, string roleName)
{
using(var roleRepository = new RoleRepository())
{
return roleRepository.Roles.Any(r => r.RoleName == roleName && r.UserRoles.Any(ur => ur.User.UserName == username));
}
}
}
public interface IRoleRepository : IDisposable
{
}
public class RoleRepository : IRoleRepository
{
private Context context = new Context();
public IQueryable<Role> Roles
{
get
{
return this.context.Roles.AsQueryable<Role>();
}
}
public void Dispose()
{
//Do nothing
}
}
public class Context : IDisposable
{
public IList<User> Users { get; set; }
public IList<Role> Roles { get; set; }
public IList<UserRole> UserRoles { get; set; }
public Context()
{
//Generate Some Fake Data
Users = new List<User>();
Users.Add(new User { UserID = 1, UserName = "A" });
Users.Add(new User { UserID = 2, UserName = "B" });
Users.Add(new User { UserID = 3, UserName = "C" });
Users.Add(new User { UserID = 4, UserName = "D" });
Roles = new List<Role>();
Roles.Add(new Role { RoleID = 1, RoleName = "User" });
Roles.Add(new Role { RoleID = 2, RoleName = "Admin" });
Roles.Add(new Role { RoleID = 3, RoleName = "Superuser" });
UserRoles = new List<UserRole>();
UserRoles.Add(new UserRole(1, Users[0], Roles[0]));
UserRoles.Add(new UserRole(1, Users[0], Roles[1]));
UserRoles.Add(new UserRole(1, Users[0], Roles[2]));
UserRoles.Add(new UserRole(1, Users[1], Roles[0]));
UserRoles.Add(new UserRole(1, Users[1], Roles[1]));
UserRoles.Add(new UserRole(1, Users[2], Roles[0]));
//User A has roles: User, Admin, Superuser
//User B has roles: User, Admin
//User C has roles: User
//User D has no roles
}
public void Dispose()
{
//Do nothing
}
}
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public IList<UserRole> UserRoles { get; set; }
public User()
{
UserRoles = new List<UserRole>();
}
}
public class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
public IList<UserRole> UserRoles { get; set; }
public Role()
{
UserRoles = new List<UserRole>();
}
}
public class UserRole
{
public int UserRoleID { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
public UserRole(int id, User user, Role role)
{
UserRoleID = id;
UserId = user.UserID;
User = user;
user.UserRoles.Add(this);
RoleId = role.RoleID;
Role = role;
role.UserRoles.Add(this);
}
}
Here is the modified "IsUserInRole" API that you already created :
public bool IsUserInRole(string username, string roleName)
{
var repo = new UserRepository();
return repo.Users.Any(u => u.UserName == username && u.UserRoles.Any(userrole => userrole.Role.RoleName == roleName));
}
The problem with your API was the FirstOrDefault, which restricts the navigation properties.

Categories

Resources