public class LowerThanAttribute : ValidationAttribute { public LowerThanAttribute(string dependentPropertyName) { DependentPropertyName = dependentPropertyName; } public string DependentPropertyName { get; set; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { int? currentPropertyValue = value as int?; currentPropertyValue ??= 0; var typeInfo = validationContext.ObjectInstance.GetType(); var dependentPropertyValue = Convert.ToInt32(typeInfo.GetProperty(DependentPropertyName) .GetValue(validationContext.ObjectInstance, null)); var displayDependentProperyName = typeInfo.GetProperty(DependentPropertyName) .GetCustomAttributes(typeof(DisplayAttribute), false) .Cast<DisplayAttribute>() .FirstOrDefault()?.Name; if (!(currentPropertyValue.Value < dependentPropertyValue)) { return new ValidationResult("مقدار {0} باید کمتر باشد از " + displayDependentProperyName); } return ValidationResult.Success; } }
اما یک مشکل! این عمل فقط در سمت سرور بررسی میشود و هنگامیکه ModelState.IsValid را در اکشن متد فراخوانی میکنیم، عمل اعتبارسنجی انجام میشود. یعنی همهی دادهها به سمت سرور ارسال میشوند و اگر خطایی در ModelState وجود داشته باشد، کاربر مجددا باید دادهها را ارسال کند.
اما میتوان با استفاده از اینترفیس IClientModelValidator، عمل اعتبارسنجی را برای این ویژگی در سمت کلاینت انجام داد. برای انجام این کار ابتدا باید از اینترفیس IClientModelValidator ارث بری کنیم و متد AddValidation آن را پیاده سازی کنیم.
public class LowerThanAttribute : ValidationAttribute, IClientModelValidator { public LowerThanAttribute(string dependentPropertyName) { DependentPropertyName = dependentPropertyName; } public string DependentPropertyName { get; set; } public void AddValidation(ClientModelValidationContext context) { var displayCurrentProperyName = context.ModelMetadata.ContainerMetadata .ModelType.GetProperty(context.ModelMetadata.PropertyName) .GetCustomAttributes(typeof(DisplayAttribute), false) .Cast<DisplayAttribute>() .FirstOrDefault()?.Name; var displayDependentProperyName = context.ModelMetadata.ContainerMetadata .ModelType.GetProperty(DependentPropertyName) .GetCustomAttributes(typeof(DisplayAttribute), false) .Cast<DisplayAttribute>() .FirstOrDefault()?.Name; MergeAttribute(context.Attributes, "data-val", "true"); MergeAttribute(context.Attributes, "data-val-lowerthan", $"{displayCurrentProperyName} باید کمتر باشد از {displayDependentProperyName}"); MergeAttribute(context.Attributes, "data-val-dependentpropertyname", "#" + DependentPropertyName); } private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value) { if (attributes.ContainsKey(key)) { return false; } attributes.Add(key, value); return true; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { int? currentPropertyValue = value as int?; currentPropertyValue ??= 0; var typeInfo = validationContext.ObjectInstance.GetType(); var dependentPropertyValue = Convert.ToInt32(typeInfo.GetProperty(DependentPropertyName) .GetValue(validationContext.ObjectInstance, null)); var displayCurrentProperyName = typeInfo.GetProperty(DependentPropertyName) .GetCustomAttributes(typeof(DisplayAttribute), false) .Cast<DisplayAttribute>() .FirstOrDefault()?.Name; if (!(currentPropertyValue.Value < dependentPropertyValue)) { return new ValidationResult("مقدار {0} باید کمتر باشد از " + displayCurrentProperyName); } return ValidationResult.Success; } }
jQuery.validator.addMethod("lowerthan", function (value, element, param) { var otherPropId = $(element).data('val-dependentpropertyname'); if (otherPropId) { var otherProp = $(otherPropId); if (otherProp) { var otherVal = otherProp.val(); if (parseInt(otherVal) > parseInt(value)) { return true; } return false; } } return true; }); jQuery.validator.unobtrusive.adapters.addBool("lowerthan");
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script> <script src="~/js/LowerThan.js"></script>
public class User { [Required] [Display(Name ="نام کاربری")] public string Username { get; set; } [Required] [Display(Name = "سن")] public int Age { get; set; } [LowerThan(nameof(Age))] [Required] [Display(Name = "سابقه کار")] public int Experience { get; set; } }