I have created a custom User class implementing IUser.
When I register everything completes fine, the tables are created (if they don't exist) and all looks ok, but, as the subject states, I cannot get User.GetUserId() to work.
It always returns null which is really annoying.
Here is my User class:
public class User : IUser
{
public User()
{
this.LastLoginDate = DateTime.UtcNow;
this.DateCreated = DateTime.UtcNow;
}
public User(string userName)
{
this.Id = Guid.NewGuid().ToString();
this.UserName = userName;
this.CreatedBy = this.Id;
this.LastLoginDate = DateTime.UtcNow;
this.DateCreated = DateTime.UtcNow;
this.IsApproved = true;
}
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredUserName")]
public string UserName { get; set; }
public string Id { get; set; }
[Required] public string CompanyId { get; set; }
[Required] public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public DateTime LastLoginDate { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredTitle")]
public string Title { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredFirstName")]
public string Forename { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredLastName")]
public string Surname { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredEmail")]
public string Email { get; set; }
public string JobTitle { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public string Photo { get; set; }
public string LinkedIn { get; set; }
public string Twitter { get; set; }
public string Facebook { get; set; }
public string Google { get; set; }
public string Bio { get; set; }
public string CompanyName { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredCredentialId")]
public string CredentialId { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredSecurityCode")]
public bool IsLockedOut { get; set; }
public bool IsApproved { get; set; }
[Display(Name = "Can only edit own assets")]
public bool CanEditOwn { get; set; }
[Display(Name = "Can edit assets")]
public bool CanEdit { get; set; }
[Display(Name = "Can download assets")]
public bool CanDownload { get; set; }
[Display(Name = "Require approval to upload assets")]
public bool RequiresApproval { get; set; }
[Display(Name = "Can approve assets")]
public bool CanApprove { get; set; }
[Display(Name = "Can synchronise assets")]
public bool CanSync { get; set; }
public bool AgreedTerms { get; set; }
public bool Deleted { get; set; }
}
public class UserContext : IdentityStoreContext
{
public UserContext(DbContext db)
: base(db)
{
this.Users = new UserStore<User>(this.DbContext);
}
}
public class UserDbContext : IdentityDbContext<User, UserClaim, UserSecret, UserLogin, Role, UserRole>
{
}
Here is my Register function:
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
try
{
// Create a profile, password, and link the local login before signing in the user
var companyId = Guid.NewGuid().ToString();
var user = new Skipstone.Models.User(model.UserName)
{
CompanyId = companyId,
Title = model.Title,
Forename = model.Forename,
Surname = model.Surname,
Email = model.Email,
CompanyName = model.CompanyName,
CredentialId = model.CredentialId
};
if (await IdentityStore.CreateLocalUser(user, model.Password))
{
// Create our company
var company = new Company()
{
Id = companyId,
CreatedBy = user.Id,
ModifiedBy = user.Id,
Name = model.CompanyName
};
using (var service = new CompanyService())
{
service.Save(company);
}
await AuthenticationManager.SignIn(HttpContext, user.Id, isPersistent: false);
var test = User.Identity.IsAuthenticated; // returns true
var u = User.Identity.GetUserId(); // returns null
return RedirectToAction("Setup", new { id = companyId });
}
else
{
ModelState.AddModelError("", "Failed to register user name: " + model.UserName);
}
}
catch (IdentityException e)
{
ModelState.AddModelError("", e.Message);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
var test returns true, so it knows the user is now logged in.
var u is null, so User.Identity.GetUserId() is not working as it should.
Does anyone have any idea why?
I can post more code on request :)
Update 1
By creating a fresh project and testing with defaults, I have found that called User.Identity returns null when in the Register method.
But in the fresh project, calling it anywhere else returns the right information, but in my project I get null for everything.
Update 2
It is definately related to the custom User class.
I created one on my fresh project and the same thing happens.
So, something is wrong :) now I just have to figure out what!?!
I assume somewhere in your project there is a row of database connection initialization, something like this:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true)
So, make sure that you use "Id" instead of "UserId" in this line
Related
i am trying to create a Menu for diffent Roles but when i choose the menu and role to create a Role_has_menu something is missing and ModelState said valid = false.
This is the method i am using
public IActionResult Create()
{
ViewData["MenuID"] = new SelectList(_context.Menu, "ID", "FullName");
ViewData["RoleID"] = new SelectList(_context.Role, "ID", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,MenuID,RoleID")] RoleHasMenu roleHasMenu)
{
if (ModelState.IsValid)
{
_context.Add(roleHasMenu);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["MenuID"] = new SelectList(_context.Menu, "ID", "FullName", roleHasMenu.MenuID);
ViewData["RoleID"] = new SelectList(_context.Role, "ID", "Name", roleHasMenu.RoleID);
return View(roleHasMenu);
}
Those are my models
public class Menu
{
public int ID { get; set; }
[Required(ErrorMessage = "The element {0} can't be empty")]
public string Controller { get; set; }
[Required(ErrorMessage = "The element {0} can't be empty")]
public string Action { get; set; }
[Required(ErrorMessage = "The element {0} can't be empty")]
public string Label { get; set; }
[InverseProperty("RoleHasMenu")]
List<RoleHasMenu> roleHasMenu { get; set; }
[NotMapped]
public string FullName { get => Controller + " - " + Action; }
}
public class Role
{
public int ID { get; set; }
[Required(ErrorMessage = "The element {0} can't be empty")]
[NotNull]
public string Name { get; set; }
[MaxLength(100, ErrorMessage = "This element can't be bigger than 100 characters")]
public string Description { get; set; }
[InverseProperty("UserAccount")]
List<UserAccount> userAccount { get; set; }
[InverseProperty("RoleHasMenu")]
List<RoleHasMenu> roleHasMenu { get; set; }
}
public class RoleHasMenu
{
[Key]
public int ID { get; set; }
[ForeignKey("MenuID")]
public Menu Menu { get; set; }
public int MenuID { get; set; }
[ForeignKey("RoleID")]
public Role Role { get; set; }
public int RoleID { get; set; }
}
and this is my problem
I have the same code in other project and it works but this time i am using Visual Studio EF6 and a MySQL database instead of SQLserver
Thanks for your time
In ASP.NET Core MVC, I am using code first migration. I have these two models:
Models:
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class Student
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
[StringLength(40)]
public string Guardian { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
[EmailAddress]
[Required]
public string Email { get; set; }
public bool AdminPermition { get; set; }
}
Then the two are in a single ViewModel:
ViewModel:
public class StudentRegisterModel
{
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
[StringLength(40)]
public string Guardian { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
[EmailAddress]
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string ConfirmPassword { get; set; }
}
Everything is saved using this service:
Service:
public async Task<bool> RegistrationService(StudentRegisterModel registerModel)
{
try
{
//validation functions
var context = new ValidationContext(registerModel, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
if (Validator.TryValidateObject(registerModel, context, results, true))
{
if (CheckEmailAvailability(registerModel.Email)){
if (registerModel.Password != registerModel.ConfirmPassword)
return false;
Student student = new Student
{
FirstName = registerModel.FirstName,
LastName = registerModel.LastName,
Email = registerModel.Email,
Guardian = registerModel.Guardian,
DateOfBirth = registerModel.DateOfBirth,
AdminPermition = false
};
User user = new User
{
Email = registerModel.Email,
Password = Encoder(registerModel.Password),
};
_context.Add(student);
_context.Add(user);
await _context.SaveChangesAsync();
return true;
}
}
return false;
}
catch
{
return false;
}
}
The Id in User is auto-generated, while the Id in Student is not.
How do I automatically duplicate the Id in User into the Id in Student?
Thanks
I think something like this should work:
public class User
{
[Key]
public int Id { get; set; }
[InverseProperty("Student")]
public Student Student { get; set; }
// ...
}
public class Student
{
[Key]
public int Id { get; set; }
[ForeignKey("Id")]
public User User { get; set; }
// ...
}
I have extended my Aspnetusers table to include FirstName, MiddleName, LastName, StudentID.
I want a simple registation page where in the admin will create student accounts. The student accounts then should
be able to add their own personal contact details.
Now, I created a custom table named "ContactDetails" containing the ff:
public class Contact
{
[Key]
[Display(Name = "User Name")]
public string UserName { get; set; }
[Display(Name = "Contact Number")]
public string StudentContactNumber { get; set; }
[Display(Name = "Mother First Name")]
public string MotherFirstName { get; set; }
[Display(Name = "Mother Middle Name")]
public string MotherMiddleName { get; set; }
[Display(Name = "Mother Last Name")]
public string MotherLastName { get; set; }
[Display(Name = "Mother Contact Number")]
public string MotherContactNumber { get; set; }
[Display(Name = "Father First Name")]
public string FatherFirstName { get; set; }
[Display(Name = "Father Middle Name")]
public string FatherMiddleName { get; set; }
[Display(Name = "Father Last Name")]
public string FatherLastName { get; set; }
[Display(Name = "Father Contact Number")]
public string FatherContactNumber { get; set; }
[Display(Name = "Emergency First Name")]
public string EmergencyFirstName { get; set; }
[Display(Name = "Emergency Middle Name")]
public string EmergencyMiddleName { get; set; }
[Display(Name = "Emergency Last Name")]
public string EmergencyLastName { get; set; }
[Display(Name = "Emergency Contact Number")]
public string EmergencyContactNumber { get; set; }
public virtual ApplicationUser User { get; set; }
}
IdentityModels class:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string StudentID { get; set; }
public string College { get; set; }
public virtual System.Collections.Generic.ICollection<Contact> ContactInfo { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
How do I put my user(Aspnetusers.Id) in ContactDetails (User_Id) table when the student is registered?
How do I make a relationship between them?
My AdminController:
// GET: /Admin/Edit/Create
[Authorize(Roles = "Administrator")]
#region public ActionResult Create()
public ActionResult Create()
{
ExpandedUserDTO objExpandedUserDTO = new ExpandedUserDTO();
ViewBag.Roles = GetAllRolesAsSelectList();
return View(objExpandedUserDTO);
}
#endregion
// PUT: /Admin/Create
[Authorize(Roles = "Administrator")]
[HttpPost]
[ValidateAntiForgeryToken]
#region
public ActionResult Create(ExpandedUserDTO paramExpandedUserDTO)
{
try
{
if (paramExpandedUserDTO == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Email = paramExpandedUserDTO.Email.Trim();
var UserName = paramExpandedUserDTO.Email.Trim();
var Password = paramExpandedUserDTO.Password.Trim();
//
var FirstName = paramExpandedUserDTO.FirstName.Trim();
var MiddleName = paramExpandedUserDTO.MiddleName.Trim();
var LastName = paramExpandedUserDTO.LastName.Trim();
var StudentID = paramExpandedUserDTO.StudentID.Trim();
var College = paramExpandedUserDTO.College.Trim();
// UserName is LowerCase of the Email
UserName = Email.ToLower();
// Create user
var objNewAdminUser = new ApplicationUser { UserName = UserName, Email = Email, FirstName = FirstName, MiddleName = MiddleName, LastName = LastName, StudentID = StudentID, College = College };
var AdminUserCreateResult = UserManager.Create(objNewAdminUser, Password);
if (AdminUserCreateResult.Succeeded == true)
{
string strNewRole = Convert.ToString(Request.Form["Roles"]);
if (strNewRole != "0")
{
// Put user in role
UserManager.AddToRole(objNewAdminUser.Id, strNewRole);
}
return Redirect("~/Admin");
}
else
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty, "Error: User "+Email+ " already exists!");
//"Error: Failed to create the user. Check password requirements.");
return View(paramExpandedUserDTO);
}
}
catch (Exception ex)
{
ViewBag.Roles = GetAllRolesAsSelectList();
//ModelState.AddModelError(string.Empty, "Error: " + ex);
return View("Create");
}
}
#endregion
Im not sure how do I proceed? Thanks in advance.
In Contact class you should have these:
public int UserId { get; set; }
public virtual ApplicationUser User { get; set; }
In ApplicationUser class you should have these:
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
So I'm making a .NET Core app with MVC and I'm wondering how I can make a new profile and at the same time put the id of that row in my AspNetUsers as "ProfileId" when someone registers.
Here's my Profile.cs :
namespace Overnight.Models
{
public enum GenderType : byte {
Unknown = 0,
Male = 1,
Female = 2,
NotApplicable = 9
}
public class Profile : BaseEntity<Int64>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public GenderType Gender { get; set; }
public Nullable<DateTime> DayOfBirth { get; set; }
public Nullable<DateTime> LastActivityDate { get; set; }
//TODO One to One reference for image and adress
public List<ProfileReview> Reviews { get; set; }
public List<Blog> Blogs { get; set; }
public List<Accomodation> Accomodations { get; set; }
public List<Post> Posts { get; set; }
public List<Wishlist> Wishlists { get; set; }
public List<Invoice> Invoices { get; set; }
public List<Discount> Discounts { get; set; }
public Security.ApplicationUser ApplicationUser { get; set; }
}
}
Here's my ApplicationUser.cs :
namespace Overnight.Models.Security
{
public class ApplicationUser : IdentityUser<Guid>
{
public string PlainPassword { get; set; }
public DateTime CreatedAt {get; set;}
public Nullable<DateTime> UpdatedAt {get; set;}
public Nullable<DateTime> DeletedAt {get; set;}
public Int64 ProfileId { get; set; }
public Profile Profile { get; set; }
}
}
And here's the code for registering in my AccountController.cs :
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(3, "User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
so not sure if this is the best approach but I think you should first create a profile and then insert it into AspNetUser table, you also have to come up with a 'rollback' mechanism, either using stored procedures or manually track your work and backtrack if anything goes wrong.
so make your RegisterViewModel to contain information needed to create a Profile, and before creating user, there should be a line like:
var profile = profileRepo.add(new profile { /* use registerViewModel to fill*/});
profleRepo.SaveChanges(); // now your profile has the Id of last inserted row
then you can do this:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, profileId = profile.Id};
OK, a little stuck here.
VIEWMODEL
public class UserProfileEdit
{
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public string FirstName { get; set; }
public string TwitterHandle{ get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// etc etc
}
CONTROLLER
public ActionResult YourProfile()
{
string username = User.Identity.Name;
ApplicationUser user = db.Users.FirstOrDefault(u => u.UserName.Equals(username));
// Construct the viewmodel
UserProfileEdit model = new UserProfileEdit();
model.ApplicationUser = user;
return View(model);
}
And on the View I have #model MySite.Models.UserProfileEdit at the top.
How can I pass the user to the ViewModel? I know I can do it line by line
model.Email = user.Email;
for example, but it should be simpler?
You can do it line by line, or you can use AutoMapper. Give it a try http://automapper.org/
This is very useful specially when you have the same kind of object mappings repeated in your code.
You have several options to do what you want to do.
You can use a tool, like AutoMapper.
Or you can pass data by a constructor :
public class UserProfileEdit
{
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public string FirstName { get; set; }
public string TwitterHandle{ get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// etc etc
public UserProfileEdit() {}
public UserProfileEdit(ApplicationUser user) {
this.ApplicationUser = user;
this.Email = user.Email;
// ...
}
}
public ActionResult YourProfile()
{
string username = User.Identity.Name;
ApplicationUser user = db.Users.FirstOrDefault(u => u.UserName.Equals(username));
return View(new UserProfileEdit(user));
}
Or using a method to init your view model's data :
public class UserProfileEdit
{
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public string FirstName { get; set; }
public string TwitterHandle{ get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// etc etc
public void Init(ApplicationUser user) {
this.ApplicationUser = user;
this.Email = user.Email;
// do what you want to do
}
}
public ActionResult YourProfile()
{
string username = User.Identity.Name;
ApplicationUser user = db.Users.FirstOrDefault(u => u.UserName.Equals(username));
UserProfileEdit vm = new UserProfileEdit();
vm.Init(user);
return View(vm);
}