I want to assign a list of stores to a particular client, based on the Identity Model in MVC 5. I want to be able to register a user/client using the default registration in the MVC 5 example code and be able to add a store, then assign the store to the user.
I'm having trouble being able to create a working viewmodel that incorporates the idenity model with a new list.
Here is what I have so far:
Model:
public class ApplicationUser : IdentityUser
{
//[Required]
[Display(Name = "Client/Company Name")]
public string ClientName { get; set; }
public List<Store> Stores { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
I tried to add to the existing default dbcontext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Store> Stores { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
My controller blows up when I try to set my store clientname to the user clientname. Clientname or any other property is unavailable for ApplicationUser.
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Stores
public ActionResult Index(ClientStoreViewModel viewModel)
{
var clients = from s in db.Stores
join c in db.Users
on s.ClientName equals u.ClientName
select new ClientStoreViewModel() { Stores = s, Users = u };
return View(clients);
}
Store class:
public class Store
{
public int Id { get; set; }
//public int ClientId { get; set; }
[Display(Name = "Client Name")]
public string ClientName { get; set; }
[Display(Name = "Store Name")]
public string Brand { get; set; }
[Display(Name = "Store Number")]
public string StoreNumber { get; set; }
[Display(Name="Store Login URL")]
public string LoginURL { get; set; }
}
Finally my viewmodel:
public class ClientStoreViewModel
{
public ApplicationUser Users { get; set; }
public Store Stores { get; set; }
public ClientStoreViewModel()
{
Stores = new Store();
Users = new ApplicationUser();
}
}
Related
I have two models/tables, one is User and the other is role the relationship is one Role can have many users. I am trying to loop through the data in the user model navigation property but i am getting an error that its returning null.
User model
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int User_Id { get; set; }
[Required]
[Display(Name ="User Name")]
public string User_Name { get; set; }
[Required(ErrorMessage = "The Field Is Required")]
[MaxLength(10, ErrorMessage = " Please Enter A Valid Input")]
public string Password { get; set; }
//Nav
[ForeignKey("RoleId")]
[Display(Name ="User Role:")]
public int RoleId { get; set;}
public Role Role { get; set; }
}
Role Model
public class Role
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Role_id { get; set; }
[Required(ErrorMessage ="This field is required")]
[Display(Name ="Role Name :")]
public string RoleType { get; set; }
//nav
public List<User> Users { get; set; }
}
Controller action Method:
public async Task<IActionResult> Index()
{
var viewModel = await userRepository.GetAllUsersAlongWithRolesAsync();
//var viewModel = await baseRepository.GetAllObjectsAsync();
return View("Index",viewModel);
}
Updates: UserRepository that inherited from the IBaseRepository
public class UserRepository : BaseRepository<User>, IUserRepository
{
private readonly ApplicationDbContext _Context;
public UserRepository(ApplicationDbContext context):base (context)
{
_Context = context;
}
public async Task <IEnumerable<User>> GetAllUsersAlongWithRolesAsync()
{
var getUsers = await _Context.Users.Include(u => u.Role).ToListAsync();
return getUsers;
}
}
In the User controller for injecting:
// injection
private readonly IBaseRepository<User> baseRepository;
private readonly IBaseRepository<Role> roleRepository;
private readonly IUserRepository userRepository;
public UserController(IBaseRepository<User> _baseRepository, IBaseRepository<Role> _roleRepository, IUserRepository userRepository)
{
baseRepository = _baseRepository;
this.roleRepository = _roleRepository;
this.userRepository = userRepository;
}
Since your method GetAllObjectsAsync is so generic, you probably won't be able to add the .Include() you need.
I'd suggest a separate method GetAllUsers() to your repository - possibly the concrete UserRepository, if you have that:
public async Task<IEnumerable<User>> GetAllUsersAsync()
{
var getUsers = await _Context.Users.Include(u => u.Role).ToListAsync();
return getUsers;
}
My dbContext return null, when I want get list of user in Index View. This list are from my database AspNetUsers table, which has been generate by identity. I can get other my database table list.
There is my ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
There is my UserController
[Area("Admin")]
public class UserController : Controller
{
UserManager<IdentityUser> _userManager;
private ApplicationDbContext _db;
public UserController(UserManager<IdentityUser> userManager, ApplicationDbContext db)
{
_userManager = userManager;
_db = db;
}
public IActionResult Index()
{
return View(_db.ApplicationUsers.ToList());
}
}
There is my ApplicationUser.Model, which inherit IdendityUser
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public string Surname { get; set; }
public ICollection<Recipe> Products { get; set; }
public ICollection<Order> Orders { get; set; }
}
I don't know how you register ApplicationDbContext and Identity framework on your ASP.NET Core MVC application because you didn't show them on the question.
There are couple problems in your code.
First, if you have a custom IdentityUser, like the ApplicationUser you have, you would have to use the generic version of IdentityDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
}
You would need to use the matching generic version of IdentityDbContext if you have any of following:
Custom IdentityUser
Custom IdentityRole
Custom primary key
All 7 classes, user and role, plus IdentityUserRole, IdentityUserClaim, IdentityRoleClaim, IdentityUserLogin, and IdentityUserToken
After you register your custom class with IdentityDbContext, you don't need to put the class as one of the DbSet<> there:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
...
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductBrand> ProductBrands { get; set; }
public DbSet<Product> Products { get; set; }
// public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Address> Address { get; set; }
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Order_detail> Order_Details { get; set; }
}
You would also need to use the generic version of AddIdentity<TUser>, AddDefaultIdentity<TUser>, or AddIdentityCore<TUser> in your Startup.cs, depending on what you need:
AddDefaultIdentity = AddIdentity + AddDefaultTokens + AddDefaultUI
You didn't specify what version of ASP.NET Core Identity you're using so I don't exactly know which one you use, but the following is how I registered it:
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.User.RequireUniqueEmail = ...;
...
})
.AddEntityFrameworkStores<ApplicationDbContext>();
I have all 7 classes customized as well as change the primary key from string to Guid.
Lastly, to use the dependency injected UserManager and SignInManager, you would need to correct generic version of them as well:
[Area("Admin")]
public class UserController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public UserController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public IActionResult Index()
{
// Get the user list
var users = _userManager.Users.ToList();
// Build your view model to define what your UI only needs, not just passing
// everything to it
var vm = new UserManagementListViewModel
{
Users = users.Select(x => new UserViewModel
{
UserId = x.Id,
UserSurname = x.Surname,
ProductCount = x.Products.Count(),
OrderCount = x.Orders.Count()
})
};
return View(vm);
}
}
I'm getting this error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.ConsoleUserInfoes_dbo.ConsolesCheckBoxes_consoleId". The conflict occurred in database "aspnet-ForePlay-20180525122039", table "dbo.ConsolesCheckBoxes", column 'ConsoleId'.
I'm using Entity Framework and ASP.NET MVC 5 and IdentityUser and try to insert data form checkListBox to table into my database.
This is happening on the register view, when user need to register and fill the form.
public class ConsoleUserInfo
{
[Key]
public int identity { get; set; }
[Required]
[StringLength(255)]
[ForeignKey("User")]
public string userid { get; set; }
[Required]
[ForeignKey("consolesCheckBox")]
public int consoleId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ConsolesCheckBox consolesCheckBox { get; set; }
}
This is the table that need to get a user id (form applictionUser) and consoleId
(form ConsolesCheckBox )
This is the ApplicationUserUser model class:
public class ApplicationUser : IdentityUser
{
[Required]
[StringLength(255)]
override
public string UserName { get; set; }
[Required]
[StringLength(50)]
public string Phone { get; set; }
public byte[] UserPhoto { get; set; }
public virtual UserAddress Address { get; set; }
public virtual ICollection<ConsolesCheckBox> consoleCheckBox { get; set; }
}
and this is the checkBoxList table:
public class ConsolesCheckBox
{
[Key]
public int ConsoleId { get; set; }
public string ConsoleName { get; set; }
public bool IsChecked { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
}
This is my account controller, all in the register get and post
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
//using database
using (ApplicationDbContext dbo = new ApplicationDbContext())
{
//data will save list of the consoleCheckBoxItem
var data = dbo.consolesCheckBox.ToList();
// because the view is request a common model, we will create new one
CommenModel a = new CommenModel();
a.ConsolesCheckBoxList = data;
// we will need to return common model, that way we will return a
return View(a);
}
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register([Bind(Exclude = "UserPhoto")]CommenModel model)
{
if (ModelState.IsValid)
{
// To convert the user uploaded Photo as Byte Array before save to DB
byte[] imageData = null;
if (Request.Files.Count > 0)
{
HttpPostedFileBase poImgFile = Request.Files["UserPhoto"];
using (var binary = new BinaryReader(poImgFile.InputStream))
{
imageData = binary.ReadBytes(poImgFile.ContentLength);
}
}
var user = new ApplicationUser
{
UserName = model.registerViewModel.Email,
Email = model.registerViewModel.Email,
Phone = model.registerViewModel.Phone
};
user.UserPhoto = imageData;
var result = await UserManager.CreateAsync(user, model.registerViewModel.Password);
//after the user create, we will use the id and add the id to the userAddress table include
// Address, longitude and latitude.
using (ApplicationDbContext dbo = new ApplicationDbContext())
{
var currentUserId = user.Id;
var pasinfo = dbo.userAddress.FirstOrDefault(d => d.Userid == currentUserId);
if (pasinfo == null)
{
pasinfo = dbo.userAddress.Create();
pasinfo.Userid = currentUserId;
dbo.userAddress.Add(pasinfo);
}
pasinfo.Address = model.useraddress.Address;
pasinfo.latitude = model.useraddress.latitude;
pasinfo.longitude = model.useraddress.longitude;
dbo.SaveChanges();
foreach (var item in model.ConsolesCheckBoxList.Where(x => x.IsChecked).Select(x => x.ConsoleId))
{
var consoleUserInfo = new ConsoleUserInfo
{
userid = currentUserId,
consoleId = item
};
dbo.consoleUserInfo.Add(consoleUserInfo);
}
dbo.SaveChanges();
}
}
}
In the register GET I have a common model, because I used 3 models in the view
this is the common model:
public class CommonModel
{
public UserAddress useraddress { get; set; }
public RegisterViewModel registerViewModel { get; set; }
public List<ConsolesCheckBox> ConsolesCheckBoxList { get; set; }
}
I need your help here, I've been trying to fix this all day.
One user can be a member of many projects while a project can have multiple members.
ASP.NET Identity ApplicationUser
public class ApplicationUser : IdentityUser
{
[Display(Name = "Projekt")]
public virtual ICollection<Project> Projects { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
My Project:
[Table("Projects")]
public class Project : IValidatableObject
{
[Key]
public int ID { get; set; }
[Required, StringLength(128), Display(Name = "Projektname"), Index(IsUnique = true)]
public string Name { get; set; }
// working one-to-many relation
[Display(Name = "Projektleiter")]
public string LeaderID { get; set; }
[ForeignKey("LeaderID"), Display(Name = "Projektleiter")]
public virtual ApplicationUser ApplicationUser { get; set; }
// many-to-many relation gets ignored
[Display(Name = "Mitarbeiter")]
public virtual ICollection<ApplicationUser> ApplicationUsers { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return new List<ValidationResult>();
}
}
No Many-to-Many table is created. The whole relation gets ignored. But the LeaderID thing is working ...
Can somebody tell me what I am missing here? (I googled the hell out of it, I deleted the whole database multiple times, I tried everything I found, no luck ...)
I would keep the ApplicationUser entity separated from whatever logic you have with the project and create another entity called Person.
public class Person
{
//Constuctor : always intantiate lists in ctor
public Person()
{
Projects = new List<Project>();
}
public int Id { get; set; }
public string IdentityId { get; set; } //gets guid from AppUser table
public ApplicationUser Identity { get; set; } // navigation property
public List<Project> Projects { get; set; }
//public int ProjectId {get; set;}//-----optional
}
so in projects know we do the same thing:
[Table("Projects")]
public class Project : IValidatableObject
{
//Constuctor : always intantiate lists in ctor
public Project()
{
Persons = new List<Person>();
}
[Key]
public int ID { get; set; }
[Required, StringLength(128), Display(Name = "Projektname"), Index(IsUnique = true)]
public string Name { get; set; }
public string PersonId { get; set; } //nav property
public List<Persons> Persons { get; set; }
public Person Person { get; set; } //context will be aware that this is fk
[Display(Name = "Projektleiter")]
public string LeaderID { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return new List<ValidationResult>();
}
}
add db sets for both entities in the dbcontext class.
Now you want to get a person with a list of projects and vice versa. For that we use the include:
var x = myContext.Persons.Include(x => x.Projects);
var d = x.ToList();
//you can use the applicationUser entity instead of person but bad things happen as the project grows.
I am fairly new to MVC5/ASP.NET Identity and I have found an issue that has stumped me a bit.
I am writing a small form for my ASP.NET MVC5 application that will allow an admin user (member of the Admins role) to review the users that have signed up to the site and edit the details of and assign roles to those users. When the form is submitted, if a role has been assigned to the user the UserManager.AddToRole method is called.
I noticed after this that once this is done, that user is then unable to log into the application. Looking in the database, it appears when AddToRole is called, the PasswordHash field is set to null. Is this normal and if not how to I get around this issue?
For reference my relevant code is below
Controller
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
public ActionResult Details(EditUserViewModel model)
{
model.Save();
return RedirectToAction("List", "Account");
}
Relevant view models
public class EditUserViewModel
{
public string UserId { get; set; }
public string UserName { get; set; }
[Required]
[StringLength(255)]
[Display(Name = "Email address")]
public string Email { get; set; }
[StringLength(255)]
[Display(Name = "First name")]
public string FirstName { get; set; }
[StringLength(255)]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[StringLength(255)]
[Display(Name = "Mobile Number")]
public string MobileNumber { get; set; }
public IList<EditUserRolesViewModel> UserRoles { get; set; }
public void Save()
{
using (ApplicationDbContext context = new ApplicationDbContext())
{
ApplicationUser user = new ApplicationUser()
{
Id = this.UserId,
UserName = this.UserName,
Email = this.Email,
FirstName = this.FirstName,
LastName = this.LastName,
MobileNumber = this.MobileNumber
};
context.Users.Attach(user);
context.Entry(user).Property(x => x.Email).IsModified = true;
context.Entry(user).Property(x => x.FirstName).IsModified = true;
context.Entry(user).Property(x => x.LastName).IsModified = true;
context.Entry(user).Property(x => x.MobileNumber).IsModified = true;
context.SaveChanges();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
foreach (var row in this.UserRoles)
{
if (row.RowChanged)
{
if (row.RoleAssigned)
{
UserManager.AddToRole(this.UserId, row.RoleName);
}
else
{
UserManager.RemoveFromRole(this.UserId, row.RoleName);
}
}
}
}
}
}
public class EditUserRolesViewModel
{
public string RoleId { get; set; }
[Display(Name = "Role name")]
public string RoleName { get; set; }
[Display(Name = "Assigned")]
public bool RoleAssigned { get; set; }
public bool RowChanged { get; set; }
}
As I see from your code, you have attached partially initialized object user to context.Users. As a result when UserManager gets control: AddToRole, it tries to update Database. And you'll have lot empty or null fields in the current users row.
You can fix doing any of the following (both will help):
instead of
ApplicationUser user = new ApplicationUser() use user = UserManager.FindById(UserId)
after assigning values from viewmodel EntityFramework will take care of modified fields.
use another context when dealing with roles
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));