I have set Identity so I have separate table for user profile data (firstname, lastname etc.).
Problem is that I have joined those tables via Email field.
I want to change this so I can connect tables by UserID instead.
What I need is to get new userID for created user and use that as foreign key to UserProfileInfo object.
public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public string Email { get; set; }
public string ConfirmationToken { get; set; }
public bool IsConfirmed { get; set; }
public virtual UserProfileInfo UserProfileInfo { get; set; }
}
public class UserProfileInfo
{
public int Id { get; set; }
public string EmailId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
When I create new user I have:
var user = new ApplicationUser()
{
UserName = model.UserName,
Email = model.Email,
ConfirmationToken = confirmationToken,
IsConfirmed = false,
UserProfileInfo = new UserProfileInfo { EmailId = model.Email }
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
SendEmailConfirmation(model.Email, model.UserName, confirmationToken);
return RedirectToAction("RegisterStepTwo", "Account");
}
else...
Why are you doing a join in the first place? ApplicationUser is your user, and the whole point of inheriting from IdentityUser is to allow you extend the user object. Just put your properties like FirstName and LastName directly on ApplicationUser.
Related
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.
I'm new to MVC and have been pulling my hair out with this one. I'm already going bold so need someone to rescue what's left!
I'm using asp.net Identity and trying to create a one-to-one relationship between RegisterViewModel and StoreDetails and really hope someone can help me out!
Here is my RegisterViewModel:
public class RegisterViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public virtual StoreDetails StoreDetails { get; set; }
}
Here is my StoreDetails model:
public class StoreDetails
{
[Key, ForeignKey("RegisterViewModel")]
public string StoreName { get; set; }
public virtual RegisterViewModel RegisterViewModel { get; set; }
}
Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser {
// PERSONAL DETAILS
UserName = model.Email,
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName
};
var storeDetails = new StoreDetails {
// STORE DETAILS
StoreName = model.StoreDetails.StoreName
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
// UPDATE DB WITH STORE DETAILS DATA
var db = new ApplicationDbContext();
db.StoreDetails.Add(new StoreDetails
{
StoreName = model.StoreDetails.StoreName
});
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
What i'm looking to achieve is on registration the StoreDetails table is generated with the following input:
#Html.TextBoxFor(m => m.StoreDetails.StoreName)
If you need any further details please ask.
Thanks
RegisterViewModel is not a real entity i.e person that gets saved into the database by EF. All it is is a carrier object that passes the values of email and password into the real User/person object called ApplicationUser. This is a view-model and not a real model.
in your example you added StoreDetails in the RegisterViewModel which is correct. But you also need to add this in your ApplicationUser class as a property.
public class ApplicationUser {
public virtual StoreDetails StoreDetails { get; set; }
Then run your migrations.
Adding anything to the RegisterViewModel is made to pass data from the view layer in a way to safe guard the object thats going into your db.
i.e
doing this doesnt do anything because the viewmodel doesnt live in the db
public class StoreDetails
{
[Key, ForeignKey("RegisterViewModel")] //this will not work remove
public string StoreName { get; set; }
public virtual RegisterViewModel RegisterViewModel { get; set; }// remove
}
public Ienumerable<StoreDetails> StoreDetails { get; set; }
public int StoreDetailsId { get; set; }
In controller:
using (var db = ApplicationDbContext.Create())
{
model.StoreDetails = db.StoreDetails.ToList();
}
i'm using Simple.Data and I have a question about.
I have the following classes:
public abstract class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Salt { get; set; }
}
public class Customer : User
{
public string Email { get; set; }
}
public class Admin : User
{
public string Name { get; set; }
public bool IsActive{ get; set; }
}
And a class that makes the actions in database:
public class Manager
{
public string ConString { get; set; }
public Manager()
{
ConString = ConfigurationManager.ConnectionStrings["Test"].ConnectionString;
}
public void CustomerUpdate()
{
var obj = new Customer()
{
Id = 1,
Username = "teste",
Password = "teste",
Salt = "",
Email = "teste#teste.com"
};
var db = Database.OpenConnection(conString);
db.tbCustomer.Update(obj);
}
public void AdminUpdate()
{
var obj = new Admin()
{
Id = 1,
Username = "teste",
Password = "teste",
Salt = "",
Name = "teste",
IsActive = true
};
var db = Database.OpenConnection(conString);
db.tbAdmin.Update(obj);
}
}
But, i have a problem:
In my db, in the table tbCustomer, the Primary Key is the "CustomerId" column. And the Primary Key of the table tbAdmin is the "AdminId" column.
As the User class has a property called "Id", I can not do updates.
Is there any way I map for when you're giving update on tbCustomer table, the system take "Id" property and enter the "CustomerId" column?
Same for tbAdmin. I want him to take "Id" and place in "AdminId".
If you can't rename the property in your class the best option is most likely to use Named Parameters in your update instead of passing the object. An example for yours would be
db.tbCustomer.UpdateById(Id: 1,
Username: "teste",
...);
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()));
I need to query data from 2 table
public class UserProfile
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
}
and
public class PrivateMessage
{
public int MessageId { get; set; }
public string Sender { get; set; }
public string Receiver { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
private DateTime _date = DateTime.Now;
public DateTime sentDate { get { return _date; } set { _date = value; } }
}
and this what i tried on my controller
public ActionResult Index()
{
var x = User.Identity.Name;
var query = from p in db.PrivateMessages
join u in db.UserProfiles on p.Sender equals u.UserName
where p.Receiver == x
select new
{
u.UserName,
u.Name,
p.Receiver,
p.Subject,
p.Message,
p.sentDate
};
return View(query);
}
this is my view model
#model IEnumerable<SeedSimple.Models.PrivateMessage>
but i got this error
The model item passed into the dictionary is of type
'System.Data.Entity.Infrastructure.DbQuery1[<>f__AnonymousType95[System.String,System.String,System.String,System.String,System.DateTime]]',
but this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[SeedSimple.Models.PrivateMessage]'.
all i want is to get username and name from UserProfile table and receiver, subject, message and sentDate on PrivateMessage table
Well you're passing as a Model an anonymous type yet you have a strongly typed View.
You can either create a new ViewModel that contains all the fields you're using for your query and pass that, or you can pass all the properties in the ViewBag (not a pretty solution).
EDIT
Thought I'd give you an example.
Here is a ViewModel containing the data you need:
public class MessageViewModel
{
public string UserName { get; set; }
public string Name { get; set; }
public string Receiver { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
public DateTime SentDate { get; set; }
}
In your view:
#model IEnumerable<SeedSimple.Models.MessageViewModel>
In your Controller:
public ActionResult Index()
{
var x = User.Identity.Name;
var result = from p in db.PrivateMessages
join u in db.UserProfiles on p.Sender equals u.UserName
where p.Receiver == x
select new MessageViewModel
{
UserName = u.UserName,
Name = u.Name,
Receiver = p.Receiver,
Subject = p.Subject,
Message = p.Message,
SentDate = p.sentDate
};
return View(result);
}
I hope this helps.