The Complete Guide To Validation In ASP.NET MVC 3 - Part 1

The latest release of ASP.NET MVC (version 3) has a number of new validation features that significantly simplify both the validation code AND the html outputted to the client. This two-part article will attempt to cover all common validation scenarios and introduce all the new MVC3 validation features along the way. We will provide detailed explanations as well as full code examples that you can adapt for your own needs.

In part one of the article we will give an overview of validation in ASP.NET MVC 3. We will look at the built-in validators including the new CompareAttribute and RemoteAttribute and see what has changed from MVC 2, particularly on the client-side. In Part Two, we will write several custom validators that include both client and server-side validation. We will also look at an alternative to using data annotations - the IValidatableObject interface. So let's get started...

Setting up Visual Studio

We will be adding all code to the 'Internet Application' template that comes with ASP.NET MVC 3, so if you wish to follow along you, just open up Visual Studio, select new ASP.NET MVC 3 Web Application and pick the Internet Application template when prompted.

The Visual Studio 2010 New Project Dialog Figure 1: The Visual Studio 2010 New Project Dialog The ASP.NET MVC3 Internet Application Template Figure 2: The Visual Studio 2010 New ASP.NET MVC3 Internet Application Template If you look at solution explorer, you will find a skeleton application with two controllers and a single file in the Models folder (AccountModels.cs) containing all view models. Open up this file, expand the Models region and you will find three models for registration, logon and change password. All examples in this article will revolve around the registration process and thus use the RegisterModel class. The Internet Application Template Figure 3: Initial Solution Explorer for Internet Application Template

Inspecting the model

public class RegisterModel
{
  [Required]
  [Display(Name = "User name")]
  public string UserName { get; set; }

  [Required]
  [DataType(DataType.EmailAddress)]
  [Display(Name = "Email address")]
  public string Email { get; set; }

  [Required]
  [ValidatePasswordLength]
  [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 do not match.")]
  public string ConfirmPassword { get; set; }
}

If you take a look at this model, you will find four properties decorated with a number of attributes. If you have worked with ASP.NET MVC version 2, you will probably recognise many of these as System.ComponentModel.DataAnnotations attributes. Some of these are used to affect appearance such as [Display] and [DataType]. The remaining attributes are used for validation. In the RegisterModel, three distinct validation atributes are used: [Required], [Compare] and [ValidatePasswordLength]. Given that throughout this series, we are dealing with data annotations based validation that exclusively use .NET attributes, I will refer to validators and attributes synonymously. So for example, [Required], RequiredAttribute and the Required validator all refer to the same System.ComponentModel.DataAnnotations.RequiredAttribute class.

RequiredAttribute is not new, having been present in MVC 2, but is by far the most commonly used validator. As the name implies, any field with a Required validator needs to have a value if it is to pass validation. The required attribute does not have any configuration properties other than the three common error message ones that we will discuss later in this article.

CompareAttribute is a new, very useful validator that is not actually part of System.ComponentModel.DataAnnotations, but has been added to the System.Web.Mvc DLL by the team. Whilst not particularly well named (the only comparison it makes is to check for equality, so perhaps EqualTo would be more obvious), it is easy to see from the usage that this validator checks that the value of one property equals the value of another property. You can see from the code, that the attribute takes in a string property which is the name of the other property that you are comparing. The classic usage of this type of validator is what we are using it for here: password confirmation.

ValidatePasswordLengthAttribute is a custom validator that is defined within the Internet Application template. If you scroll to the bottom of the AccountModels.cs file, you will see the source code for this validator which is very useful to look at when you come to write your own custom validators. The validator subclasses ValidationAttribute and implements the new IClientValidatable interface that is used to output validation-specific markup to the rendered view. In Part Two of this article, we will discuss much of the structure of ValidatePasswordLengthAttribute and use this class as a base when we come to write several custom validators of our own.

The Controller and View

If these are your first steps with MVC 3, take a look at the AccountController and Register.cshtml View. In terms of validation, you can see that there are no significant changes to either file from MVC 2. This is good and what we would expect - validation logic like all business logic belongs in the model.

If you are particularly observant, you may have noticed a change to the javascript libraries that we are using in our view. We will discuss this below.

What has changed for the client?

Before we run the application for the first time, let's make a few changes:

public class RegisterModel
{
  [Required(ErrorMessage="You forgot to enter a username.")]
  [Display(Name = "User name")]
  public string UserName { get; set; }

  [Required(ErrorMessage="Email is required (we promise not to spam you!).")]
  [DataType(DataType.EmailAddress)]
  [Display(Name = "Email address")]
  public string Email { get; set; }

  [Required]
  [ValidatePasswordLength]
  [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 do not match.")]
  public string ConfirmPassword { get; set; }
}

Here, we have just changed the error messages for some of the [Required] validators. For an explanation of all the options for customising error messages, see below. All data annotations validators share three common properties related to the error message that is displayed on validation failure. You can use these properties in three different ways:

Do not specify any property.

[Required]

Leaving all three properties blank and the default error message built in to the validator will be used. As an example, for the RequiredAttribute on the UserName property, the default error message is The User name field is required. Note that it is displaying 'User name' rather than UserName because the validator uses the Name property of the DisplayAttribute if present. Set the ErrorMessage property

[Required(ErrorMessage="Email is required (we promise not to spam you)")]

If you do not need to support multiple languages, you can simply set your error message directly on the attribute and this will replace the default error message. You can also make the error message a format string. Depending on the validator, you can specify one or more placeholders that will be replaced with the name of the property (or the Name property of the DisplayAttribute if present). The definition displayed below would result in the message 'Email address is required (we promise not to spam you)' [Display(Name = "Email address")] [Required(ErrorMessage="{0} is required (we promise not to spam you)")] Set the ErrorMessageResourceName and ErrorMessageResourceType properties [Required(ErrorMessageResourceName="Login_Username_Required" ErrorMessageResourceType=typeof(ErrorMessages))] If you prefer to put your error messages in a resource file, you can instruct the validator to retrieve the error message from there using these properties. Again you can use format strings in your resource file in the same way that you do when you are setting the ErrorMessage. OK, now it is time to run the application and see what has changed on the client-side with MVC 3. Navigate to /Account/Register and try to submit the form with missing or invalid data. You may be surprised to find client-side (javascript) validation firing and using the error messages that you just modified in the model. The Initial Registration Form

Figure 4: The Initial Registration Form Client-side validation and the option to use unobtrusive javascript (see below) is controlled by two settings in the web.config. These will both be present in all new MVC 3 projects, but you will need to add them yourself if upgrading an MVC2 application. As an aside, I cannot say that I am a fan of using appSettings in this way. I don't know why the team didn't use a custom config section but I am sure there was probably a good reason for it.

<appSettings>
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

View the page source and you will see lots of attributes on each form control starting with data-. This is unobtrusive javascript in action. Instead of outputting inline javascript or a JSON blob as in previous releases, MVC3 by default uses this much cleaner syntax. These new attributes are a feature of HTML5, but are fully backward compatible with all modern browsers (including IE6). We will talk more about unobtrusive javascript later in the article.

<div class="editor-label">
  <label for="UserName">User name</label>
</div>
<div class="editor-field">
  <input data-val="true" data-val-required="You forgot to enter a username."
    id="UserName" name="UserName" type="text" value="" />
  <span class="field-validation-valid" data-valmsg-for="UserName"
    data-valmsg-replace="true"></span>
</div>

<div class="editor-label">
  <label for="Email">Email address</label>
</div>
<div class="editor-field">
  <input data-val="true"
    data-val-required="Email is required (we promise not to spam you!)."
    id="Email" name="Email" type="text" value="" />
  <span class="field-validation-valid" data-valmsg-for="Email"
    data-valmsg-replace="true"></span>
</div>


<div class="editor-label">
  <label for="Password">Password</label>
</div>
<div class="editor-field">
  <input data-val="true"
    data-val-length="&amp;#39;Password&amp;#39; must be at least 6 characters long."
    data-val-length-min="6" data-val-required="The Password field is required."
    id="Password" name="Password" type="password" />
  <span class="field-validation-valid" data-valmsg-for="Password"
    data-valmsg-replace="true"></span>
</div>

<div class="editor-label">
  <label for="ConfirmPassword">Confirm password</label>
</div>
<div class="editor-field">
  <input data-val="true"
    data-val-equalto="The password and confirmation do not match."
    data-val-equalto-other="*.Password" id="ConfirmPassword"
    name="ConfirmPassword" type="password" />
  <span class="field-validation-valid" data-valmsg-for="ConfirmPassword"
    data-valmsg-replace="true"></span>
</div>

You will also see that we are no longer required to reference MicrosoftAjax.js, MicrosoftMvc.js or MicrosoftMvcValidation.js. Instead, we are using jquery.validate.js and an adapter library built by the MVC team: jquery.validate.unobtrusive. Since the announcement back in 2008, Microsoft has commited to using jQuery as part of their official development platform. Now in version 3 of MVC, we can see the effects of this commitment. Instead of duplicating functionality between jQuery and Microsoft Ajax libraries, jQuery has become the primary client-side library. All custom Microsoft functionality is built on top of jQuery with the jquery.validate.unobtrusive containing validation adapter logic and jquery.unobtrusive.ajax containing the necessary javascript for ajax forms and links. Note that the older libraries are still present in the Scripts folder but there is absolutely no reason to use them for new projects. In order to created some separation between MVC and jQuery (validate), the MVC developers have decided to use HTML5 data-* attributes instead of jQuery validate's method of using css class names. Not only is this more semantically correct, but this approach also allows you to use completely different javascript libraries in the future without any change to the mvc framework itself. The downside is that this separation does necessitate the creation of another javascript file to bridge these differences. Microsoft's jquery.validate.unobtrusive contains all the adapters necessary to convert the HTML5 attributes that are outputted by the validators into jQuery.validate compatible syntax. When you come to write your own custom validation, you can make use of methods in this file to register you own adapters.

Exploring the other data annotations validation attributes

If you are already familiar with MVC 2, feel free to skip this section and move on to the next section where we talk about the Remote validator.

The Range and RegularExpression validators

So we can take a look at the other built-in validators, let's add a new Age property to our model.

[Required]
[Range(18, 65, ErrorMessage = "Sorry, you must be between 18 and 65 to register.")]
public int Age { get; set; }

We will also need to add an age field to the Register.cshtml view. Just copy the following somewhere between the fieldset tags.

@Html.LabelFor(m => m.Age)
@Html.TextBoxFor(m => m.Age) @Html.ValidationMessageFor(m => m.Age)
Note that we have added a **RequiredAttribute** and **RangeAttribute** to the age property. The Range validator does exactly what you would expect and in this case restricts the property to values between 18 and 65. If you re-run the code and enter an out of range age, you'll get error message we defined. Now try entering 'xyz'. You'll see a different error message 'The field Age must be a number.'. This is not the result of a _ValidationAttribute_. It is simply because we defined the age property as an integer and as such, we cannot assign a string to it. We have no control over this message, so if it is not to your liking, you will need to change your model slightly. To get over these model binding issues, many people advocate the use of strings for all view model properties. Model binding will always be successful in this way. Strictly speaking, it is possible to change the type conversion error message, but it is not straightforward to do so and involves overriding framework components. Changing the type to a string is far simpler and has the same effect. [Required] [Range(18, 65, ErrorMessage = "Sorry, you must be between 18 and 65 to register.")] [RegularExpression(@"\d{1,3}", ErrorMessage = "Please enter a valid age.")] public string Age { get; set; }

We have changed the age property to a string so model binding always suceeds. In addition, we have added a regular expression validator that checks that the string is a valid number. We are now able to specify any error message we want here. While we are here, lets also add a RegularExpressionAttribute to the Email property: [RegularExpression("", ErrorMessage = "Please enter a valid email address.")] public string Email { get; set; }

Please no comments about the efficacy of the email regular expression. Yes, there are better expressions that you can use. If you are interested, I would recommend looking here.

The StringLength validator

Finally, let's add a StringLengthAttribute to username: [StringLength(12, MinimumLength = 6, ErrorMessage = "Username must be between 6 and 12 characters.")] public string UserName { get; set; }

As you would expect, StringLength validates the number of characters that you can have in a string type property. You must specify a maximum number, but a minimum is optional. [StringLength(12, ErrorMessage = "Username must be a maximum of 12 characters.")] public string UserName { get; set; }

In a standard text input, you can limit the number of characters by using the maxlength attribute, so you might not see any point in specifying it on the model as well, but remember that maxlength is just client-side html and as such can be manipulated or ignored by anyone that chooses to do so. StringLength like all built-in data annotations validators enforces validation logic on both the client and server side.

Viewing the model changes on the UI

Below is the fully modified version of the RegisterModel public class RegisterModel { [Display(Name = "User name")] [Required(ErrorMessage = "You forgot to enter a username.")] [StringLength(12, MinimumLength = 6, ErrorMessage = "Username must be between 6 and 12 characters.")] public string UserName { get; set; }

  [Display(Name = "Email address")]
  [DataType(DataType.EmailAddress)]
  [Required(ErrorMessage = "Email is required (we promise not to spam you!).")]
  [RegularExpression("", ErrorMessage = "Please enter a valid email address.")]
  public string Email { get; set; }

  [Display(Name = "Password")]
  [DataType(DataType.Password)]
  [Required]
  [ValidatePasswordLength]
  public string Password { get; set; }

  [Required]
  [Range(18, 65, ErrorMessage = "Sorry, you must be between 18 and 65 to register.")]
  [RegularExpression(@"\d{1,3}", ErrorMessage = "Please enter a valid age.")]
  public string Age { get; set; }

  [Display(Name = "Confirm password")]
  [DataType(DataType.Password)]
  [Compare("Password",
    ErrorMessage = "The password and confirmation password do not match.")]
  public string ConfirmPassword { get; set; }
}

Re-run the application and confirm that your form has client-side validation for the new validators that you have applied. The Modified Registration Form Figure 5: The Modified Registration Form with an Age field

If you turn off JavaScript in your browser, you can test out the server side validation. You will find that the logic is exactly the same on client and server as you would expect. The server side validation will always fire ensuring that invalid data can never make it through to your business logic. For those users with JavaScript enabled, the client-side validation will provide immediate feedback resulting in a better experience for them and less load on the server for you.

<div class="editor-label">
  <label for="UserName">User name</label>
</div>
<div class="editor-field">
  <input data-val="true" data-val-length="Username must be between 6 and 12 characters."
	data-val-length-max="12" data-val-length-min="6"
	data-val-required="You forgot to enter a username." id="UserName"
	name="UserName" type="text" value="" />
  <span class="field-validation-valid" data-valmsg-for="UserName"
	data-valmsg-replace="true"></span>
</div>

<div class="editor-label">
  <label for="Email">Email address</label>
</div>
<div class="editor-field">
  <input data-val="true" data-val-regex="Please enter a valid email address."
	data-val-regex-pattern="\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b"
	data-val-required="Email is required (we promise not to spam you!)."
	id="Email" name="Email" type="text" value="" />
  <span class="field-validation-valid" data-valmsg-for="Email"
	data-valmsg-replace="true"></span>
</div>

<div class="editor-label">
  <label for="Age">Age</label>
</div>
<div class="editor-field">
  <input data-val="true"
	data-val-range="Sorry, you must be between 18 and 65 to register."
	data-val-range-max="65" data-val-range-min="18"
	data-val-regex="Please enter a valid age." data-val-regex-pattern="\d{1,3}"
	data-val-required="The Age field is required."
	id="Age" name="Age" type="text" value="" />
  <span class="field-validation-valid" data-valmsg-for="Age"
	data-valmsg-replace="true"></span>
</div>
<div class="editor-label">
  <label for="Password">Password</label>
</div>
<div class="editor-field">
  <input data-val="true"
	data-val-length="&amp;amp;#39;Password&amp;amp;#39; must be at least 6 characters long."
	data-val-length-min="6" data-val-required="The Password field is required."
	id="Password" name="Password" type="password" />
  <span class="field-validation-valid" data-valmsg-for="Password"
	data-valmsg-replace="true"></span>
</div>

<div class="editor-label">
  <label for="ConfirmPassword">Confirm password</label>
</div>
<div class="editor-field">
  <input data-val="true"
	data-val-equalto="The password and confirmation do not match."
	data-val-equalto-other="*.Password" id="ConfirmPassword"
	name="ConfirmPassword" type="password" />
  <span class="field-validation-valid"
	data-valmsg-for="ConfirmPassword" data-valmsg-replace="true"></span>
</div>

If you look at the html source, you can see all the HTML5 data attributes. It is interesting to look at the way these data attributes are constructed. Each form element that has validation has the following attributes:

data-val - indicates that the field contains validation data and should be processed by the unobtrusive adapters script.

data-val-{validator name} - contains the error message for the validator. e.g. data-val-length

data-val-{validator name}-{argument name} - zero or more arguments necessary for performing validation. e.g. data-val-length-min

The data- prefix is defined by the HTML5 standard. The specification states 'Custom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements'. In the past, people tended to use hacks such as embedding data in css classes to add such data, but thankfully this is no longer necessary.

The Remote validator

Let's take a look at a brand new MVC 3 validator - RemoteAttribute. The Remote validator is very simple to use and yet extremely powerful. Remote is for situations where it is impossible to duplicate server side validation logic on the client, often because the validation involves connecting to a database or calling a service. If all your other validation uses javascript and responds to the user's input immediately, then it is not a good user experience to require a post back to validate one particular field. This is where the remote validator fits in.

In this example, we are going to add remote validation to the username field to check that it is unique.

[Remote("ValidateUserName", "Account", ErrorMessage = "Username is not available.")]
public string UserName { get; set; }

Remote has three constructors allowing you to specify either a routeName, a controller and action or a controller, action and area. Here we are passing controller and action and additionally overriding the error message.

Because the remote validator can be used to validate any field in any manner, the default error message is understandably vague. In this case, the error message would be 'UserName is invalid' which is not particularly useful to your end users, so always remember to override the default error message when using the RemoteAttribute.

The remote validator works by making an AJAX call from the client to a controller action with the value of the field being validated and optionally, the value of other fields. The controller action then returns a Json response indicating validation success or failure. Returning true from your action indicates that validation passed. Any other value indicates failure. If you return false, the error message specified in the attribute is used. If you return anything else such as a string or even an integer, it will be displayed as the error message. Unless you need your error message to be dynamic, it makes sense to return true or false and let the validator use the error message specified on the attribute. This is what we are doing here.

Our controller action is displayed below. To keep the example simple, we are just checking if the username is equal to 'duplicate' but in a real scenario, you would do your actual validation here making use of whatever database or other resources that you may require.

public ActionResult ValidateUserName(string username)
{
  return Json(!username.Equals("duplicate"), JsonRequestBehavior.AllowGet);
}

There are a few different arguments that can be passed to RemoteAttribute. Let's look at an alternative definition:

[Remote("ValidateUserNameRoute", HttpMethod="Post",
  AdditionalFields="Email", ErrorMessage = "Username is not available.")]
public string UserName { get; set; }

This time, we are passing a named route instead of controller and action. We have also changed the http method from the default (GET) to POST. Most interestingly, we are specifying that we need an additional field in order to perform validation. Just by specifying the AdditionalFields property on our model, the remote validator will automatically pass the values of these fields back to our controller action, with no further coding required in JavaScript or in .NET.

In our example, having email in addition to username is obviously of no use but you can imagine complex validation where multiple fields are required to validate successfully. When we include the AdditionalFields property in our validator declaration, we need to change our controller action to take in the additional field as arguments, so our controller action would become:

[HttpPost]
public ActionResult ValidateUserName(string username, string email)
{
  // put some validation involving username and email here
  return Json(true);
}

Run the application and try completing the completed form with valid and invalid usernames. As with all the built-in validators, client-side validation is enabled by default so as soon as you change the username and tab out of the field, an ajax request will be made to the controller action you specified in your remote validator declaration. This level of immediate feedback provides a great user experience and given the trivial amount of code required, I can see this validator being very popular.

The Remote validator

Figure 6: The RemoteAttribute validator in action

It is also important to note that you must ensure that the result of the controller action used by the remote validator is not be cached by the browser. How do we do this? Simply by decorating our controller action with the OutputCache attributes and explicitly setting it not to cache. Thanks to Ryan for this important step. You can read more about the remote validator on MSDN.

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]

Conclusion

We have examined the use of validators in the Internet Application template of ASP.NET MVC 3. We have reviewed the usage of many of the in-built validators including the new RemoteAttribute and CompareAttribute. We have also looked at the significant changes to client-side validation including HTML5 data-* attributes and the move from MicrosoftAjax to jQuery and jQuery Validate.

In the Second Part of this article we will create several custom validators from scratch that implement validation logic on both the client and back-end. We will also investigate an alternative to data annotations, the IValidatableObject interface.

Comments

Avatar for Ryan Ryan wrote on 14 Mar 2011

Hey,

This is a really good article. I will be checking out the remote validator soon.

There is one piece of information that people might want to know about though for the remote validator

According to msdn http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx

"The OutputCacheAttribute attribute is required in order to prevent ASP.NET MVC from caching the results of the validation methods."

Cheers

Avatar for Paul Hiles Paul Hiles wrote on 17 Mar 2011

Thanks Ryan, I did not know that. I have updated the article.

Avatar for Theja Theja wrote on 10 May 2011

How can I achieve group validation in mvc3

Avatar for Paul Hiles Paul Hiles wrote on 11 May 2011

@Theja - Well, you can write custom data annotations or use IValidatableObject to do group validation at the server side but I am guessing that you are taking about client-side integration and in particular, integration with jquery.validate's validation groups functionality. If this is the case then unfortunately, out of the box, this is not possible.

Having said that, a UX colleague of mine is in the process of hacking together some support, but it involves hundreds of lines of javascript, replacing a good deal of Microsoft's library. It is not pretty and it will be a while before I would even consider using it for a client project.

Avatar for Henk Jan Henk Jan wrote on 11 Aug 2011

I discovered an error in the validation client handling. When using a viewmodel that contains an entity the compare validation always returns the validation message.

Avatar for Michael Michael wrote on 12 Aug 2011

Great article! Things can get a bit overwhelming sometimes with MS releasing new versions and ways of doing things quite often, so it's nice when someone clears things up.

Avatar for snp snp wrote on 26 Sep 2011

Hi, I really liked this post.
This is very informative & well explained.
I tried to use 'NotEqualTo' attribute in default sample MVC project in VS 2010.
I added this attribute to Password property in RegisterModel as per this post part # 2. Also added customValidation.js with the closure script as told in post # 2 & included this script file in Register.cshtml.
But when i ran the app, only server side validation is happening, no client side validation.???
I am not able to find what is wrong i did.
Your help will be helpful.

Avatar for Paul Hiles Paul Hiles wrote on 02 Oct 2011

@snp - I have just created a new mvc3 application and got it working ok, so not sure what is wrong at your end. Here are the steps I took. Hopefully, this will help:

(1) New MVC3 application - Internet Aplication template.
(2) Downloaded the zip file from http://www.devtrends.co.uk/downloads/devtrends.validation.zip
(3) Extracted the c# project and added it to the solution, adding a reference to the project from the internet appliction MVC project.
(4) Added the devtrends.validation.js to the scripts folder.
(5) Referenced the script from Register.cshtml using:

<script src="@Url.Content("~/Scripts/devtrends.validation.js")" type="text/javascript"></script>

(6) Added the NotEqualTo attribute to the password property of the RegisterModel in AccountModels.cs:

[Required]
[NotEqualTo("Email,UserName")]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }

I can bundle this up in a NuGet package if people want me to. That way, you can just install the package and go. Let me know.

Avatar for Rana Rana wrote on 17 Oct 2011

Thank you very much for this tutorial, it really helped me make since of validation options.

One question on remote validation: ive implemented same concept as your "ValidateUserName", its working as expected but how can exclude it for editing?
when I edit a record I would get the error that this username is already there?

Thanks again :)

Avatar for Paul Hiles Paul Hiles wrote on 27 Oct 2011

@Rana - if you are editing then you will have some form of key stored either in the URL or as a hidden field so you can update the existing record. You can check for this key to determine whether you are adding or editing a record and change your logic accordingly. You will not want to skip the username check completely for an edit though. Instead, you want to check if the username has changed and if not, skip the check.

If the key is a hidden field, you can use the AdditionalFields property of the RemoteAttribute and then just add an extra parameter to your remote validation method. Just change the example above where we pass the additional email field and use your id/key instead. If you are using the URL, you can just access this directly from your validation method.

Avatar for Steve Steve wrote on 05 Nov 2011

If all tutes were this polished the internets would suck much less. Highly appreciated and looking for a way to tip you ;)

Avatar for Sen K. Mathew Sen K. Mathew wrote on 14 Nov 2011

Hi
I wan to check the username while i am editing. so I passed username and userid as AdditionalFields.
But the mvc3 not allowing to edit the field after it displayes the first error message. It gets stuck.

Avatar for Paul Hiles Paul Hiles wrote on 15 Nov 2011

@Sen K Mathew - I have not experienced this issue with the Remote validator, so without code, it is very difficult to determine the cause. I would suggest you put a cut down example on stackoverflow.

Avatar for Sen K. Mathew Sen K. Mathew wrote on 22 Nov 2011

Hi sir
I Added a comment on November 14, 2011 at 08:14.
I am repeating the same once agin for your easy reference.

I wan to check the username while i am editing. so I passed username and userid as AdditionalFields.
But the mvc3 not allowing to edit the field after it displayes the first error message. It gets stuck.

the problem was with IE8. Remote or all validator will get stuck if you use
IE 8. You need to convert the browser to compatiability mode.
This issue is related to IE 8 bug.
Thanks a lot.
Sen K. Mathew

Avatar for Paul Hiles Paul Hiles wrote on 22 Nov 2011

@Sen K Mathew - I did some research and it turns out that there are some compatibility problems with IE when using certain versions of jQuery and jQuery.validate. Updating to jQuery 1.6.1 and jQuery.validate 1.8.1 should fix the problem.

More information can be found in this bug report:

https://github.com/jzaefferer/jquery-validation/issues/105

Avatar for Dpak Dpak wrote on 23 Nov 2011

Hi,

Q1) Can you have more than 1 RemoteAttribute specified for a field?
Q2) Has anyone tried extending the "RemoteAttribute" and creating custom "RemoteAttributes" ?

Avatar for Manu Manu wrote on 28 Nov 2011

I try to implement a "Forgot password" mechanism and I thought it would be better to check the user name and the e-mail address before resetting the password and sending the email. I did this:
-- model:
public class ForgotPasswordModel
{
[Required(ErrorMessageResourceType = typeof(AccountResources), ErrorMessageResourceName = "RequiredUserNameMessage")]
[Display(ResourceType = typeof(AccountResources), Name = "UserNameDisplay")]
[Remote("ValidateUser", "Account", ErrorMessage = "Unknown user")]
public string UserName { get; set; }

[Required(ErrorMessageResourceType = typeof(AccountResources), ErrorMessageResourceName = "RequiredEmailMessage")]
[DataType(DataType.EmailAddress)]
[Remote("ValidateEmailAddress", "Account", AdditionalFields = "UserName", ErrorMessage = "Wrong password"]
[Display(ResourceType = typeof(AccountResources), Name = "EmailDisplay")]
public string Email { get; set; }
}

-- validation controller ("Account"):
public ActionResult ValidateUser(string username)
{
bool result=false;
MembershipUser currentUser = Membership.GetUser(username);

result = (currentUser != null) && (currentUser.UserName.Equals(username));
return Json(result, JsonRequestBehavior.AllowGet);
}

public ActionResult ValidateEmailAddress(string username, string email)
{
bool result = false;
MembershipUser currentUser = Membership.GetUser(username);

result = (currentUser != null) && (currentUser.Email.Equals(email));
return Json(result, JsonRequestBehavior.AllowGet);
}

-- in the _Layout.cshtml view I included
<script src="@Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js files")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.2.min.js"; type="text/javascript"></script>
<script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"; type="text/javascript"></script>

-- in the Web.config file I have:
<appSettings>
<add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

I can't get the remote validation to fire, neither client-side, nor on submit. The "Required" validation is performed, though.

I'm stuck, please suggest a solution, thank you in advance.

Avatar for Manu Manu wrote on 28 Nov 2011

Hello again, I just solved the remote validation problem: it was because of the jquery includes in the _Layout.cshtml view, so you may discard my previous post.
Thank you.

Avatar for Dharmesh Dharmesh wrote on 04 Jan 2012

I want to pass some extra information which is not part of model where i am applying remote attribute.

Is it possible?

I have one viewmodel which contain list of x model which is bound to telerik grid. now when user enter same name again i want to give error message that name already exist.

Avatar for ARUN RANA ARUN RANA wrote on 09 Jan 2012

How can i put updaterprogress image beside username when post request is being executed , in case of remote validation ?

Avatar for David David wrote on 14 Feb 2012

Is it possible to use a checkbox as AdditionalFields in the Remote attribute? I tried that, but it always posts 'true'to the server for the field value. Doesn't matter if it's checked or not.

Avatar for Georgios Georgios wrote on 07 Mar 2012

Awesome guide, thanks for posting it.

Avatar for Daniel Daniel wrote on 19 Apr 2012

Thank you so much for this article. I did learn a lot more from it about validation than from MVC books I have.

Avatar for Rocky royalson Rocky royalson wrote on 03 Aug 2012

Hi Paul,

How to validate multiple email addresses entered in the To/CC fields,

Using MVC3 I want to implement this client requirement.

Multiple email address should be comma separated, and
rocky.royalson@abc.com, abc@gmail.com => this is right

rocky,royalson@abc.com => this is wrong bcoz after rocky there is comma which should not be allow in the email id.

Please help me to achieve this i have written some regular expression as follows, please correct me to implement this :-

[RegularExpression((@"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6},?$"), ErrorMessage = "Please enter a valid Email Address.")]

Avatar for sharmila sharmila wrote on 16 Aug 2012

It doesnt seem to work in IE7. but works in chrome and firefox

Avatar for Zeeshan Umar Zeeshan Umar wrote on 14 Sep 2012

This is really a comprehensive tutorial, I was really looking for quite some time something like it. You did an excellent job.

Avatar for Stephen Stephen wrote on 22 Mar 2013

In 'The Range and RegularExpression Validators' section you note 'we have no control over the message' (for typeof int)

An alternative is to modify the message in the unobtrusive adaptors

e.g. for a data property with the [DataType(DataType.Date)] attribute

$.validator.unobtrusive.adapters.add('date', function (options) {
if (options.message) {
options.messages['date'] = 'The date must be in the format dd/mm/yyyy';
}
});

Avatar for Deepanshu Deepanshu wrote on 13 May 2013

Great Article... very Helpful Thanks a lot.
But i am looking where the text field support multiple language. I mean user should be able to enter multiple language.
What regularexpresssions should be used in that case directly in the model.?
I read something over unicode and used p{L}, something like this, but din't worked.
Can some one please help me out.

Avatar for Jason Presley Jason Presley wrote on 10 Jul 2013

Does the Remote validator work in MVC 4? I have seen this described in several blog posts but I'm trying it and I get nothing. Either I'm missing something that all of the posts are assuming or there is something broken in MVC 4. Any help of suggestions would be appreciated. Thanks!