Data annotations, unobtrusive validation. Min age, max age - asp.net-mvc-3

What do I want to achieve:
To show a seperate validation message for failing minimum age check and one for maximum age check
To store the minimum and maximum age in one area as integers. Not in js/ validator... only in the model. which I hope to change to look at a config file.
For the validation to work with jquery unobtrusive and server side, and to be in one place against the model (and obv some jquery)
To be enabled using data annotations
I wanted to check against DOB as a datetime, not have the user put in there age as an int. If i did I could have used [Min] notation and [Max] notation for age. It wasn't good enough.
Why didn't I use a range notation. I wanted to fire a different validation message for each min fail and max fail. I looked into this and had no look. I'd also have to pass in the range as a datetime and its static or something so I couldn't have done DateTime.Now.AddYears(-90) for instance.
My problems
I'm a noob at MVC, JQuery validation and the whole MVC architecture!
What I've come up with works. However, as you can see there is alot repeated code, I'd like to conform to DRY.
My first hack was to pass in the value that i'm checking against into the validation message. I got around this by doing...
[MaximumAgeCheck(90,"You have to be at most {0} to apply")]
and inside the validation attribute
private readonly int _min;
private readonly string _defaultErrorMessage = "";
public MinimumAgeCheck(int min, string defaultErrorMessage)
: base(defaultErrorMessage)
{
_min = min;
_defaultErrorMessage = defaultErrorMessage.Replace("{0}", _min.ToString());
}
and I used it for instance like so..
return new ValidationResult(_defaultErrorMessage);
I know this isn't the right way to do it, and wondered what is the best way to do this?
Second hack!
I'm passing in two validation parameters which I want to be able to access in the jQuery.validator.addMethod... method.
I tried to access these parameters by doing the following... params.[thevalueiadded], params[0]... etc, I even logged out params into console.log but it never showed me all the params, only the first value as a string!
My work around was to store the javascript variables at the top and load them from the adapters.add.
I'm probabily making little sense so here is the code, that works...I warn you, it is messy!
Model property and data annotation
[Required(ErrorMessage = "Date of birth required")]
[Display(Name = "Date of Birth")]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
[DataType(DataType.DateTime, ErrorMessage = "Date of birth should be in dd/mm/yyyy format")]
[MinimumAgeCheck(18,"You have to be at least {0} to apply")]
[MaximumAgeCheck(90,"You have to be at most {0} to apply")]
public DateTime? DateOfBirth { get; set; }
Minimum Age Check and Maximum age check
validation attributes
public class MinimumAgeCheck : ValidationAttribute, IClientValidatable
{
private readonly int _min;
private readonly string _defaultErrorMessage = "";
public MinimumAgeCheck(int min, string defaultErrorMessage)
: base(defaultErrorMessage)
{
_min = min;
_defaultErrorMessage = defaultErrorMessage.Replace("{0}", _min.ToString());
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
DateTime dtV = (DateTime)value;
long lTicks = DateTime.Now.Ticks - dtV.Ticks;
DateTime dtAge = new DateTime(lTicks);
if (!(dtAge.Year >= _min && dtAge.Year <= 30))
{
return new ValidationResult(_defaultErrorMessage);
}
return ValidationResult.Success;
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, _min);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule mcvrTwo = new ModelClientValidationRule();
mcvrTwo.ValidationType = "checkminimumage";
mcvrTwo.ErrorMessage = _defaultErrorMessage;
mcvrTwo.ValidationParameters.Add("todaysdate", DateTime.Now.ToString("dd/MM/yyyy"));
mcvrTwo.ValidationParameters.Add("lowerage", _min.ToString());
return new List<ModelClientValidationRule> { mcvrTwo };
}
}
public class MaximumAgeCheck : ValidationAttribute, IClientValidatable
{
private readonly int Max;
private readonly string _defaultErrorMessage = "";
public MaximumAgeCheck(int max, string defaultErrorMessage)
: base(defaultErrorMessage)
{
Max = max;
_defaultErrorMessage = defaultErrorMessage.Replace("{0}", Max.ToString());
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
DateTime dtV = (DateTime)value;
long lTicks = DateTime.Now.Ticks - dtV.Ticks;
DateTime dtAge = new DateTime(lTicks);
if (!(dtAge.Year >= Max && dtAge.Year <= 30))
{
return new ValidationResult(_defaultErrorMessage);
}
return ValidationResult.Success;
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,Max);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule mcvrTwo = new ModelClientValidationRule();
mcvrTwo.ValidationType = "checkmaximumage";
mcvrTwo.ErrorMessage = _defaultErrorMessage;
mcvrTwo.ValidationParameters.Add("todaysdate", DateTime.Now.ToString("dd/MM/yyyy"));
mcvrTwo.ValidationParameters.Add("upperage", Max.ToString());
return new List<ModelClientValidationRule> { mcvrTwo };
}
}
The Jquery
(function ($) {
var mintodaysDateVal;
var maxtodaysDateVal;
var lowerageVal;
var upperageVal;
jQuery.validator.unobtrusive.adapters.add("checkminimumage", ['lowerage', 'todaysdate', 'upperage'], function (options) {
options.rules["checkminimumage"] = options.params;
mintodaysDateVal = options.params.todaysdate;
lowerageVal = options.params.lowerage;
options.messages["checkminimumage"] = options.message;
});
jQuery.validator.addMethod("checkminimumage", function (value, element, params) {
var currDate = mintodaysDateVal;
var sdoc = currDate.split('/');
var dobDate = value;
var sdob = dobDate.split('/');
//pass year,month,date in new Date object.
var vDOB = new Date(sdob[2], sdob[1] - 1, sdob[0]);
var vDOC = new Date(sdoc[2], sdoc[1] - 1, sdoc[0]);
//getAge user define function to calculate age.
var vYrs = getAge(vDOB, vDOC);
var result = false;
if (vYrs >= lowerageVal) { result = true; }
return result;
});
jQuery.validator.unobtrusive.adapters.add("checkmaximumage", ['lowerage', 'todaysdate', 'upperage'], function (options) {
options.rules["checkmaximumage"] = options.params;
maxtodaysDateVal = options.params.todaysdate;
upperageVal = options.params.upperage;
options.messages["checkmaximumage"] = options.message;
});
jQuery.validator.addMethod("checkmaximumage", function (value, element, params) {
var currDate = maxtodaysDateVal;
var sdoc = currDate.split('/');
var dobDate = value;
var sdob = dobDate.split('/');
var vDOB = new Date(sdob[2], sdob[1] - 1, sdob[0]);
var vDOC = new Date(sdoc[2], sdoc[1] - 1, sdoc[0]);
var vYrs = getAge(vDOB, vDOC);
var result = false;
if (vYrs <= upperageVal) { result = true; }
return result;
});
function getAge(oldDate, currDate) {
return currDate.getFullYear() - oldDate.getFullYear();
}
} (jQuery));
I hope this makes sense, I've read it over and its quite garbled... so i'll be happy to answer any comments.

Really useful code, but the ValidationResult IsValid method has some bugs. It doesn't handle future dates or blank dates. Plus it seems to have a hard coded limit to age 30 in - looks to be debug code? Anyway, I addressed those issues for my code and came up with the below:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
{
return new ValidationResult(_defaultErrorMessage);
}
DateTime dtV = (DateTime)value;
long lTicks = DateTime.Now.Ticks - dtV.Ticks;
if (lTicks < 0)
{
return new ValidationResult(_defaultErrorMessage);
}
DateTime dtAge = new DateTime(lTicks);
if (!(dtAge.Year >= _min ))
{
return new ValidationResult(_defaultErrorMessage);
}
return ValidationResult.Success;
}

Take a look at the MVC Foolproof Validation library. You can find it in NuGet.
It has pretty much all the validation you need and is added via data annotations. It will intergrate nicely into the unobtrusive client side validation.

Related

Does the IClientValidator support input file?

Edit
I found that the problem is that View Components are unable to have an #section (see ViewComponent and #Section #2910 ) so adding custom client-side validation using the unobtrusive library seems imposible (or very complex). Moreover, the inability of including the required javascript into a View Component makes me regret of following this approach to modularize my app in the first place...
I am learning to make custom validation attributes with client-side support. I was able to implement a custom validator for a string property and it works pretty well, but when I tried to make one for input file it doesn't work (i.e. when I select a file in my computer, the application doesn't display the validation messages. The server-side validation works. Here is some code that shows my implementation.
The class of the model
public class UploadPanelModel
{
public int? ID { get; set; }
public string Title { get; set; }
public string Description { get; set; } //Raw HTML with the panel description
[FileType(type: "application/pdf")]
[FileSize(maxSize: 5000000)]
public IFormFile File { get; set; }
public byte[] FileBytes { get; set; }
public ModalModel Modal { get; set; } //Only used if the Upload panel uses a modal.
The validator
public class FileSizeAttribute : ValidationAttribute, IClientModelValidator
{
private long _MaxSize { get; set; }
public FileSizeAttribute (long maxSize)
{
_MaxSize = maxSize;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
UploadPanelModel panel = (UploadPanelModel)validationContext.ObjectInstance;
return (panel.File==null || panel.File.Length <= _MaxSize) ? ValidationResult.Success : new ValidationResult(GetFileSizeErrorMessage(_MaxSize));
}
private string GetFileSizeErrorMessage(long maxSize)
{
double megabytes = maxSize / 1000000.0;
return $"El archivo debe pesar menos de {megabytes}MB";
}
public void AddValidation(ClientModelValidationContext context)
{
if(context == null)
{
throw new ArgumentNullException(nameof(context));
}
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-filesize", GetFileSizeErrorMessage(_MaxSize));
var maxSize = _MaxSize.ToString();
MergeAttribute(context.Attributes, "data-val-filesize-maxsize", maxSize);
}
private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
The javascript in the Razor View
#section Scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script type="text/javascript">
$.validator.addMethod('filesize',
function (value, element, params) {
var size = $((params[0]).val()).size(),
maxSize = params[1];
if (size < maxSize) {
return false;
}
else {
return false;
}
}
);
$.validator.unobtrusive.adapters.add('filesize',
['maxSize'],
function (options) {
var element = $(options.form).find('input#File')[0];
options.rules['filesize'] = [element, options.params['maxSize']];
options.messages['filesize'] = options.message;
}
);
</script>
I always return false in the javascript method to force the application to show the validation error regardless the chosen file, but it still doesn't work.
Your addMethod() function will be throwing an error because params[0] is not a jQuery object and has no .val() (you also have the $ in the wrong place). You would need to use
var size = params[0].files[0].size;
However I suggest you write you scripts as
$.validator.unobtrusive.adapters.add('filesize', ['maxsize'], function (options) {
options.rules['filesize'] = { maxsize: options.params.maxsize };
if (options.message) {
options.messages['filesize'] = options.message;
}
});
$.validator.addMethod("filesize", function (value, element, param) {
if (value === "") {
return true;
}
var maxsize = parseInt(param.maxsize);
if (element.files != undefined && element.files[0] != undefined && element.files[0].size != undefined) {
var filesize = parseInt(element.files[0].size);
return filesize <= maxsize ;
}
return true; // in case browser does not support HTML5 file API
});

Validation attributed is cached

I have following code in custom validation attribute called DateRange:
private DateTime _minDate = DateTime.Today.AddYears(-100);
private DateTime _maxDate = DateTime.MaxValue;
// String representation of the Min Date (yyyy/MM/dd)
public string Min
{
get { return FormatDate(_minDate, DateTime.Today.AddYears(-100)); }
set { _minDate = value == "Today" ? DateTime.Today : ParseDate(value, DateTime.Today.AddYears(-100)); }
}
// String representation of the Max Date (yyyy/MM/dd)
public string Max
{
get { return FormatDate(_maxDate, DateTime.MaxValue); }
set { _maxDate = value == "Today" ? DateTime.Today : ParseDate(value, DateTime.MaxValue); }
}
Then I write this attribute in metadata on some property of entity model like this:
[DateRange(Max = "Today")]
public string SomeDateProperty { get; set; };
I set breakpoint on Max property's getter. First time I open view, breakpoint is activated and DateTime.Today is got. Consequent refresh of the view does not activate breakpoint and old value is got. I think it's caching validation attribute. My question is: Is this because of caching? If it is, then how to disable it? Thanks in advance
The constructor for the custom attributes only get hit once, no idea how to turn off any sort of caching. The way I got round this for my scenario, was to only deal with the date calculation in the "IsValid" Method.
I created a date in the past attribute, that needed the date to be in the past, but you could set how long in the past was valid.
public class DateInPastAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "'{0}' must be in the past.";
public int DaysInPastAllowed { get; set; }
public DateInPastAttribute(int daysInPastAllowed)
: base(DefaultErrorMessage)
{
this.DaysInPastAllowed = daysInPastAllowed;
}
public override bool IsValid(object value)
{
if (!(value is DateTime))
{
return true;
}
DateTime maxDate = DateTime.Now;
DateTime minDate = maxDate.AddDays(this.DaysInPastAllowed * -1);
DateTime dateValue = (DateTime)value;
return
minDate <= dateValue &&
dateValue <= maxDate;
}
public override string FormatErrorMessage(string name)
{
return string.Format(CultureInfo.CurrentCulture, this.ErrorMessageString, name);
}
}
You can then use it in your view model like this:
[DateInPast(365)]
public DateTime DateReceived { get; set; }
Which would allow a date to be entered within the last year. You could amend this for the scenario that you require.

Greater Than or Equal To Today Date validation annotation in MVC3

Has anyone seen an MVC3 data annotation for Date validation that requires a single selected date to be equal to or greater than current date?
If there's already a third party add on that's cool too. I'm already using the DataAnnotationsExtensions but it doesn't offer what I'm looking for.
There doesn't seem to be any reference of this on. So, hoping someone has already solved this before I try to reinvent the wheel and write my own custom validator.
I've tried Range but that requires 2 dates and both have to be constants in string format such as [Range(typeof(DateTime), "1/1/2011", "1/1/2016")] but that doesn't help. And the DataAnnotationsExtensions Min validator only accepts int and double
Update Solved
Thanks to #BuildStarted this is what I ended up with and it works great server-side and now client side with my script
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Web.Models.Validation {
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class DateMustBeEqualOrGreaterThanCurrentDateValidation : ValidationAttribute, IClientValidatable {
private const string DefaultErrorMessage = "Date selected {0} must be on or after today";
public DateMustBeEqualOrGreaterThanCurrentDateValidation()
: base(DefaultErrorMessage) {
}
public override string FormatErrorMessage(string name) {
return string.Format(DefaultErrorMessage, name);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
var dateEntered = (DateTime)value;
if (dateEntered < DateTime.Today) {
var message = FormatErrorMessage(dateEntered.ToShortDateString());
return new ValidationResult(message);
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
var rule = new ModelClientCustomDateValidationRule(FormatErrorMessage(metadata.DisplayName));
yield return rule;
}
}
public sealed class ModelClientCustomDateValidationRule : ModelClientValidationRule {
public ModelClientCustomDateValidationRule(string errorMessage) {
ErrorMessage = errorMessage;
ValidationType = "datemustbeequalorgreaterthancurrentdate";
}
}
}
And in my model
[Required]
[DateMustBeEqualOrGreaterThanCurrentDate]
public DateTime SomeDate { get; set; }
The client side script
/// <reference path="jquery-1.7.2.js" />
jQuery.validator.addMethod("datemustbeequalorgreaterthancurrentdate", function (value, element, param) {
var someDate = $("#SomeDate").val();
var today;
var currentDate = new Date();
var year = currentDate.getYear();
var month = currentDate.getMonth() + 1; // added +1 because javascript counts month from 0
var day = currentDate.getDate();
var hours = currentDate.getHours();
var minutes = currentDate.getMinutes();
var seconds = currentDate.getSeconds();
today = month + '/' + day + '/' + year + ' ' + hours + '.' + minutes + '.' + seconds;
if (someDate < today) {
return false;
}
return true;
});
jQuery.validator.unobtrusive.adapters.addBool("datemustbeequalorgreaterthancurrentdate");
Create a custom attribute.
public class CheckDateRangeAttribute: ValidationAttribute {
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
DateTime dt = (DateTime)value;
if (dt >= DateTime.UtcNow) {
return ValidationResult.Success;
}
return new ValidationResult(ErrorMessage ?? "Make sure your date is >= than today");
}
}
code was written off the cuff so fix any errors :)
Use [Remote] for special validations, simple and easy:
Your model:
[Remote("ValidateDateEqualOrGreater", HttpMethod="Post",
ErrorMessage = "Date isn't equal or greater than current date.")]
public DateTime Date { get; set; }
//other properties
Your action:
[HttpPost]
public ActionResult ValidateDateEqualOrGreater(DateTime Date)
{
// validate your date here and return True if validated
if(Date >= DateTime.Now)
{
return Json(true);
}
return Json(false);
}
Simple way to accomplish this task is using CompareValidator.
The code below uses AjaxControlToolKit's CalendarExtender.
Copy the below code to your HTML directive
<asp:TextBox ID="txtCompletionDate" runat="server" CssClass="txtNormal"></asp:TextBox>
<cc1:CalendarExtender ID="CalendarExtender1" TargetControlID="txtCompletionDate"
Format="dd/MM/yyyy" runat="server">
</cc1:CalendarExtender>
<asp:RequiredFieldValidator ID="rfvCompletionDate" runat="server" ControlToValidate="txtCompletionDate"
CssClass="labelError" ErrorMessage="*"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="cvDate" runat="server" ControlToCompare="hiddenbox" ErrorMessage="*"
ControlToValidate="txtCompletionDate" CssClass="labelError" ToolTip="Completion Date should be greater than or equal to Today"
Operator="GreaterThanEqual" Type="Date"></asp:CompareValidator>
<asp:TextBox ID="hiddenbox" runat="server" CssClass="hiddenbox">
</asp:TextBox>
add the below line in the CSS
.hiddenbox {display:none;}

MVC3 Validation for textboxes one or the other required

I'm looking for a way to check two textboxes in a form to make sure at least one of them is populated. The validation should fail only if both textboxes are empty. Is there an easy way to do this using Unobtrusive JScript and MVC3 form validation?
Thanks
You could implement something like this answer by Darin Dimitrov.
It explains how to make your own custom validator (on both client and server side). It will use the MVC3 validation and JQuery unobtrusive validation. You could check if the condition is met (one or more checkboxes are checked) and validate based on that.
Javascript you can do this way using Jquery
$(document).ready(function(){
var inp = $("#txt").val();
var inp2 = $("#txt2").val();
if(jQuery.trim(inp).length < 0 && jQuery.trim(inp2).length < 0)
{
//show your message.
}
})
You can look the conditional validation explained in below mentioned article
http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx
you can put [RequiredIf] attribute on both text boxes and check if textBox1 is empty then textbox2 is required and vice versa.
Try this. It has all the info. Hope it helps:
http://derans.blogspot.com/2011/05/contact-form-revisited-with-aspnet-mvc.html
Try nuget package foolproof validation. It includes [Requiredif] and [Requiredifnot] http://foolproof.codeplex.com/
Here is mine version of AtLeastOneRequired validator with supporting DisplayAttribute:
[AttributeUsage(AttributeTargets.Property)]
public class AtLeastOneRequiredAttribute : ValidationAttribute
{
private readonly string[] _members;
public AtLeastOneRequiredAttribute(params string[] members)
{
_members = members;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (_members == null || _members.Length < 1)
return null;
var displayNames = new List<string>();
foreach (var member in _members)
{
var propertyInfo = validationContext.ObjectType.GetProperty(member);
if (propertyInfo == null)
throw new InternalErrorException("Property '{0}' cannot be found in '{1}'", member, validationContext.ObjectType);
var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance);
var stringValue = propertyValue as string;
if (stringValue != null && stringValue.Trim().Length != 0)
return ValidationResult.Success;
var displayAttribute = propertyInfo.GetCustomAttribute<DisplayAttribute>();
displayNames.Add(displayAttribute != null ? displayAttribute.Name : member);
}
return new ValidationResult(FormatErrorMessage(String.Join(", ", displayNames)));
}
}
And very simple model:
public class FeedbackPostModel
{
[Display(Name = "Phone")]
[AtLeastOneRequired("SenderPhone", "SenderEmail", ErrorMessageResourceName = "ValidationAtLeastOnRequired", ErrorMessageResourceType = typeof(Strings))]
[StringLength(256, ErrorMessageResourceName = "ValidationFieldStringLengthMax", ErrorMessageResourceType = typeof(Strings))]
[Phone(ErrorMessageResourceName = "ValidationFieldPhoneFormat", ErrorMessageResourceType = typeof(Strings))]
public string SenderPhone { get; set; }
[Display(Name = "Email")]
[StringLength(256, ErrorMessageResourceName = "ValidationFieldStringLengthMax", ErrorMessageResourceType = typeof(Strings))]
[EmailAddress(ErrorMessageResourceName = "ValidationFieldEmailAddress", ErrorMessageResourceType = typeof(Strings))]
public string SenderEmail { get; set; }
}

ASP MVC 2 Validation : Passing Javascript code to the client

I am writing a custom validation attribute
It does conditional validation between two fields
When I create my rule, one of the things that I could not solve is how to pass javascript code through ValidationParameters
Usually, I just do
ValidationParameters["Param1"] = "{ required :function(element) { return $("#age").val() < 13;) }"
However, the MicrosoftMvcJQueryValidation.js routines trnasforms this to
Param1 = "{ required :function(element) { return $("#age").val() < 13;) }"
I could use Param1.eval() in Javascript. This will evaluates and executes the code but I just want to evalute the code and execute it later
JSON parser does not parse string contening Javascript code
So I am asking here for any idea
Not sure how you would inject javascript as you describe, but you may want to consider using the custom validation pattern for ASP.NET MVC 2.
Important pieces are the ValidationAttribute, DataAnnotationsModelValidator, registering the validator in Application_Start with DataAnnotationsModelValidatorProvider.RegisterAdapter, and the client side Sys.Mvc.ValidatorRegistry.validators function collection to register your client side validation code.
Here's the example code from my post.
[RegularExpression("[\\S]{6,}", ErrorMessage = "Must be at least 6 characters.")]
public string Password { get; set; }
[StringLength(128, ErrorMessage = "Must be under 128 characters.")]
[MinStringLength(3, ErrorMessage = "Must be at least 3 characters.")]
public string PasswordAnswer { get; set; }
public class MinStringLengthAttribute : ValidationAttribute
{
public int MinLength { get; set; }
public MinStringLengthAttribute(int minLength)
{
MinLength = minLength;
}
public override bool IsValid(object value)
{
if (null == value) return true; //not a required validator
var len = value.ToString().Length;
if (len < MinLength)
return false;
else
return true;
}
}
public class MinStringLengthValidator : DataAnnotationsModelValidator<MinStringLengthAttribute>
{
int minLength;
string message;
public MinStringLengthValidator(ModelMetadata metadata, ControllerContext context, MinStringLengthAttribute attribute)
: base(metadata, context, attribute)
{
minLength = attribute.MinLength;
message = attribute.ErrorMessage;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule
{
ErrorMessage = message,
ValidationType = "minlen"
};
rule.ValidationParameters.Add("min", minLength);
return new[] { rule };
}
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MinStringLengthAttribute), typeof(MinStringLengthValidator));
}
Sys.Mvc.ValidatorRegistry.validators["minlen"] = function(rule) {
//initialization
var minLen = rule.ValidationParameters["min"];
//return validator function
return function(value, context) {
if (value.length < minLen)
return rule.ErrorMessage;
else
return true; /* success */
};
};

Resources