MVC Validation Lower/Higher Than Other Value

MVC Validation Lower/Higher than other value

You can use a custom validation attribute here is my example with dates.
But you can use it with ints too.

First, here is the model :

public DateTime Beggining { get; set; }

[IsDateAfterAttribute("Beggining", true, ErrorMessageResourceType = typeof(LocalizationHelper), ErrorMessageResourceName = "PeriodErrorMessage")]
public DateTime End { get; set; }

And here is the attribute itself :

public sealed class IsDateAfterAttribute : ValidationAttribute, IClientValidatable
{
private readonly string testedPropertyName;
private readonly bool allowEqualDates;

public IsDateAfterAttribute(string testedPropertyName, bool allowEqualDates = false)
{
this.testedPropertyName = testedPropertyName;
this.allowEqualDates = allowEqualDates;
}

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName);
if (propertyTestedInfo == null)
{
return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName));
}

var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

if (value == null || !(value is DateTime))
{
return ValidationResult.Success;
}

if (propertyTestedValue == null || !(propertyTestedValue is DateTime))
{
return ValidationResult.Success;
}

// Compare values
if ((DateTime)value >= (DateTime)propertyTestedValue)
{
if (this.allowEqualDates && value == propertyTestedValue)
{
return ValidationResult.Success;
}
else if ((DateTime)value > (DateTime)propertyTestedValue)
{
return ValidationResult.Success;
}
}

return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessageString,
ValidationType = "isdateafter"
};
rule.ValidationParameters["propertytested"] = this.testedPropertyName;
rule.ValidationParameters["allowequaldates"] = this.allowEqualDates;
yield return rule;
}

What is the best way of adding a greater than 0 validator on the client-side using MVC and data annotation?

You can't store a number bigger than what your underlying data type could hold so that fact that the Range attribute requires a max value is a very good thing. Remember that doesn't exist in the real world, so the following should work:

[Range(1, int.MaxValue, ErrorMessage = "Please enter a value bigger than {1}")]
public int Value { get; set; }

Custom Validation Attributes: Comparing two properties in the same model

You can create a custom validation attribute for comparison two properties. It's a server side validation:

public class MyViewModel
{
[DateLessThan("End", ErrorMessage = "Not valid")]
public DateTime Begin { get; set; }

public DateTime End { get; set; }
}

public class DateLessThanAttribute : ValidationAttribute
{
private readonly string _comparisonProperty;

public DateLessThanAttribute(string comparisonProperty)
{
_comparisonProperty = comparisonProperty;
}

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
ErrorMessage = ErrorMessageString;
var currentValue = (DateTime)value;

var property = validationContext.ObjectType.GetProperty(_comparisonProperty);

if (property == null)
throw new ArgumentException("Property with this name not found");

var comparisonValue = (DateTime)property.GetValue(validationContext.ObjectInstance);

if (currentValue > comparisonValue)
return new ValidationResult(ErrorMessage);

return ValidationResult.Success;
}
}

Update:
If you need a client side validation for this attribute, you need implement an IClientModelValidator interface:

public class DateLessThanAttribute : ValidationAttribute, IClientModelValidator
{
...
public void AddValidation(ClientModelValidationContext context)
{
var error = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-error", error);
}
}

The AddValidation method will add attributes to your inputs from context.Attributes.

Sample Image

You can read more here IClientModelValidator

validation depending on the values of other fields (MVC)

You have two possible approaches here.

IValidatableObject

As mentioned by user stuartd in the comments, you could implement the IValidatableObject in your model to make your validation.
In your case, your code would look something like this:

public class MyModel : IValidatableObject
{
// Your properties go here

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// You may want to check your properties for null before doing this
var sumOfFields = PhoneNumber.Length + Area.Length + Prefix.Length;

if(sumOfFields != 10)
return new ValidationResult("Incorrect phone number!");
}
}

Custom ValidationAttribute

Since you stated that you want to use data annotations, you could implement a custom ValidationAttribute.
It would go something along these lines.

public class TotalAttributesLengthEqualToAttribute : ValidationAttribute
{
private string[] _properties;
private int _expectedLength;
public TotalAttributesLengthEqualToAttribute(int expectedLength, params string[] properties)
{
ErrorMessage = "Wrong total length";
_expectedLength = expectedLength;
_properties = properties;
}

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (_properties == null || _properties.Length < 1)
{
return new ValidationResult("Wrong properties");
}

int totalLength = 0;

foreach (var property in _properties)
{
var propInfo = validationContext.ObjectType.GetProperty(property);

if (propInfo == null)
return new ValidationResult($"Could not find {property}");

var propValue = propInfo.GetValue(validationContext.ObjectInstance, null) as string;

if (propValue == null)
return new ValidationResult($"Wrong property type for {property}");

totalLength += propValue.Length;
}

if (totalLength != _expectedLength)
return new ValidationResult(ErrorMessage);

return ValidationResult.Success;
}
}

Than you would choose one of your properties and implement it like:

[TotalAttributesLengthEqualTo(10, nameof(PhoneNumber), nameof(Area), nameof(Prefix), ErrorMessage = "The phone number should contain 10 digits")]
public string PhoneNumber
{
get...

Note that if your compiler does not support C# 6.0, you will have to change the strings starting with $ to string.Format, and you will have to substitute the attribute names inside nameof() for ther hardcoded names.

Greater Than or Equal To Today Date validation annotation in MVC3

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 :)



Related Topics



Leave a reply



Submit