Validation Summary for Collections - asp.net-mvc

EDIT: upgraded this question to MVC 2.0
With asp.net MVC 2.0 is there an existing method of creating Validation Summary that makes sense for models containing collections? If not I can create my own validation summary
Example Model:
public class GroupDetailsViewModel
{
public string GroupName { get; set; }
public int NumberOfPeople { get; set; }
public List<Person> People{ get; set; }
}
public class Person
{
[Required(ErrorMessage = "Please enter your Email Address")]
[RegularExpression(#"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage = "Please enter a valid Email Address")]
public string EmailAddress { get; set; }
[Required(ErrorMessage = "Please enter your Phone Number")]
public string Phone { get; set; }
[Required(ErrorMessage = "Please enter your First Name")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter your Last Name")]
public string LastName { get; set; }
}
The existing summary <%=Html.ValidationSummary %> if nothing is entered looks like this.
The following error(s) must be corrected before proceeding to the next step
* Please enter your Email Address
* Please enter your Phone Number
* Please enter your First Name
* Please enter your Last Name
* Please enter your Email Address
* Please enter your Phone Number
* Please enter your First Name
* Please enter your Last Name
The design calls for headings to be inserted like this:
The following error(s) must be corrected before proceeding to the next step
Person 1
* Please enter your Email Address
* Please enter your Phone Number
* Please enter your First Name
* Please enter your Last Name
Person 2
* Please enter your Email Address
* Please enter your Phone Number
* Please enter your First Name
* Please enter your Last Name
Answer Based on Pharcyde's answer.
public static MvcHtmlString NestedValidationSummary(this HtmlHelper helper)
{
if (helper.ViewData.ModelState.IsValid)
return MvcHtmlString.Empty;
// create datastructure to group error messages under a given key (blank key is for general errors)
var errors = new Dictionary<string,List<string>>();
foreach (KeyValuePair<string, ModelState> keyPair in helper.ViewData.ModelState)
{
foreach (ModelError error in keyPair.Value.Errors)
{
//determine the 'key' for the group in which this error belongs
var key = keyPair.Key.Split(']')[0];
if (key.Contains("People["))
key = "Person " + key.Split('[')[1];
else
key = string.Empty;
if(!errors.ContainsKey(key))
errors.Add(key,new List<string>());
//now add message using error.ErrorMessage property
errors[key].Add(error.ErrorMessage);
}
}
// generate the HTML
var ul = new TagBuilder("ul");
foreach (KeyValuePair<string, List<string>> errorPair in errors.OrderBy(p=>p.Key))
{
var li = new TagBuilder("li");
if(!string.IsNullOrEmpty(errorPair.Key))
li.InnerHtml += string.Format("<p class=\"no-bottom-margin\"><strong>{0}</strong></p>",errorPair.Key);
var innerUl = new TagBuilder("ul");
foreach (var message in errorPair.Value)
{
var innerLi = new TagBuilder("li");
innerLi.InnerHtml = message;
innerUl.InnerHtml += innerLi.ToString(TagRenderMode.Normal);
}
li.InnerHtml += innerUl.ToString(TagRenderMode.Normal);
ul.InnerHtml += li.ToString(TagRenderMode.Normal);
}
return MvcHtmlString.Create(ul.ToString(TagRenderMode.Normal));
}

You are going to have to extend the HtmlHelper methods and roll your own. Heres the bit of code that is important for your situation where you need a group by:
//HtmlHelper being extended
if(helper.ViewData.ModelState.IsValid)
{
foreach(KeyValuePair<string,ModelState> keyPair in helper.ViewData.ModelState)
{
//add division for group by here using keyPair.Key property (would be named "Person" in your case).
foreach(ModelError error in keyPair.Value.Errors)
{
//now add message using error.ErrorMessage property
}
}
}

Related

ASP.NET MVC List Concatenating Parent Table Field

This is a bit embarrassing as I'm sure the answer is simple.
I'm using Entityframework and Code First techniques trying to build my first functional MVC form while following the excellent ASP.NET tutorials.
How do I display a string that includes Parent information to the table being queried. I wanted to include a parent value in the string being used for the dropdown list .... or should I be doing this the opposite way and selecting the parent and have the children show up as a result of the selection?
I thought it would be as simple as adding to the model since it is already talking to its parent. Intellisense is okay with it :-)
Model Class
public class SourceLocation
{
[Key]
public int SourceLocationID { get; set; }
public int SourceID { get; set; }
[Required]
[Display(Name = "Product Type")]
[StringLength(25)]
public string ProductType { get; set; }
[Required]
[Display(Name = "Source Location")]
[StringLength(50)]
public string SamplingLocation { get; set; }
[Display(Name = "Sampling Location Notes")]
public string LocationNotes { get; set; }
public string SourceProductType
{
get
{
return CementSources.SampleSource + " " + ProductType + " ex " + SamplingLocation;
}
}
public virtual CementSource CementSources { get; set; }
}
}
The Controller referencing SourceSampleType is configured thusly.
// GET: Specifications/Create
public ActionResult Create()
{
ViewBag.FieldID = new SelectList(db.Fields, "FieldID", "FieldName");
ViewBag.SourceLocationID = new SelectList(db.SourceLocations, "SourceLocationID", "SourceProductType");
ViewBag.SpecificationTypeID = new SelectList(db.SpecificationTypes, "SpecificationTypeID", "SpecificationTypeName");
return View();
}
When I try to create a new Specimen which is configured to show SourceSampleType, the error is:
There is already an open DataReader associated with this Command which must be closed first.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
Source Error:
Line 28: get
Line 29: {
Line 30: return CementSources.SampleSource + " " + ProductType + " ex " + SamplingLocation;
Line 31: }
Line 32: }
Am I not using this syntax correctly or is it something related to Eager/Lazy loading that I have yet to parse and understand?
The error occurs because you iterating through the results of SourceLocation but in each iteration, you executing another query to get the value of its CementSources property.
You need to remove the SourceProductType property from the model, and use Include() in the query to include CementSources
ViewBag.SourceLocationID = db.SourceLocations
.Include(x => x.CementSources)
.Select(x => new SelectListItem
{
Value = x.SourceLocationID.ToString(),
Text = string.Format("{0} {1} ex {2}", x.CementSources.SampleSource, x.ProductType, x.SamplingLocation)
});

Display one error message for 3 textboxes with mvc 4 razor engine

I'm Currently validating a fax number in which I need to to only display one error message for all of 3 of the textboxes. Like a Summary
It seems a bit picky/silly of a business requirement as there are 3 textboxes and all are required by themselves but if someone has done this before that would be nice.
In my Model:
[Required(ErrorMessage = "Fax is Required...")]
[RegularExpression("^[0-9]{3}$", ErrorMessage = "Not a valid fax #")]
public string poc_fax_1 { get; set; }
[Required(ErrorMessage = "Fax is Required...")]
[RegularExpression("^[0-9]{3}$", ErrorMessage = "Not a valid fax #")]
public string poc_fax_2 { get; set; }
[Required(ErrorMessage = "Fax is Required...")]
[RegularExpression("^[0-9]{4}$", ErrorMessage = "Not a valid fax #")]
public string poc_fax_3 { get; set; }
View:
(#Html.TextBoxFor(model => model.poc_fax_1, new { #class = "input-mini", #maxlength=3 })) -
#Html.ValidationMessageFor(m=>m.poc_fax_1)
#Html.TextBoxFor(model => model.poc_fax_2, new { #class = "input-mini", #maxlength=3 }) -
#Html.ValidationMessageFor(m=>m.poc_fax_2)
#Html.TextBoxFor(model => model.poc_fax_3, new { #class = "input-mini", #maxlength=4 })
#Html.ValidationMessageFor(m=>m.poc_fax_3)
Note: Image is BEFORE I fixed the numeric entry only and thus updated the question.
Instead of using annotations for each piece of the fax number you can check in the controller action if the 3 fields together are valid
Something like this: check in your controller
if (faxfield1 != null && faxfield2 != null && faxfield3 != null)
{
ModelState.AddModelError("FaxError", "Fax is not valid");
}
Then use this in your view (once)
#Html.ValidationMessage("FaxError")
Note: this is just showing how you can do it in a other way, you'll have to use other validation ofc :)

Forgot Password + Email Confirmation in ASP.NET MVC WebMatrix [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
It appears that these two features have a set of helper functions and schema in the WebMatrix code to get going. However, there are no controller methods or views to get it done, so you have to implement yourself.
Is there any samples anywhere where I can just copy this code into my app? I'm looking for something to:
Generate Forgot Password Email
Generate Confirmation Email
Forgot Password view + Controller method
Resend confirmation email view + Controller method
FORGOT PASSWORD FUNCTIONALITY
The other day I was trying to create a “forgot password functionality” in asp.net MVC 4. I googled in and out but couldn't get the best solution. I have finally found the way out.
15 simple steps
Part 1
Sending Password Reset Information via Email
Step 1
• Create Mvc 4 c# Internet application template :)
(Account and home controllers will automatically be generated)
• Build and run your project. Register and login.
(Simple membership tables will be generated)
Everything working fine?
Step 2
• Oops!! They don’t ask our email id while registration! In order to send password token to users we need their email id!! So let’s make a few changes in database go to server explorer! ( If u can’t find it u can press Ctrl + alt + S )
• Expand "data connections" and u will see a couple of tables. Open User Profile table.
Add the following columns:
EmailId nvarchar(max)
2.Details nvarchar(max)
Step 3
• Now go to Solution Explorer...Models ... Account model ... Register model
• Add these two properties for Email Id and Details
//new properties
[Required]
[Display(Name="Email ID")]
public string EmailId { get; set; }
[Required]
[Display(Name = "About Yourself")]
public string Details { get; set; }
Step 4
• Now go to Solution Explorer…Views ... Account Views ... Register.cshtml view
• Add these two properties for allowing users to enter email id and other details.
#Html.LabelFor(m => m.EmailId)
#Html.TextBoxFor(m => m.EmailId)
#Html.LabelFor(m => m.Details)
#Html.TextBoxFor(m => m.Details)
Step 5
• Now go to Solution Explorer…Controllers ... Account Controller ... Post version of Register controller action method
• Add these properties for allowing users to enter email id and other details.The changes are highlighted.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { EmailId = model.EmailId, Details = model.Details});
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Why don’t we again build and run our project? Register and fill in the details .Now you will be asked to specify email address also .Add these properties for allowing users to enter email id and other details.
Go to server explorer and right click on User Profile table and Select “Show Table Data” U can view the details you entered for verification.
Step 6
• Now lets implement the password reset functionality  Go to account controller and create the following controller action method (GET )
[AllowAnonymous]
public ActionResult ForgotPassword()
{
return View();
}
• (POST)
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ForgotPassword(string UserName)
{
//check user existance
var user = Membership.GetUser(UserName);
if (user == null)
{
TempData["Message"] = "User Not exist.";
}
else
{
//generate password token
var token = WebSecurity.GeneratePasswordResetToken(UserName);
//create url with above token
var resetLink = "<a href='" + Url.Action("ResetPassword", "Account", new { un = UserName, rt = token }, "http") + "'>Reset Password</a>";
//get user emailid
UsersContext db = new UsersContext();
var emailid = (from i in db.UserProfiles
where i.UserName == UserName
select i.EmailId).FirstOrDefault();
//send mail
string subject = "Password Reset Token";
string body = "<b>Please find the Password Reset Token</b><br/>" + resetLink; //edit it
try
{
SendEMail(emailid, subject, body);
TempData["Message"] = "Mail Sent.";
}
catch (Exception ex)
{
TempData["Message"] = "Error occured while sending email." + ex.Message;
}
//only for testing
TempData["Message"] = resetLink;
}
return View();
}
• The GET controller action just returns the view.
• The POST controller action :
Receives the username
Verifies its existence
Generates Password reset token
Builds URL to be emailed.
Step 7
• Right click on the forgot password action method and add view  The code for the view page will be as below
#{
ViewBag.Title = "Forgot Password";
}
<h2>Forgot Password</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<fieldset>
<legend>Forgot Password Form</legend>
<ol>
<li>
#Html.Label("User Name", new { #for = "UserName" })
#Html.TextBox("UserName")
<span style="color:red;">#TempData["Message"]</span>
</li>
</ol>
<input type="submit" value="Recover" />
</fieldset>
}
• The view page will display a textbox where in user can enter the user name.
Step 8
• Now go to Solution Explorer...Models ... Account model … User Profile View Model. Changes have been highlighted
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
//new properties
public string EmailId { get; set; }
public string Details { get; set; }
}
Step 9
• Now go to Solution Explorer...Views ... Account … Login View.
Now we can see an option to recover his password in case he has forgotten it.
<ul>
<li>
#Html.ActionLink("Register", "Register") if you don't have an account.
</li>
<li>
#Html.ActionLink("Forgot Password", "ForgotPassword") if you want to recover your password.
</li>
</ul>
Part 2
Receiving Password Reset Information from URL
Step 1
• Go to Solution Explorer...Controller ... Account Controller …
Create new Reset Password Action Method
• This method is accepting ‘un’ (which is username) and ‘rt’ (which is password reset token) from the URL.
[AllowAnonymous]
public ActionResult ResetPassword(string un, string rt)
{
UsersContext db = new UsersContext();
//TODO: Check the un and rt matching and then perform following
//get userid of received username
var userid = (from i in db.UserProfiles
where i.UserName == un
select i.UserId).FirstOrDefault();
//check userid and token matches
bool any = (from j in db.webpages_Memberships
where (j.UserId == userid)
&& (j.PasswordVerificationToken == rt)
//&& (j.PasswordVerificationTokenExpirationDate < DateTime.Now)
select j).Any();
if (any == true)
{
//generate random password
string newpassword = GenerateRandomPassword(6);
//reset password
bool response = WebSecurity.ResetPassword(rt, newpassword);
if (response == true)
{
//get user emailid to send password
var emailid = (from i in db.UserProfiles
where i.UserName == un
select i.EmailId).FirstOrDefault();
//send email
string subject = "New Password";
string body = "<b>Please find the New Password</b><br/>" + newpassword; //edit it
try
{
SendEMail(emailid, subject, body);
TempData["Message"] = "Mail Sent.";
}
catch (Exception ex)
{
TempData["Message"] = "Error occured while sending email." + ex.Message;
}
//display message
TempData["Message"] = "Success! Check email we sent. Your New Password Is " + newpassword;
}
else
{
TempData["Message"] = "Hey, avoid random request on this page.";
}
}
else
{
TempData["Message"] = "Username and token not maching.";
}
return View();
}
Step 2
• Right click on the reset password action method and add view  The code for the view page will be as below
#{
ViewBag.Title = "ResetPassword";
}
<h2>Password Mailed :) </h2>
Step 3
• Go to Solution Explorer...Models... Account Models …
Make the following changes.
• We create an instance of UserProfile DB Model and implement db.webpages_Memberships’ as DbSet.Use ‘webpages_Memberships’ as a model.
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<webpages_Membership> webpages_Memberships { get; set; }
}
[Table("webpages_Membership")]
public class webpages_Membership
{
[Key]
public int UserId { get; set; }
public DateTime CreateDate { get; set; }
public string ConfirmationToken { get; set; }
public bool IsConfirmed { get; set; }
public DateTime LastPasswordFailureDate { get; set; }
public int PasswordFailuresSinceLastSuccess { get; set; }
public string Password { get; set; }
public DateTime PasswordChangeDate { get; set; }
public string PasswordSalt { get; set; }
public string PasswordVerificationToken { get; set; }
public DateTime PasswordVerificationTokenExpirationDate { get; set; }
}
Step 4
• Add the Random Password Generation Function to the account controller
• This method when called will generate a random password for the user
private string GenerateRandomPassword(int length)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!#$?_-*&#+";
char[] chars = new char[length];
Random rd = new Random();
for (int i = 0; i < length; i++)
{
chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
}
return new string(chars);
}
Step 5
• Add the Send Email Function in account controller.
• This function will send first mail to user when user clicks on recover button on forgot password form. The first mail contains the reset password link. When user clicks on the link. User will be redirected to the reset password page. Again the new password will be mailed to the user.
• You need to put in your email address in place of XXXXX#gmail.com and write your password.
private void SendEMail(string emailid, string subject, string body)
{
System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.EnableSsl = true;
client.Host = "smtp.gmail.com";
client.Port = 587;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("xxxxx#gmail.com", "password");
client.UseDefaultCredentials = false;
client.Credentials = credentials;
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
msg.From = new MailAddress("xxxxx#gmail.com");
msg.To.Add(new MailAddress(emailid));
msg.Subject = subject;
msg.IsBodyHtml = true;
msg.Body = body;
client.Send(msg);
}

Remote ViewModel validation of nested objects not working

I have a class user which looks like this:
public class User
{
public int UserId { get; set; }
[Required(ErrorMessage = "A username is required.")]
[StringLength(20, ErrorMessage = "Your username must be 4-20 characters.", MinimumLength = 4)]
[RegularExpression("^[a-zA-Z0-9]*$", ErrorMessage = "Your username can only consist of letters and numbers.")]
[Remote("UsernameExists", "RemoteValidation", ErrorMessage = "Username is already taken")]
public string Username { get; set; }
[Required(ErrorMessage = "A password is required.")]
[MinLength(4, ErrorMessage = "Your password must have at least 4 letters.")]
public string Password { get; set; }
[Required(ErrorMessage = "An email address is required.")]
public string Email { get; set; }
}
For the Register functionality I have created a ViewModel that holds a User object and a string for the password confirmation:
public class RegistrationViewModel
{
public User User { get; set; }
[DisplayName("Password confirmation")]
[Required, Compare("User.Password", ErrorMessage = "The password do not match")]
public string PasswordConfirmation { get; set; }
}
The first problem I run into is that I can't seem to get the validation for Compare("User.Password") to work as it does not seem to find the property on the user. Is there any way to validate the PasswordConfirmation property against the User.Password property?
The second problem is the Remote validation of the Username field. I followed David Hayden's tutorial at http://davidhayden.com/blog/dave/archive/2011/01/04/ASPNETMVC3RemoteValidationTutorial.aspx but the parameter username in the UsernameExists method is always null. Am I missing something here?
Edit:
I'm sorry but I was actually not clear enough on the error I receive for the password comparison. It works fine when filling in the fields, if the passwords do not match I will receive an error. However, when submitting the form I get the following error in the validation summary: Could not find a property named UserToRegister.Password.
Edit 2:
I have figured out part of the problem thanks to Joe's post. The remote validator posts back URL/?UserToRegister.Username=temp which obviously does not match the username parameter of my controller action. In order to map my action parameter to UserToRegister.Username the following is required:
public ActionResult UsernameExists([Bind(Prefix = "UserToRegister.Username")]string username)
This now correctly passes the parameter to the method. However I still get the error when using the Compare attribute on the password field.
Thanks.
The issue with the validation of the PasswordConfigurmation property against the User.Password property is caused by a bug in in the 'jquery.validate.unobtrusive.js' file.
Originally, the jquery 'equalTo' function is:
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
setValidationValues(options, "equalTo", element);
});
You just need to modify this line:
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
to:
element = $(options.form).find(":input[name='" + fullOtherName + "']")[0];
Note the addition on the single quotes around the 'fullOtherName' selector. Once you've made this change, the client side validation works as expected.
For the remote validation part nothing jumps out at me. It might be helpful to open up firebug and see what the request that is being fired looks like. You should see something roughly like this if everything is properly wired up...
http://localhost:14547/[Controller]/[ActionName]?[ParamName]=[paramValue]
From the request you provided, you can either use a prefix like you ended up doing or you can make your action take a user named UserToRegister and then within the action access the UserName property. This is the recommended way of dealing with remote validation of objects and might be a little easier to think about than using a Bind attribute.
For the compare validation, it appears that on the client side validation is succeeding but on the server side validation fails because the validation context does not contain a property named User.Password, only a property named User.
Inheritance seems like a standard way of adding functionality in this case. How about having your RegistrationViewModel derive from the UserViewModel:
public class RegistrationViewModel : UserViewModel
{
[DisplayName("Password confirmation")]
[Required]
[Compare("Password", ErrorMessage = "The password do not match")]
public string PasswordConfirmation { get; set; }
}
and:
public ActionResult UsernameExists(string Username)
{
...
}

How to clear textboxes defined with MVC HTML helpers

I can't figure out how to do this very simple thing: My page contains a set of textboxes that a user can fill out to add an item to a list. Then the item shows up in a dropdown list.
At that point, I want the "add" textboxes to be cleared. This is the behavior expected by most users, I think. The item has been added; now the textboxes should be empty, ready for the next item to be entered.
However, I can't seem to clear them when I am using Html helpers, e.g., Html.Textbox(...). I like these controls because of the way they "remember" the input in case of input error. However, unlike webforms controls, you can't set them programmatically. They continue to retain the values until the user enters something else.
Is there any way around this behavior? I thought of clearing them in javascript, but I don't want to do that if there are any errors.
UPDATE some of the code;
One of my textboxes in the view:
<h6 style="margin-top: 0px">Add custom email template:</h6>
<div style="margin-top: 10px">
<div class="label">Name:</div>
<%= Html.TextBox("addName", "", new { #class="formtext", style="width: 400px" }) %>
<div class="alerttext"><%= Html.ValidationMessage("addName") %></div>
</div>
The class I am using for model binding:
public class ManageEmailTemplatesSubmittedData
{
[RegularExpression(RegExpressions.templateNameRestrict, ErrorMessage="Names should begin with a character and consist of only characters and numbers")]
public string addName { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string addDescription { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string addSubject { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string addTemplate { get; set; }
public string templates { get; set; }
[RegularExpression(RegExpressions.templateNameRestrict, ErrorMessage = "Names should begin with a character and consist of only characters and numbers")]
public string editName { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage="Invalid entry; please omit unusual characters")]
public string editDescription { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string editSubject { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string editTemplate { get; set; }
}
My action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CustomEmails(SubmitButtons buttons, ManageEmailTemplatesSubmittedData data)
{
bool saved = false;
string selectedTemplate = data.templates;
if (ModelState.IsValid)
{
ButtonStyles buttonStyles = ButtonStylesCreator.GetSelectListButtonStyles(rc.persistedData.loggedInUser.userType);
Notification notification = new Notification(rc);
if (buttons.addTemplate == buttonStyles.addEmailTemplateButtonValue)
{
// add an email template
notification.SaveCustomTemplate(data.addName, data.addName, data.addTemplate, data.addSubject, data.addDescription);
saved = true;
}
else if (buttons.saveTemplate == buttonStyles.saveTemplateValue)
{
// update an email template
notification.SaveCustomTemplate(data.templates, data.editName, data.editTemplate, data.editSubject, data.editDescription);
selectedTemplate = "";
saved = true;
}
}
ConfigureEmailsModelBuilder builder = new ConfigureEmailsModelBuilder(rc, rc.persistedData.loggedInUser.userID, selectedTemplate, true, saved);
return View(builder.Build());
}
ConfigureEmailsModelBuilder constructs the view model, which includes a SelectList that is the dropdown list of the items that have been added. (The view is strongly typed to the type generated by builder.Build).
The HTMLHelper's first look at the ModelState and ViewData to see if any values match their key and then finally use whatever value you provide them.
If you need to reset the textboxe's value you also need to clear the ModelState entry with the matching key. Another alternative is redirecting to the same page instead of simply rendering a view via javascript or with MVC.
This is working for me on an MVC3 site log on page.
ModelState.Clear();
model.UserName = string.Empty;
model.Password = string.Empty;
ModelState.AddModelError("", "The user name or password provided is incorrect.");
This will clear the login textboxes used for password and username, and keep any model errors.

Resources