Seed Database with Users after adding custom fields MVC 5 - asp.net-mvc

I've added a couple of custom fields to my ApplicationUser:
public class ApplicationUser : IdentityUser
{
public enum BUserType {IndividualBuyer, IndividualSeller, Broker, Admin};
public string DisplayName;
public BUserType UserType;
I've updated all the views and controllers and I can create new users through my web app. Great.
However, my database seed function doesn't add the new fields to my users. For example, if I create a new user in my initializer, the new fields aren't filled in.
public class ListingInitializer : System.Data.Entity.DropCreateDatabaseAlways<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!(context.Users.Any(u => u.UserName == "arnold#pizzashop.com")))
{
var userToInsert = new ApplicationUser { UserName = "arnold#pizzashop.com", DisplayName = "Arnold Toughguy", UserType = ApplicationUser.BUserType.IndividualSeller };
userManager.Create(userToInsert, "password1234");
}
So my question is, what could be wrong here? I assume userManager.Create does some fancy reflection-to-linq voodoo to find all the fields to persist. Is this not the case? Do I have to add bindings somewhere?

Just a thought, can you just try once after moving the enum definition outside of your POCO class, though I am not absolutely sure that the same will solve your problem.
You can also refer to this video, which may help you somewhat: http://thedatafarm.com/data-access/video-entity-framework-5-enums-and-moving-solution-from-ef-4-3/.

Related

How to query against dbo.AspNetUserLogins table (IdentityUserLogin entity)?

I am using the standard MVC template with the identity provider in VS 2013.
By extending ApplicationUser:IdentityUser, I am able to access the table AspNetUsers using ApplicationDbContext.
I now want to query the data in another table, AspNetUserLogins. How do I reference it without having to create a new database context and a new Entity Data Model to represent this existing table?
The corresponding entity for dbo.AspNetUserLogins table is IdentityUserLogin class. So we just need to declare an appropriate IDbSet<IdentityUserLogin> or DbSet<IdentityUserLogin> property in the ApplicationDbContext class as follows:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
// ...
public IDbSet<IdentityUserLogin> UserLogins { get; set; }
// ...
}
and then query it as usually:
using (var dbContext = new ApplicationDbContext())
{
var userLogins = dbContext.UserLogins.ToList();
}
I know this is old but for anyone looking to do this with asp .Net Core:
Add user manager to your controller constructor that you can access below by DI.
var user = await _userManager.GetUserAsync(User);
var hello = await _userManager.GetLoginsAsync(user);

Get the user id of a username identity 2.0

MVC 5 with asp.net identity 2.0
I understand how to get the currently logged in user id. I have a need to get the user id of a different user in the system. How is this done?
Ex. I need to get the user id of user names "fsmith" ...
Inside the AccountController you can call the following method to get user object and then get the User Id.
var user = await UserManager.FindByNameAsync(userName);
var userId = user.Id;
If you are not inside AccountController you can get the UserManager reference using the following code
var UserManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
To add to Shashi's useful answer...
If you're inside the account controller you can use the existing UserManager:
var user = await UserManager.FindByNameAsync(userName);
var userId = user.Id;
In other controllers (and maybe select other places where HttpContext is available) you create a User Manager with:
var um = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
But what it took me a while to realize is you can get at it just about anywhere with this last bit. For instance I used it in my seed method (in Configuration.cs) so I could seed the User property of another model:
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(*insert-your-db-context-here*));
One way would to use the FindByNameAsync method of your user manager (or the generic version of it). It takes the name of the user (in your case "fsmith") and returns a task of a user object. This user object contains all the information available about that user.
A code snippet could look similar to the following one (if you're looking for the database ID):
var user = await UserManager.FindByNameAsync("fsmith");
var userId = user.Id;
EDIT
The UserManager instance is normally declared as follows (keep in mind that there are many ways of declaring it, for example when using Dependency Injection):
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
If you are using Bearing Token Auth, the above sample do not return an Application User.
Instead, use this:
ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);
return user.Id;
This works in apsnetcore 2.0. Have not tried in earlier versions.

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

Entity framework add a where clause to all queries

I am using Entity framework 5 and using repository pattern. Say I got these entities Customer, Files, Images, Tasks, Invoice, User.
Each entity (apart from Customer) has a foreign key of Customer. When a user logs in I store the customerid in session (aps.net mvc). What I want is any CRUD taken on all entities to be limited to the customer who's user is logged in. e.g I can't afford to delete a Task belonging to customer 1 to be deleted by user who is from customer 2.
Is adding an argument of customerid for each method of repositories the best way to achieve this or are there any better/clever ways of doing it?
Tricky to give a definitive answer but you could make it a bit more extensible by implementing higer order functions, like this:
public interface IRepository<T>
{
public T GetBy(Expression<Func<T, bool>> query)
}
public class FileRepository : IRepository<File>
{
public File GetBy(Expression<Func<T, bool>> query)
{
using(var context = new FilesContext())
{
return context.Files.Where(query).FirstOrDefault();
}
}
}
public class SomeController
{
private IRepository<File> _repo;
public SomeController(IRepository<File> repo)
{
_repo = repo;
}
public ActionResult Index()
{
var model = _repo.GetBy(f => f.CustomerId == Session.Whatever.CustomerId);
return View(model);
}
}
This way you can vary the search query when required, rather than tie yourself in to using a hardcoded customer id property. For example, if you wanted to get the File object by the FileID, not the CustomerID, then:
var model = _repo.GetBy(f => f.FileId == someId);
and that's the only part of the code that needs to change.
Some really good info on Higher Order functions and functional programming in C# here: http://www.codeproject.com/Articles/375166/Functional-programming-in-Csharp
Edit:
You might be able to isolate the "Always use the customer ID when hitting DB" into a repository of it's own, using a decorator style pattern, thus: (massive disclaimer - I haven't tested this, but something along these lines should work)
public class SpecialFileRepo : IRepository<File>
{
private readonly IRepository<File> _baseRepo;
public SpecialFileRepo(IRepository<File> baseRepo)
{
_baseRepo = baseRepo;
}
public SpecialFileRepo() : this(new FileRepository())
{
}
public File GetBy(Expression<Func<File, bool>> query)
{
var parameters = query.Parameters;
var newParam = Expression.Parameter(typeof (File), "f");
var additionalQuery = Expression.AndAlso(query.Body,
Expression.Equal(
Expression.PropertyOrField(newParam, "CustomerId"),
Expression.Constant(HttpContext.Current.Session["customerId"])));
var newQuery = query.Update(additionalQuery, parameters);
return _baseRepo.GetBy(newQuery);
}
}
Then anything that's talking to a repository, as far as it's concerned, it's just a base repository, but this class is sitting in between and always grafting the "customerid = sessionwhatever" expression onto what finally gets passed to the database. And of course, anything that only cares about using the base repository, can still do so.

Get user id in ASP.NET Core 2

I'm trying to get the user id in an ASP.NET Core 2.1 MVC project.
However, I was only able to get the email. I'm almost sure there has to be a 1/2 line way to get it (in the ASP.NET MVC membership it was just var loggedInUserId = User.Identity.GetUserId();
I tried so far like this:
var loggedInUserId = User.Identity.ToString(); // Result = Name (E-mail)
// var loggedInUserId = User.Identity.Name; // Result (E-mail)
& this is now what I need
The old method of User.Identity.GetUserId() no longer exists, but the id is available as a claim on your principal, i.e. User. There's a number of ways you can get to it:
The first and easiest is just pull out the claim:
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
If you already have an instance of UserManager<TUser> (or want to inject one), then you can use the GetUserId() method on that:
var userId = _userManager.GetUserId(User);
Finally, if you want the old way back, it's as simple as adding an extension to ClaimsPrincipal and utilize the first method above:
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal) =>
principal.FindFirstValue(ClaimTypes.NameIdentifier);
}
You need to inject dependency in the controller like shown below:
[Authorize]
public class AccountController: Controller
{
private readonly UserManager<IdentityUser> _userManager;
public AccountController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
}
Now, you can use below code anywhere inside that controller to get user details.
var user = await _userManager.FindByEmailAsync(model.EmailID);
Now, You can use user.Id to get userId.
In Asp.net Core 2.2, I solved this problem with the following piece of code.
using Microsoft.AspNetCore.Identity;
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
This way you will get the user information by his email. User.Identity.Name will provide you the email address of the current logged in user.
I hope this will be useful to someone.

Resources