Partial Model Validation in MVC4 - c#

I have a PartialView that is a form used to create or modify a user and implements the ViewModel DynamicActionUserModel. The view that referrences this partialView shows a table of all MembershipUsers and gives the ability to create a new user Membership.CreateUser() or modify a user 'Membership.UpdateUser()`. The form in the partialView does an ajax post to my controller to submit data.
The issue I'm running into is that when a user is created their userName, email, password and role is serialized back to the controller as DynamicActionUserModel.RegisterModel and validated, but when a user is modified, password is not a property that is available (nor do I want to make it available to modify on the client side) so it isn't set in DynamicActionUserModel.RegisterModel and ModelState.IsValid is always false.
Perhaps the design of my model and view needs to change, or is there a way to validate the model but ignore password when a user is being modified? Not sure what the best practice is for this one.
I guess another option would be to create another ViewModel and another partialView specifically for modifying a user but that seems sloppy.
Model
public class DynamicActionUserModel {
public string Action { get; set; }
public RegisterModel RegisterModel { get; set; }
}
public class RegisterModel {
[Required]
[Display(Name = "User Name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.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; }
public string[] SelectedRoles { get; set; }
public MultiSelectList Roles { get; set; }
}
Controller
[HttpGet]
public ActionResult CreateUser() {
var model = new DynamicActionUserModel {
Action = "CreateUser",
RegisterModel = new RegisterModel {
Roles = new MultiSelectList(System.Web.Security.Roles.GetAllRoles())
}
};
return PartialView("_UserPartial", model);
}
[HttpGet]
public ActionResult ModifyUser() {
var model = new DynamicActionUserModel {
Action = "ModifyUser",
RegisterModel = new RegisterModel {
Roles = new MultiSelectList(System.Web.Security.Roles.GetAllRoles())
}
};
return PartialView("_UserPartial", model);
}
[HttpPost]
public ActionResult ModifyUser(DynamicActionUserModel model) {
bool isEqual = true;
if(!ModelState.IsValid) { // this is always false because password is empty
return PartialView("_UserPartial", model);
}
var user = Membership.GetUser(model.RegisterModel.UserName);
// do stuff
Membership.UpdateUser(user);
return Json(new {success = false});
}
View
#using RobotDog.Models
#model IEnumerable<RobotDog.Models.UserModel>
<!-- table of users -->
<div class="modify-form">
#Html.Action("ModifyUser")
</div>
<div class="create-user-form">
#Html.Action("CreateUser")
</div>
PartialView
#model RobotDog.Models.DynamicActionUserModel
#using(Html.BeginForm(Model.Action,"Admin", FormMethod.Post, new { #class = "ajax" })) {
<!-- Email -->
#Html.TextBoxFor(x => x.RegisterModel.Email, new { #class = inputSize, placeholder = "Email"})
<!-- UserName -->
#if(Model.Action == "ModifyUser") {
#Html.HiddenFor(x => x.RegisterModel.UserName)
<span class="input-xlarge uneditable-input">#Html.DisplayNameFor(x => x.RegisterModel.UserName)</span>
} else {
#Html.TextBoxFor(x => x.RegisterModel.UserName, new { #class = inputSize, placeholder = "User Name" })
}
<!-- Password -->
#if(Model.Action == "Createuser") {
#Html.PasswordFor(x => x.RegisterModel.Password, new { #class = inputSize, placeholder = "Password"})
}
<!-- Roles -->
#Html.ListBoxFor(x => x.RegisterModel.SelectedRoles, Model.RegisterModel.Roles)
<!-- Submit -->
<input type="submit" value="Submit" class="btn"/>
}

Try with ModelState.Remove("password") before calling ModelState.IsValid, but as suggested here if a property is not always required you should not mark it as required.

Have you looked at ModelState.IsValidField ?
Note: even as of MVC4 the documentation is backwards and should say :
Determines whether there are any ModelError objects that are associated with or prefixed with the specified key.
I've made a little extension method helper for this:
public static class ModelStateHelpers
{
public static bool IsValidFor<TModel, TProperty>(this TModel model,
System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression,
ModelStateDictionary modelState)
{
string name = ExpressionHelper.GetExpressionText(expression);
return modelState.IsValidField(name);
}
}
Usage is simple:
bool billingValid = model.IsValidFor(x => x.CheckoutModel.BillingAddress, ModelState);

Related

Implementing MVC design pattern with Repositories and Mapping, C#

I have a problem with implementing the CRUD operations by using repositories, view models, and mapping in my ASP.Net MVC project. The "details"(read the information about one object) and "index"(read the whole list of objects), controllers are working.
I am mapping the Model to ViewModel and then display it in View. But for Create, Update and Delete operations, I should map the ViewModel to the Model. Could you tell me where am I wrong?
Model
public class User
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Unique]
[Required]
[MaxLength(100)]
public string Email { get; set; }
[Required]
public string Password { get; set; }
public string Phone { get; set; }
public bool IsAdmin { get; set; }
}
Base repository
public class BaseRepository<T> : IBaseRepository<T> where T : class
{
private RushHourContext db = null;
private DbSet<T> table = null;
public BaseRepository()
{
this.db = new RushHourContext();
table = db.Set<T>();
}
public BaseRepository(RushHourContext db)
{
this.db = db;
table = db.Set<T>();
}
public IEnumerable<T> SelectAll()
{
return table.ToList();
}
public T SelectByID(object id)
{
return table.Find(id);
}
public void Insert(T obj)
{
table.Add(obj);
}
public void Update(T obj)
{
table.Attach(obj);
db.Entry(obj).State = EntityState.Modified;
}
public void Delete(object id)
{
T existing = table.Find(id);
table.Remove(existing);
}
public void Save()
{
db.SaveChanges();
}
}
Interface for Repository
public interface IBaseRepository<T> where T : class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Controller
private RushHourContext _db = new RushHourContext();
private IBaseRepository<User> _repository = null;
public UsersController()
{
this._repository = new BaseRepository<User>();
}
public ActionResult Index()
{
if (!LoginUserSession.IsStateAdmin)
{
return RedirectToAction("Login");
}
var users = _repository.SelectAll().ToList();
var userViewModel = Mapper.Map<List<UserViewModel>>(users);
return View(userViewModel);
}
public ActionResult Details(int? id)
{
var users = _repository.SelectByID(id);
var userViewModel = Mapper.Map<UserViewModel>(users);
return View(userViewModel);
}
public ActionResult Create(User user)
{
var users = _repository.Insert(user); // THIS CODE HERE IS WRONG
var userViewModel = Mapper.Map<User>(users);
return View(userViewModel);
}
UserViewModel
public class UserViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "Please enter User Name.")]
[Display(Name = "User Name")]
public string Name { get; set; }
[MaxLength(100)]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[Display(Name = "Password")]
public string Password { get; set; }
public string Phone { get; set; }
public bool IsAdmin { get; set; }
}
View
#model RushHour.ViewModels.UserViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<div>
#Html.AntiForgeryToken()
#using (Html.BeginForm("Create", "Users", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div>#Html.LabelFor(model => model.Id)</div>
<div>#Html.TextBoxFor(model => model.Id)</div>
<div>#Html.ValidationMessageFor(model => model.Id)</div>
<div>#Html.LabelFor(model => model.Name)</div>
<div>#Html.TextBoxFor(model => model.Name)</div>
<div>#Html.ValidationMessageFor(model => model.Name)</div>
<div>#Html.LabelFor(model => model.Password)</div>
<div>#Html.TextBoxFor(model => model.Password)</div>
<div>#Html.ValidationMessageFor(model => model.Password)</div>
<div>#Html.LabelFor(model => model.Email)</div>
<div>#Html.TextBoxFor(model => model.Email)</div>
<div>#Html.ValidationMessageFor(model => model.Email)</div>
<div>#Html.LabelFor(model => model.Phone)</div>
<div>#Html.TextBoxFor(model => model.Phone)</div>
<div>#Html.ValidationMessageFor(model => model.Phone)</div>
<div>#Html.LabelFor(model => model.IsAdmin)</div>
<div>#Html.TextBoxFor(model => model.IsAdmin)</div>
<div>#Html.ValidationMessageFor(model => model.IsAdmin)</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
</div>
Your model in your Create view is your UserViewModel and that should be passed into the controller, not User.
The pattern you have set up suggests the user will first be on the Create view while entering new user information. So, they will navigate to this view without passing any objects to it on their first trip. If that's the case, you'll want a parameterless constructor for the first visit where you'll just create a new UserViewModel and pass it in. You're then navigating back to this view after user creation which will present a form to them and be very confusing for user experience. You'll probably want to redirect to a confirmation page or the login page with a message saying user created.
Whenever you make changes to the data, EntityFramework won't make those changes until you call SaveChanges on the repository. It's odd that you aren't saving your new user immediately after it being created.
DbSet.Add
DbContext.SaveChanges
For the create function use UserViewModel instead of User. Then map from UserViewModel to User to insert in database. After, if you want to display the saved data, then return UserViewModel object.
Try the following code.
[HttpPost]
public ActionResult Create(UserViewModel userViewModel)
{
var user = new User();
var newUser = Mapper.Map(userViewModel, user);
_repository.Insert(newUser);
_repository.Save();
return View(userViewModel);
}
you can do like this:
[HttpPost]
public ActionResult Create(UserViewModel userViewModel)
{
var user = Mapper.Map<User>(userViewModel);
_reoisitory.Add(user);
}

C# ASP.NET MVC - Model gets nulled on POST

I've been struggling with this problem for a while now and I can't find any solution on that solves it for me.
I'm trying to add a string to my model in a view, however when the model gets returned to my HttpPost everything is null except for the string that I'm trying to fill
My model looks like this
namespace WhatsUp.Models {
public class ChatModel
{
public Account user { get; set; }
public Contact contact { get; set; }
public Chat chatA { get; set; }
public Chat chatB { get; set; }
public string newMessage { get; set; }
public ChatModel() { }
public ChatModel(Account user, Contact contact, Chat chatA, Chat chatB)
{
this.user = user;
this.contact = contact;
this.chatA = chatA;
this.chatB = chatB;
}
}
}
My controller looks like this
namespace WhatsUp.Controllers
{
public class ChatsController : Controller
{
IMessageRepository repository = new DbMessageRepository();
IContactRepository contactRepository = new DbContactRepository();
IAccountRepository accountRepository = new DbAccountRepository();
IChatRepository chatRepository = new DbChatRepository();
// GET: Chats
public ActionResult Index()
{
return View();
}
public ActionResult Chat(int contactId)
{
Account user = accountRepository.GetAccount(User.Identity.Name);
Contact contact = contactRepository.GetContact(contactId);
Chat chatA = chatRepository.GetChat(user.id, contact.accountId ?? default(int));
if(chatA == null)
{
chatRepository.CreateChat(user.id, contact.accountId ?? default(int));
}
Chat chatB = chatRepository.GetChat(contact.accountId ?? default(int), user.id);
if(chatB == null)
{
chatRepository.GetChat(user.id, contact.accountId ?? default (int));
}
ChatModel chatModel = new ChatModel(user, contact, chatA, chatB);
return View(chatModel);
}
[HttpPost]
public ActionResult Chat(ChatModel chatModel)
{
repository.SendMessage(new Message(0, chatModel.newMessage, chatModel.chatA.Id));
ModelState.Clear();
return View(chatModel);
}
}
}
And my view
#using WhatsUp.Models
#model ChatModel
#{
ViewBag.Title = "Chat";
}
<h2>Chat with #Model.contact.name</h2>
<div id="chatWindow" style="overflow-y:auto; overflow-x:hidden; height:500px;">
<script>
var element = document.getElementById('chatWindow');
element.scrollTop = element.offsetHeight
</script>
</div>
#using (Html.BeginForm())
{
#Html.TextAreaFor(x => x.newMessage, new { #class = "form-control"})
<input type="submit" value="Send" class="btn btn-primary" />
}
Always use a ViewModel for that kind of things. Follow this steps:
First, create a ViewModel that will contain your message and the chat ids.
Second, ake the ids as a hidden field in your view.
Last thing is, in your POST action, to make sure to get each Chat instance via their id before sending the message.

Send dropdownlist value back to variable MVC 4

Hi there I have a table of jobs with a specific id for them
id title
1 Manager
2 Engineer
3 IT
I have created a way so that I am able to load these value from a database with this table and data.
Here is my model
[Display(Name = "Type: "),
Required(ErrorMessage = "Required")]
public IEnumerable<SelectListItem> jobTitle { get; set; }
Here is my controller
public void loadDropDown()
{
JobModel selectedJob = new JobModel();
reviewlogsEntities db = new reviewlogsEntities();
IEnumerable<SelectListItem> type = db.types.Select(m => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)m.id),
Text = m.title
});
ViewBag.JobTitle = type;
}
[HttpGet]
public ActionResult DisplayJobTitle()
{
if (Request.IsAuthenticated)
{
loadDropDown();
return View();
}
else
{
return RedirectToAction("index", "home");
}
}
[HttpPost]
public ActionResult DisplayJobTitle(JobModel curJob)
{
loadDropDown();
if (ModelState.IsValid)
{
return View();
}
else
{
ModelState.AddModelError("", "Looks like there was an error with your job title, please make sure a job title is selected.");
}
return View();
}
And Lastly what my view looks like:
#Html.ValidationSummary(true, "Please try again.")
#using (Html.BeginForm())
{
#Html.LabelFor(model => model.type)
#Html.DropDownList("JobTitle")
<input class="submitButton" type="submit" value="Show Job Info" style="margin-left:126px;margin-bottom: 20px;" />
}
See the problem is that variable jobTitle in my model is null because I never give it a value and since I don't give it a value the form thinks it is not filled out since it must be required and will not submit properly. My question is how do I return the value of whatever the users selected as their job title back to jobTitle variable when the form is submitted so that I won't get a submission failure.
Model should accept selected value not collection of items:
[Display(Name = "Type: "),
Required(ErrorMessage = "Required")]
public int jobTitle { get; set; }
You need a property to map selected value in your model like:
[Display(Name = "Type: "),
Required(ErrorMessage = "Required")]
public int SelectedjobTitle { get; set; }
and then in your View:
#Html.DropDownList("SelectedJobTitle",ViewBag.JobTile as IEnumerable<SelectListItem>)
use the DropDownListFor like this:
#Html.DropDownListFor(model => model.JobTitle, Model.Jobs)
on your model:
[Display(Name = "Type: "),
Required(ErrorMessage = "Required")]
public int JobTitle { get; set; }
public IEnumerable<SelectListItem> Jobs { get; set; }
don't forget to fill the "Jobs" on your controller.

Bind Model to Radio Buttons on POST

I am trying to expand on the user register form that is generated using EF6 and MVC, I want to be able to display a list of user roles that is displayed as radio buttons, which I believe I have done. However the trouble I am having is when I post the form back to the controller, it's not binding the selected option back to the view model. What am I doing wrong?
My View Model:
public class RegisterViewModel
{
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "Username")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 4)]
public string Username { get; set; }
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "FirstName")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 2)]
public string FirstName { get; set; }
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "Surname")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 2)]
public string Surname { get; set; }
//Other fields removed to save space
[Required]
[Display(Name = "Roles")]
public IEnumerable<IdentityRole> UserRoles { get; set; }
}
I have a list of Identity Roles that I want to pass to the view like so:
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
var model = new RegisterViewModel();
model.UserRoles = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>()).Roles.ToList();
return View(model);
}
And on the view I display the roles like so:
<div class="panel-body">
#foreach (var item in Model.UserRoles)
{
<div class="col-md-8">
<div>
#Html.RadioButtonFor(m => m.UserRoles, item.Name)
#Html.DisplayFor(m => item.Name, new { #class = "col-md-3 control-label" })
</div>
</div>
}
#Html.ValidationMessageFor(m => m.UserRoles, "", new { #class = "text-danger" })
</div>
However when the form is submitted back the model is never valid as the role is never bound. (Or at least that's what I believe) Any ideas?
You do not want to have the radio buttons tied to the list of values, you need to change you model to a list of roles and the selected role like this
//Other fields removed to save space
[Required]
[Display(Name = "Role")]
public IdentityRole UserRole { get; set; }
[Display(Name = "Roles")]
public IEnumerable<IdentityRole> UserRoles { get; set; }
Then you create the radio button like this
#Html.RadioButtonFor(m => m.UserRole, item.Name)
This will then post back the selected value to the UserRole property.
NOTE: I think you will also need to play with the value of the radiobutton to get it to populate back to the UserRole since I do not think item.Name would work. You may want to post back to a string field with the name and then look up the proper role in the post method of the controller.
I looked into this (Even tested the theory since I had one available) and it is impossible. You can bind any sub property of the selected object to your view model but not the object in its entirety.
Here is my reference from stack overflow.
Html controls (input, textarea, select) post back their name/value pairs. In your case the form data associated with the radio button would be UserRoles: someValue.
Assuming your POST method is public ActionResult Register(RegisterViewModel model), the DefaultModelBinder first initializes an instance of RegisterViewModel then finds the matching form data name/value pair and tries to set the value of property UserRoles to the string "someValue" which of course fails because UserRoles is a complex object and UserRoles becomes null.
You cannot bind html controls to complex objects unless you create a custom ModelBinder and/or ValueProviders and even then it will only set one property of you model because you are only posting back one value.
You need to create a view model with properties representing what you want to display/edit in the view, for example (assuming typeof IdentityRole has a property int ID)
public class RegisterViewModel
{
[Required]
[Display(ResourceType = typeof(ResourceStrings), Name = "Username")]
[StringLength(50, ErrorMessageResourceType = typeof(ResourceStrings), ErrorMessageResourceName = "MinLengthValidation", MinimumLength = 4)]
public string Username { get; set; }
....
// For binding the selected roles
[Required(ErrorMessage = "Please select a role")]
public int ID SelectedRole { set; set; }
// For displaying the available roles
[Display(Name = "Roles")]
public IEnumerable<IdentityRole> UserRoles { get; set; }
}
Then in the view
#model yourAssembly.RegisterViewModel
#using (Html.BeginForm())
{
....
foreach(var role in Model.UserRoles)
{
#Html.RadioButtonFor(m => m.SelectedRole, role.ID, new { id = role.Name })
<label for="#role.Name">#role.Name</label>
}
#Html.ValidationMessageFor(m => m.SelectedRole)
....
}
and when you post back, you can get the ID of the selected role from the models SelectedRole property.

bypassing model validation in controller?

I have created an ADO.NET model of my database.
Created a new controller with CRUD (entity framework and using the ADO.NET entity model I created).
In my database I have a simple Users table. The Password row in the table will hold the users passwords encrypted with SimpleCrypto (PBKDF2).
In my ADO.NET Users.cs model I have added following validation:
[Required]
[DataType(DataType.Password)]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string Password { get; set; }
That works with jQuery in the browser with validation.
But in my controller I am encrypting the Password, and then the Password string will be way more than 20 chars in lenght.
var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);
user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;
_db.Users.Add(user);
_db.SaveChanges();
And this gives me and "Validation failed for one or more entities."-error.
I can copy the user over to a "var newUser" and then set all the properties there, but isn't there a easier way to bypass the model validation in this case?
EDIT: If I remove the validation of the Password prop in the model then everything works. So it is the validation that gives me the error because I alter the Password from 6-20 length chars to +100 lengt chars because of the encryption in the controller.
EDIT: Complete controller section inserted to this question.
[HttpPost]
public ActionResult Create(Users user)
{
if (!ModelState.IsValid)
{
return View();
}
if (_db.Users.FirstOrDefault(u => u.Email == user.Email) != null)
{
ModelState.AddModelError("", "User already exists in database!");
return View();
}
var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);
user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;
_db.Users.Add(user);
_db.SaveChanges();
return RedirectToAction("Index", "User");
}
This is where ViewModels enter the game. You should create a model which you pass to the view and map that back to the domain model later.
The ViewModel:
public class RegisterModel
{
[Required]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string Password { get; set; }
}
The domain model (your current User model):
public class User
{
// other properties..
[Required]
public string Password { get; set; }
}
You can use these models in your controller like this:
The GET action:
public ActionResult Register()
{
var registerModel = new RegisterModel();
return View(registerModel)
}
With a view like this:
#model RegisterModel
#Html.LabelFor(model => model.UserName)
#Html.TextBoxFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
#Html.LabelFor(model => model.Password)
#Html.PasswordFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
And the POST action:
[HttpPost]
public ActionResult Register(RegisterModel registerModel)
{
// Map RegisterModel to a User model.
var user = new User
{
UserName = registerModel.UserName,
Password = registerModel.Password // Do the hasing here for example.
};
db.Users.Add(user);
db.SaveChanges();
}
You say your password encryption is occurring in the controller. In this case shouldn't you be encrypting after validation? For example:
public ActionResult SomeControllerAction(UserViewModel user)
{
if (!ModelState.IsValid)
{
// at this point the human readable (and assuming < 20 length) password
// would be getting validated
return View(user);
}
// now when you're writing the record to the DB, encrypt the password
var crypto = new SimpleCrypto.PBKDF2();
var encryptedPass = crypto.Compute(user.Password);
user.Password = encryptedPass;
user.PasswordSalt = crypto.Salt;
_db.Users.Add(user);
_db.SaveChanges();
// return or redirect to whatever route you need
}
If you wanted to specifically control your validation, then try implementing IValidatableObject on your view model class and perform validation here, instead of via attributes. For example:
public class UserViewModel : IValidatableObject
{
public string Username { get; set; }
public string Password { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// validate the unencrypted password's length to be < 20
if (this.Password.Length > 20)
{
yield return new ValidationResult("Password too long!");
}
}
}
If i understand correctly you have a database table with a password field.
According to your model this password field is 20 characters long
[StringLength(20, MinimumLength = 6)]
And you want to insert a value greater then 20 characters.
If entity framework did not stop you then you would get a database error.(Entity framework doesn't know there is a mismatch between your data model and the database and it doesn't wanna take the risk of pushing the insert through)
I assume however that you ment to specify a clientSide validation rule on your viewmodel and not a length constraint on the database.
I hope you see why this is a confusing setup.
My advice would be to either split your viewModel and model up so you can post a viewModel with unencrypted password of maxlength 20 that you can convert to a model password with length 100.
If you find that too much hassle you could create an unmapped password property which you set from html when you post it and you convert it to the password property in your controller.
Your class could look like this :
public class RegisterModel
{
[Required]
public string UserName { get; set; }
[Required]
[NotMapped]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Password")]
public string PlainTextPassword { get; set; }
[Required]
[StringLength(300)]//This is optional
[DataType(DataType.Password)]
public string Password { get; set; }
}

Categories