I'm implementing some integration tests and there is an entity with certain attributes that must be respected. The entity is the following:
[Table("ManualClassifiers")]
public class ManualClassifier : Classifier
{
[RegularExpression(#"^([a-zA-Z]+?)([-\s'][a-zA-Z]+)*?")]
[Required(ErrorMessage = "First name field is mandatory")]
[Column(name: "first_name")]
public string FirstName { get; set; }
[RegularExpression(#"^([a-zA-Z]+?)([-\s'][a-zA-Z]+)*?")]
[Required(ErrorMessage = "Last name field is mandatory")]
[Column(name: "last_name")]
public string LastName { get; set; }
[EmailAddress]
[Required(ErrorMessage = "Email field is mandatory")]
[Column(name: "email")]
public string Email { get; set; }
[RegularExpression(#"^[a-zA-Z0-9._]+$")]
[Required(ErrorMessage = "Username field is mandatory")]
[Column(name: "username")]
public string Username { get; set; }
[Required(ErrorMessage = "Password hash field is mandatory")]
[Column(name: "passwordHash")]
public string PasswordHash { get; set; }
[Required(ErrorMessage = "Password salt field is mandatory")]
[Column(name: "passwordSalt")]
public string PasswordSalt { get; set; }
}
When trying to validate the first regular expression, my test is always passing (even when my input is a white space, and hence, should fail or throw some error). This is the test:
[TestMethod]
public async Task Insert_ManualClassifier_With_Empty_Field_Fails()
{
using var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<DataContext>()
.UseSqlite(connection) // Set the connection explicitly, so it won't be closed automatically by EF
.Options;
// Create the dabase schema
// MigrateAsync if using Migrations
using (var context = new DataContext(options))
{
await context.Database.EnsureCreatedAsync();
} // The connection is not closed, so the database still exists
using (var context = new DataContext(options))
{
var user = new ManualClassifier()
{
FirstName = " ", //this is where it should not match the regular expression and fail
LastName = "Last",
Email = "example#gmail.com",
Username = "firstlast123"
};
IRepositoryService repoService = new RepositoryService(context, NullLogger<RepositoryService>.Instance);
string passwordHash = "pwhash";
string passwordSalt = "pwsalt";
int userID = await repoService.CreateUser(user, passwordHash, passwordSalt);
}
}
This is the repository method I'm invoking:
public async Task<int> CreateUser(ManualClassifier user, string passwordHash, string passwordSalt)
{
//TO DO: CREATE UPPER LAYER IN REPO PROJECT TO MAP RESULTS
if (_context.ManualClassifiers.Any(u => u.Username == user.Username))
{
_logger.LogDebug($"User with email {user.Username} already exists");
throw new UsernameAlreadyExistsException(user.Username);
}
if (_context.ManualClassifiers.Any(u => u.Email == user.Email))
{
_logger.LogDebug($"User with email {user.Email} already exists");
throw new EmailAlreadyExistsException(user.Email);
}
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
user.Email = user.Email.ToLower();
_logger.LogDebug("New user created successfully");
await _context.ManualClassifiers.AddAsync(user);
await _context.SaveChangesAsync();
return user.Id;
}
Your regular expression validation for FirstName and LastName are missed end string anchor $. You should add the $ anchor to the regex validation for these 2 fields.
[Table("ManualClassifiers")]
public class ManualClassifier : Classifier
{
[RegularExpression(#"^([a-zA-Z]+?)([-\s'][a-zA-Z]+)*?$")]
[Required(ErrorMessage = "First name field is mandatory")]
[Column(name: "first_name")]
public string FirstName { get; set; }
[RegularExpression(#"^([a-zA-Z]+?)([-\s'][a-zA-Z]+)*?$")]
[Required(ErrorMessage = "Last name field is mandatory")]
[Column(name: "last_name")]
public string LastName { get; set; }
[EmailAddress]
[Required(ErrorMessage = "Email field is mandatory")]
[Column(name: "email")]
public string Email { get; set; }
[RegularExpression(#"^[a-zA-Z0-9._]+$")]
[Required(ErrorMessage = "Username field is mandatory")]
[Column(name: "username")]
public string Username { get; set; }
[Required(ErrorMessage = "Password hash field is mandatory")]
[Column(name: "passwordHash")]
public string PasswordHash { get; set; }
[Required(ErrorMessage = "Password salt field is mandatory")]
[Column(name: "passwordSalt")]
public string PasswordSalt { get; set; }
}
Related
I'm using an UI to insert data into the DB. Here is my entity model and controller. Whenever I'm inserting data into the UserDetail table, it automatically creates a new row in the UserRole table. Not sure why it's happening like this. For now UserRole is hard-coded in controller.
public class UserDetail
{
[Key]
public int UserID { get; set; }
[Required]
[StringLength(30, MinimumLength = 4)]
public string UserName { get; set; }
[Required]
[StringLength(50, MinimumLength = 4)]
public string FirstName { get; set; }
[Required]
[StringLength(50, MinimumLength = 4)]
public string LastName { get; set; }
[Required]
[EmailAddress]
[StringLength(150, MinimumLength = 4)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[StringLength(30,MinimumLength=4)]
public string Password { get; set; }
public UserRole UserRole { get; set; }
}
public class UserRole
{
[Key]
public int RoleID { get; set; }
[Required]
[StringLength(20,MinimumLength=5)]
public string RoleName { get; set; }
public IEnumerable<UserDetail> UserDetail { get; set; }
}
[HttpPost]
public HttpResponseMessage Register(UserDetail usrInfo)
{
UserContext ctx = new UserContext();
UserDetail user = new UserDetail
{
UserRole = ctx.UserRole.Where(id => id.RoleID == 2).Select(r => r).FirstOrDefault(),
FirstName = usrInfo.FirstName,
LastName = usrInfo.LastName,
UserName = usrInfo.UserName,
Password = usrInfo.Password,
Email = usrInfo.Email,
};
_unitofwork.userDetail.Add(user);
if (_unitofwork.Completed() > 0)
return Request.CreateResponse(HttpStatusCode.OK, "Created");
else
return Request.CreateResponse();
}
public class UserContext: DbContext
{
public UserContext():base()
{
Database.SetInitializer<UserContext>(new CreateDatabaseIfNotExists<UserContext>());
//Database.SetInitializer<UserContext>(new DropCreateDatabaseIfModelChanges<UserContext>());
}
public DbSet<UserDetail> UserDetails { get; set; }
public DbSet<UserRole> UserRole { get; set; }
}
In the statement where you are instantiating the userdetail object you use a separately defined context to query for the user role:
UserContext ctx = new UserContext();
UserDetail user = new UserDetail
{
**UserRole = ctx.UserRole.Where(id => id.RoleID == 2).Select(r => r).FirstOrDefault(),**
FirstName = usrInfo.FirstName,
LastName = usrInfo.LastName,
UserName = usrInfo.UserName,
Password = usrInfo.Password,
Email = usrInfo.Email,
};
_unitofwork.userDetail.Add(user);
if (_unitofwork.Completed() > 0)
return Request.CreateResponse(HttpStatusCode.OK, "Created");
else
return Request.CreateResponse()
You then add the user to the userdetail collection under the _unitofwork object which has it's own context. To make thiswork, the userrole object you retrieved has to be under the same context to which you are adding the userdetail object.
So you probably want something like:
UserDetail user = new UserDetail
{
UserRole = _unitofwork.UserRole.Where(id => id.RoleID == 2).Select(r => r).FirstOrDefault(),
FirstName = usrInfo.FirstName,
LastName = usrInfo.LastName,
UserName = usrInfo.UserName,
Password = usrInfo.Password,
Email = usrInfo.Email,
};
_unitofwork.userDetail.Add(user);
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; }
I'm new to .Net and I need your help. I'm using code first approach for my project and I'm trying to build custom register/login with encryption. By some reason I cannot save the user in my database when trying to encrypt the password. Saving the user in the database works when I remove the 2 lines for encryption and salting. Here is my User model:
public class User
{
[Key]
public int UserId { get; set; }
[Required(ErrorMessage = "First Name is required !")]
[Display(Name = "First Name: ")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required !")]
[Display(Name = "Last Name: ")]
public string LastName { get; set; }
[Required(ErrorMessage = "Email is required !")]
[EmailAddress]
[StringLength(50)]
[RegularExpression(#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$", ErrorMessage = "Please enter valid email")]
[Display(Name = "Email Address: ")]
public string Email { get; set; }
[StringLength(50)]
[Display(Name = "Company Name: ")]
public string CompanyName { get; set; }
[Required(ErrorMessage = "Password is required !")]
[DataType(DataType.Password)]
[Display(Name = "Password: ")]
public string Password { get; set; }
[NotMapped]
[DataType(DataType.Password)]
[Compare("Password", ErrorMessage = "Passwords don't match !")]
public string ConfirmPassword { get; set; }
public string PasswordSalt { get; set; }
public int AdminCode { get; set; }
}
And here is my Register method in my controller:
[HttpPost]
public ActionResult Register(Models.User user)
{
if (ModelState.IsValid)
{
using (AppContext db = new AppContext())
{
var crypto = new SimpleCrypto.PBKDF2();
var encrypPass = crypto.Compute(user.Password);
//var newUser = db.Users.Create();
//newUser.FirstName = user.FirstName;
//newUser.LastName = user.LastName;
//newUser.Email = user.Email;
//newUser.CompanyName = user.CompanyName;
//newUser.Password = encrypPass;
//newUser.PasswordSalt = crypto.Salt;
//newUser.AdminCode = 0;
user.Password = encrypPass;
user.PasswordSalt = crypto.Salt;
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Data is not correct");
}
return View();
}
Here is my table.. When trying to encrypt I get Error "Validation failed for one or more entities.", but I have no idea what validation is failing. I've checked my DB table and the User model and I don't see the problem. I've really tried to figure it out by my own, but I can't! Any ideas what am I missing ? Thanks in advance.
I need to store additional information during user registration such as: First Name, Last Name and etc.
My question has two parts:
How can I save my additional information during Register?
My current method throws error:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
I have already checked "Watch" inside VS and also used try-catch but it didn't help.
Thanks in advance for your help!
IdentityModels.cs
public class ApplicationIdentityAccount : IdentityUser
{
public virtual ICollection<AccountProfile> AccountProfiles { get; set; }
}
public class AccountProfile
{
[Key]
public string AccountProfileID { get; set; }
[DisplayName("First Name")]
[StringLength(50)]
[Required(ErrorMessage = "First name is required")]
public string FirstName { get; set; }
[DisplayName("Middle Name")]
[StringLength(50)]
public string MiddleName { get; set; }
[DisplayName("Last Name")]
[StringLength(50)]
[Required(ErrorMessage = "Last name is required")]
public string LastName { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationIdentityAccount User { get; set; }
}
public class ApplicationIdentityDbContext : IdentityDbContext<ApplicationIdentityAccount>
{
public ApplicationIdentityDbContext()
: base("ApplicationIdentity", throwIfV1Schema: false)
{
}
public static ApplicationIdentityDbContext Create()
{
return new ApplicationIdentityDbContext();
}
public System.Data.Entity.DbSet<AccountProfile> AccountProfile { get; set; }
}
AccountViewModels.cs > RegisterViewModel
public class RegisterViewModel
{
[Required]
[Display(Name = "Username")]
public string UserName { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
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; }
}
AccountController.cs
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationIdentityAccount
{
UserName = model.UserName,
Email = model.Email,
AccountProfile = new[] {new AccountProfile()
{
FirstName = model.FirstName,
LastName = model.LastName
}}
};
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 http://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");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
I know that I should place FirstName and LastName inside:
var user = new ApplicationIdentityAccount
{
UserName = model.UserName,
Email = model.Email,
};
Since your question has two parts:
Your method for storing additional information is correct
You can't proceed unless you see the actual error, in order to see the details you need to add this where you create the user.
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException ex)
{
// Retrieve the error messages as a list of strings.
var errorMessages = ex.EntityValidationErrors
.SelectMany(x => x.ValidationErrors)
.Select(x => x.ErrorMessage);
// Join the list to a single string.
var fullErrorMessage = string.Join("; ", errorMessages);
// Combine the original exception message with the new one.
var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
// Throw a new DbEntityValidationException with the improved exception message.
throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
}
}
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
I have NullReferenceException error in forgotten password section. Where is my mistake and how can I fix it? Here are my codes:
my controller :
public ActionResult ForGotPasswordSent(ForGotModel forgetModel)
{
User user = _userService.GetUserByEmail(forgetModel.Email);
if (user.IsActive)
{
var objEmail = new EmailHelper();
Message msg = new Message();
msg.SuccessMessage = "You have sent the mail,Please verify that";
msg.IsSuccess = true;
string strBody = "Thanks for using the forgot password function.You need to set new password to your account, please click here to proceed";
bool result = objEmail.SendMail("noreply#xx.com", "xxtest#gmail.com", "", "Activate Your Account", strBody, true);
if (result)
return View("Activation", msg);
else
return View("Activation");
}
else
{
this.ModelState.AddModelError("", "You have to activate your account");
return View("Activation");
}
}
my User class:
public class User : IPrincipal
{
public int Id { get; set; }
[Required(ErrorMessage = "Kullanıcı adı girilmesi zorunludur.")]
[Display(Name = "Kullanıcı Adı")]
public string Username { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
[Required(ErrorMessage = "Password Required")]
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 bool IsActive { get; set; }
public bool IsAdmin { get; set; }
public bool IsDeleted { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
my ForgotModel
public class ForGotModel
{
[Required]
[Display(Name = "Email")]
public string Email { get; set; }
}
_userService.GetUserByEmail method:
public User GetUserByEmail(string email)
{
var user = _userRepository.Get(x => x.Email == email);
return user;
}
You probably will want to add a null check to user before checking the IsActive property. Try this:
if (user != null && user.IsActive)
GetUserByEmail might return null, when no user is found. Verify that your User object is not null before checking for user.IsActive.