mvc model and viewmodel?
so, i have a "User" model that has a lot of fields but following are the impt ones:
public int Id {get;set;}
public string Username { get; set; }
public string Pwd { get; set; }
and i have a view model that validates the password that i use on a different controller:
public class ConfirmPassword : IValidatableObject
{
[Required]
public string Password { get; set; }
[Required(ErrorMessage="Confirm Password field is required.")]
public string ConfirmPwd { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string regex1 = @"^.{8,10}$"; // 8 - 10 characters
Match requirement1 = Regex.Match(Password, regex1);
if (Password != ConfirmPwd)
yield return new ValidationResult("Password and Confirm Password is not identical.");
if (!requirement1.Success)
yield return new ValidationResult("Password must be between 8 and 10 characters.");
}
}
is there a way where i can connect the view model to my model entity? or just copy paste the codes my only option? I can't do copy paste since the code needs to have a IValidateObject which will mess up the who开发者_JAVA技巧le User entity as there's a ton of background auditing happeneing.. I just need to validate the passwords whenever a profile is edited / created.
EDIT: so sorry if everybody got confused. basically, i have multiple validations that i need on the confirm passwords that can't be handled by dataannotations, ergo the confirmpassword viewmodel. this validation i want to be applied onto the User model but without adding the "ConfirmPassword" field into it. as i dont need another field on the database. My question is how do i force the validations i have from the confirmapassword to trigger whenever the view POSTs and the password field does not meet its requirements?
namespace
{
public class User
{
public int Id {get;set;}
public string Username { get; set; }
public string Pwd { get; set; }
}
}
namespace
{
public class ConfirmPassword : IValidatableObject
{
[Required]
public string Password { get; set; }
[Required(ErrorMessage="Confirm Password field is required.")]
public string ConfirmPwd { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string regex1 = @"^.{8,10}$"; // 8 - 10 characters
string regex2 = @"(?:.*?[A-Z]){1}"; // 1 uppercase
string regex3 = ""; // 1 lowercase
string regex4 = ""; // 1 numeric
Match requirement1 = Regex.Match(Password, regex1);
Match requirement2 = Regex.Match(Password, regex2);
Match requirement3 = Regex.Match(Password, regex3);
Match requirement4 = Regex.Match(Password, regex4);
if (Password != ConfirmPwd)
yield return new ValidationResult("Password and Confirm Password is not identical.");
if (!requirement1.Success)
yield return new ValidationResult("Password must be between 8 and 10 characters.");
if (!requirement2.Success)
yield return new ValidationResult("Password must contain at least 1 uppercase letter.");
if (!requirement3.Success)
yield return new ValidationResult("Password must contain at least 1 lowercase letter.");
if (!requirement4.Success)
yield return new ValidationResult("Password must contain at least 1 numeric character.");
}
}
}
You can use the decorator patter in your view model to do what you like. You can also use the System.ComponentModel.DataAnnotations
namespace attributes to do all your validation for you.
public class ConfirmPassword
{
User model;
[Required]
public string Username
{
get { return this.model.Username; }
set { this.model.Username = value; }
}
[Required]
[DataType(DataType.Password)]
public string Password
{
get { return this.model.Pwd; }
set { this.model.Pwd = value; }
}
[Required(ErrorMessage = "Confirm Password field is required.")]
[Compare("NewPassword",
ErrorMessage = "The new password and confirmation password do not match.")]
[RegularExpression(@"^.{8,10}$")]
[DataType(DataType.Password)]
public string ConfirmPwd { get; set; }
public ConfirmPassword()
{
this.model = new User();
}
public ConfirmPassword(User model)
{
this.model = model;
}
}
Ok, I am still a little iffy on what you mean by connect view model to model entity... I think what you want is to now check if the password from the actual user matches the password passed in to the view model.
I personally would not do this in the view model itself, but rather in the controller and would add a ModelState.AddError if the password was incorrect.
The normal input validation can happen on the server or client side if you are using client side validation, but you can't check the password client side, so it will have to go to the server.
public LoginViewModel()
{
[Required]
public string LoginId {get; set;}
[DataType(DataType.Password)]
public string Password {get; set;}
[DataType(DataType.Password)]
public string ConfirmPassword {get; set;}
// this validation is not db related and can be done client side...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string regex1 = @"^.{8,10}$"; // 8 - 10 characters
Match requirement1 = Regex.Match(Password, regex1);
if (Password != ConfirmPwd)
yield return new ValidationResult("Password and Confirm Password is not identical.");
if (!requirement1.Success)
yield return new ValidationResult("Password must be between 8 and 10 characters.");
}
}
[HttpGet]
public ActionResult Login()
{
var model = new LoginViewModel();
return View("Login",model);
}
[HttpPost]
public ActionResult Login(LoginViewModel model)
{
var user = GetUserFromRepositoryByUsername(model.username);
if(user != null)
{
if(user.password == model.Password)
{
RedirectToAction("YouLoggedInYay!");
}
}
// if we made it this far, the user didn't exist or the password was wrong.
// Highlight the username field red and add a validation error message.
ModelState.AddError("Username","Your credentials were invalid punk!");
return View("Login",model);
}
I would include a userId in your ViewModel or add it on the URL so the controller can pick it up.
After validating the password combo you use the Id to retrieve the relevant User and update it with the new password. You can just do this within your new password post action.
You may want to match with the old password btw.
From what I believe, your UI validations and Logic validations should not be mixed up. It is worth doing in over again in the Logic even if it is the same thing. Basically, it is not the responsibility of the Entity object to carry the validations. It might be some service layer class that does it for the Entity. And you can probably throw an exception at that point.So it is handled in completely different ways in the UI and the Logic.
"I just need to validate the passwords whenever a profile is edited / created"
Use data annotations combined with IsValid on the ViewModel to check for failures. As far as mapping a Model to a View Model just use a decorator pattern.
Use System.ComponentModel.DataAnnotations (they even have a regular expression validator you can use) Once passwords are verified against a policy, convert them to an MD5 hash and store that, not the password value If all else fails there is nothing wrong with creating a separate UserValidation Class and share logic between the View Model and Model e.g. they both call the same methods to determine validity (reducing code).
精彩评论