I am referring this article:
http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx
which shows how to create custom annotation in Asp.Net MVC 2
That article is specific to MVC 2 which used MicrosoftAjax. MVC 4 no longer includes the MS Ajax files as they have been deprecated and the preferred method is to use jquery.
To verify your settings, make sure these scripts are in your layout
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
And these two settings are present in the appSettings section in your web.config file
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
So when you add data annotations to your ViewModels you get client side and server side validation both
public class MyModel
{
[Required]
[StringLength(30)]
public string FirstName { get; set; }
[Required]
[StringLength(30)]
public string LastName { get; set; }
}
In your view just make sure you have code like this
<div>
@Html.LabelFor(model => model.FirstName)
</div>
<div>
@Html.TextBoxFor(model => model.FirstName) <br/>
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div>
@Html.LabelFor(model => model.LastName)
</div>
<div>
@Html.TextBoxFor(model => model.LastName) <br/>
@Html.ValidationMessageFor(model => model.LastName)
</div>
Update
Here's an example of a custom validator that I have called RateRequiredIfCustomIndexRate This is the javascript side of it so that it gets added to jquery validation
$("document").ready(function () {
var isCustomRateRequired = document.getElementById("IsCustomRateRequired");
isCustomRateRequired.onchange = function () {
if (this.checked) {
$('#Rate').attr('disabled', 'disabled');
$('#Rate').val('');
}
else {
$('#Rate').removeAttr('disabled');
}
};
});
jQuery.validator.addMethod("raterequiredifcustomindexrate", function (value, element, param) {
var rateRequired = $("#CustomRateRequired").val();
if (rateRequired && value == "") {
return false;
}
return true;
});
jQuery.validator.unobtrusive.adapters.addBool("raterequiredifcustomindexrate");
The key thing missing here is that the server-side validator must implement the IClientValidatable interface:
public class RateRequiredIfCustomIndexRateAttribute : ValidationAttribute, IClientValidatable
{
public override bool IsValid(object value)
{
return false;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "raterequiredifcustomindexrate"
};
}
}
Once you do that, the client-side validation should be hooked up properly. You can verify this by making sure that your input field has an attribute "data-val-raterequiredifcustomindexrate" attribute.