Select MVC Membership usernames to list - asp.net-mvc

I am trying to select all usernames in MVC membership provider into a queryable list to plug into a function that checks if a given username exists and modifies it by adding a number at the end if it is so. I am struggling to get the list. I am not sure if what I am trying to achieve is achievable.
So far this is what I have come up with as below
var allusers = (from MembershipUser u in Membership.GetAllUsers()
select new
{
Uname = u.UserName
}).ToList();
But It does not work and gives the error
cannot convert from 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<string>'
I have realised that the error goes away only when the below code is in place.
private string GetUniqueSlug(string Uname, object allusers)
{
throw new NotImplementedException();
}
But this is the function that is supposed to be evaluated
//unique username for autogenerate
private string GetUniqueSlug(string Uname, List<string> allusers)
{
var slug = Uname.ToSeoUrl();
return allusers.Any(s => s == slug)? GetUniqueSlugInternal(slug, allusers) : slug;
}
When the condition is triggered to generate a new uname, the not implemented step gets the focus

It worked with this instead
List<string> allusers = (from MembershipUser c in Membership.GetAllUsers()
select new { UserName = c.ToString() }).Select(t=>t.UserName).ToList();

Related

Getting Profile ID of User from his Jobs using Sessions and LINQ

As the title says. I have a page with a Job that have an ID. This ID I am storing in a Session and when I am trying to access the Company profile I just test if the Session Variable with Job ID from the tables Jobs and then I am trying to select the User ID and then with this User ID I search in UserManager and try to populate the page with some data.
Code For Company Profile:
public async Task<ActionResult> Details(string id)
{
String JobValID = Convert.ToString(Session["DetailsURL"]);
var UserJobID = context.Jobs.Where(x => x.ID.ToString() == JobValID).OrderByDescending(x => x.UserID).Select(x => x).ToString();
UserJobID = id; //This line is to see what value I got from LINQ and is still the Session value.
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var user = await UserManager.FindByIdAsync(id);
return View(user);
}
View For this Controller is default scaffolded View from controller.
And like This I get Session["DetailsURL"]
var currentID = Url.RequestContext.RouteData.Values["id"];
Session["DetailsURL"] = currentID;
I guess this is not the standard way to get a User Profile page. But I am using an ActionLink from Job Page to get into the Company Profile.
Here ActionLink to get from JobPage to Company Profile:
#Html.ActionLink("About this company", "Details", "UserAdmin", new { id = Session["UserJobID"] }, null)
My problem is in LINQ statement, when I am trying to select UserID, it doesn't get the right value, and when I am searching in UserManager the value is still the session Value.
Found the solution here
So how I did it:
var UserJobId = (from c in context.Jobs
where c.ID == JobValID
select new { c.UserID }).Single();
var myVal = UserJobId.UserID;
id = myVal;
It has been awhile since I have used C#, but your LINQ statement seems to be getting a list of Job objects and doing ToString on the list. If Job has reference to the UserId associated with it, then the following LINQ statement should work:
var userId = context.Jobs
.SingleOrDefault(x => x.ID.ToString() == jobId)
.?Select(j => j.<accessorToUserId>) // Not sure what your schema is
.?ToString()
Notice the ?. This is just in case SingleOrDefault returns null then the following method calls won't happen. If, for some reason, more than one Job uses that jobId, which is really bad practice, replace SingleOrDefault with FirstOrDefault.
Also, Select is supposed to be used to map from type T to type U. Doing Select(x => x) is pointless since you are simply doing T -> T.

How to get list of all ApplicationUsers who are in certain Role from database by LINQ expression?

I want to get:
list of ApplicationUsers who are in role "NormalUser" to anybody
list of all ApplicationUsers only to Admins only.
I did this:
// GET: ApplicationUsers
public ActionResult Index() {
// if you are Admin you will get all users
if (User.IsInRole("Admin"))
return View(db.Users.ToList());
//if you are somebody else(not Admin) you will see only list of NormalUsers
//HERE I GET ERROR
var list = db.Users.Where(x => UserManager.IsInRole(x.Id, "NormalUser")).ToList(); // here I get error
return View(list);
}
UserManager inside code above is: UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
But unfortunately my LINQ expresiion is incorrect. I get error:
LINQ to Entities does not recognize the method 'Boolean IsInRole[ApplicationUser,String](Microsoft.AspNet.Identity.UserManager`2[WebApplication2.Models.ApplicationUser,System.String], System.String, System.String)' method, and this method cannot be translated into a store expression.
Question: How to correctly get list of users who are in role "NormalUser"?
The UserManager.IsInRole function isn't supported at the database, but if your application can bear the weight of pulling the whole User table back from the database before applying your filter then you can just add a ToList between your Users table reference and your Where filter, i.e.
var list = db.Users.ToList().Where(x => UserManager.IsInRole(x.Id, "NormalUser")).ToList();
I reached here for a good quick answer but could not find one. So decided to put on what I got for any other visitor who comes here. To get the List of Users in any particular Role, one can use this code.
public async Task<ActionResult> Index()
{
List<ApplicationUser> appUsers=new List<ApplicationUser>();
await Task.Run( () =>
{
var roleManager = new RoleManager<IdentityRole>( new RoleStore<IdentityRole>( db ) );
var adminRole=roleManager.FindByName("Admin");
appUsers = db.Users.Where( x => x.Roles.Any( s => s.RoleId == adminRole.Id ) ).ToList();
} );
return View( appUsers );
}
It would be useful to know how Roles and Application users relate.
If the user can only belong to one role, it would be fine for you to do something like this:
var list = db.Users.ToList().Where(x => x.Role == "NormalUser").ToList();
Id the user can be part of multiple roles, it would look something more like this:
var list = db.Users.ToList().Where(x => x.Roles.Contains("NormalUser")).ToList();
Hope this helps.

Updating user data - ASP.NET Identity

I've added custom fields to the ApplicationUser class
I've also created a form through which the user can enter/edit the fields.
However for some reason I'm not able to update the fields in the database.
[HttpPost]
[ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(EditProfileViewModel model)
{
if (ModelState.IsValid)
{
// Get the current application user
var user = User.Identity.GetApplicationUser();
// Update the details
user.Name = new Name { First = model.FirstName, Last = model.LastName, Nickname = model.NickName };
user.Birthday = model.Birthdate;
// This is the part that doesn't work
var result = await UserManager.UpdateAsync(user);
// However, it always succeeds inspite of not updating the database
if (!result.Succeeded)
{
AddErrors(result);
}
}
return RedirectToAction("Manage");
}
My problem is similar to MVC5 ApplicationUser custom properties, but that seems to use an older version of Identity because the IdentityManager class doesn't seem to exist.
Can someone guide me on how to update User info in the database?
UPDATE:
If I include all the fields in the register form, all the values are stored in the appropriate field in a new record of the Users table from the database.
I don't know to make changes to the fields of an existing user (row in the users table). UserManager.UpdateAsync(user) doesn't work.
Also note my issue is more Identity oriented than EntityFramework
OK... I spent hours trying to figure why userManager.updateAsync would not persist the user data that we edit ... until I reached the following conclusion:
The confusion arises from the fact that we create the UserManager in one line like this:
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDbContext()));
...then we use manager.UpdateAsync( user ); but that will update the user in the context, and then we will need to save changes to the dbcontext of the Identity. So, the question is how to get the Identity DBcontext in the easiest way.
To solve this, we should not create the UserManager in one line ... and here is how I do it:
var store = new UserStore<ApplicationUser>(new MyDbContext());
var manager = new UserManager(store);
then after updating the user by calling
manager.UpdateAsync(user);
then you go to the context
var ctx = store.context;
then
ctx.saveChanges();
wahooooooo...persisted :)
Hope this will help someone who pulled their hair for a few hours :P
If you leave any of the fields for ApplicationUser OR IdentityUser null the update will come back as successful but wont save the data in the database.
Example solution:
ApplicationUser model = UserManager.FindById(User.Identity.GetUserId())
Add the newly updated fields:
model.Email = AppUserViewModel.Email;
model.FName = AppUserViewModel.FName;
model.LName = AppUserViewModel.LName;
model.DOB = AppUserViewModel.DOB;
model.Gender = AppUserViewModel.Gender;
Call UpdateAsync
IdentityResult result = await UserManager.UpdateAsync(model);
I have tested this and it works.
The OWIN context allows you to get the db context. Seems to be working fine so far me, and after all, I got the idea from the ApplciationUserManager class which does the same thing.
internal void UpdateEmail(HttpContext context, string userName, string email)
{
var manager = context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindByName(userName);
user.Email = email;
user.EmailConfirmed = false;
manager.Update(user);
context.GetOwinContext().Get<ApplicationDbContext>().SaveChanges();
}
The UserManager did not work, and As #Kevin Junghans wrote,
UpdateAsync just commits the update to the context, you still need to save the context for it to commit to the database
Here is quick solution (prior to new features in ASP.net identity v2) I used in a web forms projetc. The
class AspNetUser :IdentityUser
Was migrated from SqlServerMembership aspnet_Users. And the context is defined:
public partial class MyContext : IdentityDbContext<AspNetUser>
I apologize for the reflection and synchronous code--if you put this in an async method, use await for the async calls and remove the Tasks and Wait()s. The arg, props, contains the names of properties to update.
public static void UpdateAspNetUser(AspNetUser user, string[] props)
{
MyContext context = new MyContext();
UserStore<AspNetUser> store = new UserStore<AspNetUser>(context);
Task<AspNetUser> cUser = store.FindByIdAsync(user.Id);
cUser.Wait();
AspNetUser oldUser = cUser.Result;
foreach (var prop in props)
{
PropertyInfo pi = typeof(AspNetUser).GetProperty(prop);
var val = pi.GetValue(user);
pi.SetValue(oldUser, val);
}
Task task = store.UpdateAsync(oldUser);
task.Wait();
context.SaveChanges();
}
I also had problems using UpdateAsync when developing a version of SimpleSecurity that uses ASP.NET Identity. For example, I added a feature to do a password reset that needed to add a password reset token to the user information. At first I tried using UpdateAsync and it got the same results as you did. I ended up wrapping the user entity in a repository pattern and got it to work. You can look at the SimpleSecurity project for an example. After working with ASP.NET Identity more (documentation is still non-existent) I think that UpdateAsync just commits the update to the context, you still need to save the context for it to commit to the database.
I have tried the functionality in the same way and when i call UserManager.Updateasync method it succeeds but there is no update in the database. After spending some time i found another solution to update the data in aspnetusers table which is following:
1) you need to create UserDbContext class inheriting from IdentityDbContext class like this:
public class UserDbContext:IdentityDbContext<UserInfo>
{
public UserDbContext():
base("DefaultConnection")
{
this.Configuration.ProxyCreationEnabled = false;
}
}
2) then in Account controller update user information like this:
UserDbContext userDbContext = new UserDbContext();
userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
await userDbContext.SaveChangesAsync();
where user is your updated entity.
hope this will help you.
Excellent!!!
IdentityResult result = await UserManager.UpdateAsync(user);
Based on your question and also noted in comment.
Can someone guide me on how to update User info in the database?
Yes, the code is correct for updating any ApplicationUser to the database.
IdentityResult result = await UserManager.UpdateAsync(user);
Check for constrains of all field's required values
Check for UserManager is created using ApplicationUser.
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
This works for me. I'm using Identity 2.0, it looks like GetApplicationUser isn't there anymore.
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (!string.IsNullOrEmpty(form["FirstName"]))
{
user.FirstName = form["FirstName"];
}
if (!string.IsNullOrEmpty(form["LastName"]))
{
user.LastName = form["LastName"];
}
IdentityResult result = await UserManager.UpdateAsync(user);
I am using the new EF & Identity Core and I have the same issue, with the addition that I've got this error:
The instance of entity type cannot be tracked because another instance
of this type with the same key is already being tracked.
With the new DI model I added the constructor's Controller the context to the DB.
I tried to see what are the conflict with _conext.ChangeTracker.Entries() and adding AsNoTracking() to my calls without success.
I only need to change the state of my object (in this case Identity)
_context.Entry(user).State = EntityState.Modified;
var result = await _userManager.UpdateAsync(user);
And worked without create another store or object and mapping.
I hope someone else is useful my two cents.
Add the following code to your Startup.Auth.cs file under the static constructor:
UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
The UserManagerFactory setting line of code is what you use to associate your custom DataContext with the UserManager. Once you have done that, then you can get an instance of the UserManager in your ApiController and the UserManager.UpdateAsync(user) method will work because it is using your DataContext to save the extra properties you've added to your custom application user.
I am using .Net Core 3.1 or higher version.Please follow the solution:
public class UpdateAssignUserRole
{
public string username { get; set; }
public string rolename { get; set; }
public bool IsEdit { get; set; }
}
private async Task UpdateSeedUsers(UserManager<IdentityUser> userManager, UpdateAssignUserRole updateassignUsername)
{
IList<Users> Users = await FindByUserName(updateassignUsername.username);
if (await userManager.FindByNameAsync(updateassignUsername.username) != null)
{
var user = new IdentityUser
{
UserName = updateassignUsername.username,
Email = Users[0].Email,
};
var result = await userManager.FindByNameAsync(updateassignUsername.username);
if (result != null)
{
IdentityResult deletionResult = await userManager.RemoveFromRolesAsync(result, await userManager.GetRolesAsync(result));
if (deletionResult != null)
{
await userManager.AddToRoleAsync(result, updateassignUsername.rolename);
}
}
}
}

mvc entity framework many to many user and role insert

I have an mvc project with database first entityframework. In Project I have 3 tables.
Users >>> UsersInRoles <<< Roles with many to many relationship.
and my CreateUser codes below;
public bool CreateUser(string email, string password, string birthday,string firstname,string lastname)
{
bool result;
var dogumgunu = Convert.ToDateTime(birthday);
var sifre = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "sha1");
var confirmation = CreateConfirmationToken(email);
try
{
var user = new User
{
UserName = email,
Password = sifre,
UserJoinDate = DateTime.Now,
UserBirthDay = dogumgunu,
UserConfirmationToken = confirmation,
UserID = Guid.NewGuid(),
MemberFirstName = firstname,
MemberLastName = lastname
};
var role = new Role
{
RoleName = "Client"
};
user.Roles.Add(role); //problem is here!!!!!!!!!
_bb.Users.AddObject(user);
_bb.SaveChanges();
result = true;
}
catch (Exception)
{
result = false;
}
return result;
}
In this code I am new user creating. And I am adding a role. But This code include a new Role in Roles table. I dont want to this. I want to just add UsersInRoles table a new user. What is wrong? Thanks for reply.
Swap these two lines:
_bb.Users.AddObject(user);
user.Roles.Add(role);
because AddObject converts the whole object graph to the Added state. If you add the role afterwards, its state will remain Unchanged.
And you should fetch the role from the database first or create a Role object that only has an existing RoleId. (A so called stub entity).
So in stead of new Role you could do
var role = _bb.Roles.Single(r => r.RoleName == "Client");

using GroupPrincipal can you get additional info from UserPrincipal

I am looking up users who are members of an AD group using GroupPrincipal.
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, "Advisors");
I need to get the EmployeeID field from this lookup but I believe this is only possible using UserPrincipal.
var members = group.Members.Select(x => new DomainContext() { EmployeeID = x.EmployeeId, FullName = x.DisplayName }).ToList();
Does anyone know of a way round this?
You have to use UserPrincipal unless you're using the underlying DirectoryEntry/DirectorySearcher classes.
You should use .GetMembers() instead of .Members then you can do stuff like:
var userMembers = group.GetMembers().OfType<UserPrincipal>();
foreach( var member in userMembers) {
string empid = member.EmployeeId; //do something with the EmployeeId
}

Resources