Seed User with custom role in EF6 code-first - c#

I am having trouble figuring out how to seed additional users and roles into my MVC5 application, using EF6 code first. In order to debug the Seed method from the Configure.cs since update-database was not working, I wrote this controller,
public ActionResult test() {
var context = new ApplicationDbContext();
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
roleManager.Create(new IdentityRole { Name = "basic" });
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var adminthere = context.Users.Any(n => n.UserName == "Admin");
var basicthere = context.Users.Any(n => n.UserName == "Basic");
// Create Dummy basic account
if (!basicthere) {
var basicUser = new ApplicationUser { UserName = "Basic" };
userManager.Create(basicUser, "test");
var _id = basicUser.Id;
userManager.AddToRole(basicUser.Id, "basic");
}
return View();
}
The debugger throws an exception at the userManager.AddToRole(basicUser.Id, "basic"); call saying "UserID not found"? Here is a screenshot including variable values from the debug session:
What is the problem? Also, the exact same code (changing the words "basic" for "Admin") works for seeding the database with the Admin user in role "admin". Why?
EDIT EDIT: moved edit I posted here previoulsy to a real answer below.

As the comments suggested I will post my this as an answer:
The line of code userManager.Create(basicUser, "test"); didn't succeed - the passwort must at least have 6 characters. So while creating the basicUser ApplicationUser instance worked (and hence the _id was not null) I didn't have an IdentityUser of that _id. On admin it succeeded previously bc. I had a different pwd that I didn't want to post here ...

Related

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 run code within Seed method during deployment?

I have a Web Api solution that makes use of ASP.NET Identity (v2.1) and Entity Framework v6.1. Inside the Seed() method of the Configuration.cs file I have code that creates my first Identity user. This code makes use of the Identity framework to hash the password, create the security stamp, etc. These are all things I cannot do via SQL so adding to the Up() method does not seem like an option.
protected override void Seed(ApplicationDbContext context)
{
// Create the admin user
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
var user = new ApplicationUser()
{
UserName = "adminuser",
Email = "adminuser#mycompany.com",
EmailConfirmed = true,
FirstName = "John",
LastName = "Does",
JoinDate = DateTime.Now.AddYears(-1)
};
manager.Create(user, "SuperSecurePassword321!");
if (roleManager.Roles.Count() == 0)
{
roleManager.Create(new IdentityRole { Name = "Admin" });
roleManager.Create(new IdentityRole { Name = "Employee" });
roleManager.Create(new IdentityRole { Name = "Customer" });
}
var adminUser = manager.FindByName("adminuser");
manager.AddToRoles(adminUser.Id, new string[] { "Admin" });
}
I need to use FTP to publish this (no control over this). Any suggestions on how to run this code once it is deployed and the database is schema is setup?
Options I have considered:
I have thought about creating an API endpoint that when called can
kick off this code, however, this endpoint would have to allow
anonymous access since it would be creating this first user and
the roles used in the system. I would then need to somehow disable
or remove this endpoint later.
Script the database and include the data and then restore that to
the database server targeted for deployment.
Seed() gets called when the database is accessed the first time. What's wrong with that automatic behavior?
If you want to call it manually, try something like this in protected void Application_Start():
Database.SetInitializer(new YourInititalizer());
var dbContext = new TheContextYouAreUsing();
dbContext.Database.Initialize(force: true);

Understanding MVC-5 Identity

I created a new ASP.NET MVC-5 application with Individual User Accounts and then updated all the Nuget packages in the solution. Now I'm trying to follow some of the guidelines shown in some tutorials but I encountered some problems.
The first one is that a class called ApplicationRoleManager which is being used throughout the application wasn't created (the ApplicationUserManager was created).
The second problem is more about Entity-Framework: I've seen that for seeding the database with a user and role many people create a static constructor in the ApplicationDbContext class:
static ApplicationDbContext()
{
Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
}
So I added it, and the implementation of the ApplicationDbInitializer is:
public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
InitializeIdentityForEF(context);
base.Seed(context);
}
//Create User=Admin#Admin.com with password=Admin#123456 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 = "admin#admin.com";
const string password = "Admin#123456";
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 };
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);
}
}
After adding everything I opened the Package Manager Console and typed Enable-Migrations, then Add-Migration someName and then Update-Database.
the results were that the database was created successfully but no data was inserted to the database.
After noticing the data wasn't inserted I moved the Seed logic to the Index method of the home controller and the data was inserted after running the application.
I also needed to add this line: app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
to the Startup.Auth.cs file.
So my questions are:
Do I really need to enter the ApplicationRoleManager class
manually?
How do I make the seed method work?
UPDATE
I've changed the Seed method to:
protected override void Seed(ApplicationDbContext context)
{
var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
//since there is no ApplicationRoleManager (why is that?) this is how i create it
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
const string name = "admin#admin.com";
const string password = "Admin#123456";
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);
}
//app hangs here...
var user = userManager.FindByName(name);
if (user == null)
{
user = new ApplicationUser { UserName = name, Email = name };
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);
}
base.Seed(context);
}
So now, the Admin role is created but when getting to var user = userManager.FindByName(name); the application hangs with no exception or any message...
When using migrations you can use the built in initializer and the Seed method:
Database.SetInitializer<ApplicationDbContext>(new
MigrateDatabaseToLatestVersion<ApplicationDbContext,
APPLICATION.Migrations.Configuration>());
and in APPLICATION.Migrations.Configuration (this was created by the Enable-Migrations command):
protected override void Seed(ApplicationDbContext context)
{
// seed logic
}
As a role manager you can also use the RoleManager<ApplicationRole> base implementation.
I also was a bit confused about hanging of application in this case. The problem can be solved in this way
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUserManager>(db));
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(db));
And for anyone using the ApplicationUser with Integer foreign key, the code is this one:
var userManager = new ApplicationUserManager(new ApplicationUserStore(context));
var roleManager = new ApplicationRoleManager(new ApplicationRoleStore(context));
This works great for default MVC 5 project.
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
It doesn't appear that the solutions posted address the issue of the app hanging on the call of userManager.FindByName(name). I'm running into the same problem. It worked a few hours ago on my local. I published to Azure and it started hanging. When I tested my local again it all of a sudden started hanging at that step. No error is returned and no timeout (at least after waiting 10-15 minutes). Does anyone have any tips to address Yoav's ultimate question?
I have some other very simple seeding processes that run before adding roles, and db.Foo.AddOrUpdate(foo) calls are running without error, but not actually saving anything to the database.
I just spent a deeply unpleasant half day dealing with this. I finally managed to get the damn thing to fire:
public static void InitializeIdentityForEF(ApplicationDbContext context)
{
context.Configuration.LazyLoadingEnabled = true;
//var userManager = HttpContext.Current
// .GetOwinContext().GetUserManager<ApplicationUserManager>();
//var roleManager = HttpContext.Current
// .GetOwinContext().Get<ApplicationRoleManager>();
var roleStore = new RoleStore<ApplicationRole, int, ApplicationUserRole>(context);
var roleManager = new RoleManager<ApplicationRole, int>(roleStore);
var userStore = new UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context);
var userManager = new UserManager<ApplicationUser, int>(userStore);
...
It's the end of an extremely long day, and I suspect someone's going to tell me why I shouldn't do this. The rest of my Seed method fires beautifully, however, using non-async methods (FindByName/Create).
Sir goobering,
You struggles have helped me get passed this problem, I had to do it a little different though.
context.Configuration.LazyLoadingEnabled = true;
//var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
//var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
const string name = "admin#example.com";
const string password = "Admin#123456";
const string roleName = "Admin";
***var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
var roleManager = new ApplicationRoleManager(new RoleStore<IdentityRole>(context));***
//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);
}

Updating a user with Asp.Net Identity - username exists

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);

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