ASP.Net MVC 条件验证:结束日期必须大于或等于开始日期



我可以做到服务器端部分。 我想要如果开始日期不为空,那么结束日期必须等于或大于开始日期。 服务器端逻辑几乎完成,但我有点困惑客户端逻辑该怎么做。 基本上我想通过IClientValidatable界面来做到这一点。

我的服务器端代码如下

型号代码

   public class DateValTest
    {
        [Display(Name = "Start Date")]
        [DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
        public DateTime? StartDate { get; set; }
        [Display(Name = "End Date")]
        [DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
        [DateGreaterThanAttribute(otherPropertyName = "StartDate", ErrorMessage = "End date must be greater than start date")]
        public DateTime?  EndDate { get; set; }
    }

属性代码

 public class DateGreaterThanAttribute : ValidationAttribute
    {
        public string otherPropertyName;
        public DateGreaterThanAttribute() { }
        public DateGreaterThanAttribute(string otherPropertyName, string errorMessage)
            : base(errorMessage)
        {
            this.otherPropertyName = otherPropertyName;
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ValidationResult validationResult = ValidationResult.Success;
            try
            {
                // Using reflection we can get a reference to the other date property, in this example the project start date
                var containerType = validationContext.ObjectInstance.GetType();
                var field = containerType.GetProperty(this.otherPropertyName);
                var extensionValue = field.GetValue(validationContext.ObjectInstance, null);
                var datatype = extensionValue.GetType();
                //var otherPropertyInfo = validationContext.ObjectInstance.GetType().GetProperty(this.otherPropertyName);
                if (field == null)
                    return new ValidationResult(String.Format("Unknown property: {0}.", otherPropertyName));
                // Let's check that otherProperty is of type DateTime as we expect it to be
                if ((field.PropertyType == typeof(DateTime) || (field.PropertyType.IsGenericType && field.PropertyType == typeof(Nullable<DateTime>))))
                {
                    DateTime toValidate = (DateTime)value;
                    DateTime referenceProperty = (DateTime)field.GetValue(validationContext.ObjectInstance, null);
                    // if the end date is lower than the start date, than the validationResult will be set to false and return
                    // a properly formatted error message
                    if (toValidate.CompareTo(referenceProperty) < 1)
                    {
                        validationResult = new ValidationResult(ErrorMessageString);
                    }
                }
                else
                {
                    validationResult = new ValidationResult("An error occurred while validating the property. OtherProperty is not of type DateTime");
                }
            }
            catch (Exception ex)
            {
                // Do stuff, i.e. log the exception
                // Let it go through the upper levels, something bad happened
                throw ex;
            }
            return validationResult;
        }
    }

我关心的是如何将开始日期文本框名称从服务器端传递到客户端,这将为结束日期文本框添加一些属性。

因此,只需帮助我为GetClientValidationRules功能构建一些服务器端代码,为客户端构建一些代码 例如,$.validator.unobtrusive.adapters.add and $.validator.addMethod任何人都可以帮助我实现它。

谢谢

更新

我尝试以这种方式解决它,但我的客户端 js 没有触发。 这是我修改后的代码。

型号代码

public class DateValTest
{
    [Display(Name = "Start Date")]
    [DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? StartDate { get; set; }
    [Display(Name = "End Date")]
    [DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [MyDate(ErrorMessage = "Back date entry not allowed")]
    [DateGreaterThanAttribute(otherPropertyName = "StartDate", ErrorMessage = "End date must be greater than start date")]
    public DateTime?  EndDate { get; set; }
}

我的属性相关代码

 public class DateGreaterThanAttribute : ValidationAttribute, IClientValidatable
    {
        public string otherPropertyName;
        public DateGreaterThanAttribute() { }
        public DateGreaterThanAttribute(string otherPropertyName, string errorMessage)
            : base(errorMessage)
        {
            this.otherPropertyName = otherPropertyName;
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ValidationResult validationResult = ValidationResult.Success;
            try
            {
                // Using reflection we can get a reference to the other date property, in this example the project start date
                var containerType = validationContext.ObjectInstance.GetType();
                var field = containerType.GetProperty(this.otherPropertyName);
                var extensionValue = field.GetValue(validationContext.ObjectInstance, null);
                var datatype = extensionValue.GetType();
                //var otherPropertyInfo = validationContext.ObjectInstance.GetType().GetProperty(this.otherPropertyName);
                if (field == null)
                    return new ValidationResult(String.Format("Unknown property: {0}.", otherPropertyName));
                // Let's check that otherProperty is of type DateTime as we expect it to be
                if ((field.PropertyType == typeof(DateTime) || (field.PropertyType.IsGenericType && field.PropertyType == typeof(Nullable<DateTime>))))
                {
                    DateTime toValidate = (DateTime)value;
                    DateTime referenceProperty = (DateTime)field.GetValue(validationContext.ObjectInstance, null);
                    // if the end date is lower than the start date, than the validationResult will be set to false and return
                    // a properly formatted error message
                    if (toValidate.CompareTo(referenceProperty) < 1)
                    {
                        validationResult = new ValidationResult(ErrorMessageString);
                    }
                }
                else
                {
                    validationResult = new ValidationResult("An error occurred while validating the property. OtherProperty is not of type DateTime");
                }
            }
            catch (Exception ex)
            {
                // Do stuff, i.e. log the exception
                // Let it go through the upper levels, something bad happened
                throw ex;
            }
            return validationResult;
        }
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
                ValidationType = "isgreater",
            };
            rule.ValidationParameters.Add("otherproperty", otherPropertyName);
            yield return rule;
        }
    }

我的 js 代码

$.validator.unobtrusive.adapters.add('isgreater', ['otherproperty'], function (options) {
    options.rules['isgreater'] = { isgreater: options.params.otherproperty };
    options.messages['isgreater'] = options.message;
});
$.validator.addMethod("isgreater", function (value, element, param) {
    alert('pop' + params.otherproperty);
    var otherProp = $('#' + params.otherproperty);
    var date = new Date(value);
    if (otherProp.val() != '')
    {
        return date >= minDate;
    }
    return true;
});

我的结束日期文本框 html 如下所示

<input type="date" 
value="03/16/2016" 
name="EndDate" 
id="EndDate" 
data-val-restrictbackdates-mindate="03/16/2016 00:00:00" 
data-val-restrictbackdates="Back date entry not allowed" 
data-val-isgreater-otherproperty="StartDate" 
data-val-isgreater="End date must be greater than start date" 
data-val-date="The field End Date must be a date." 
data-val="true" 
class="input-validation-error form-control text-box single-line">

问题是我的JS代码没有触发.....无法捕获该区域 js 代码中的错误是什么。需要一些提示或帮助。谢谢

我解决...此处更新了代码

型号代码

public class DateValTest
{
    [Display(Name = "Start Date")]
    [DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? StartDate { get; set; }
    [Display(Name = "End Date")]
    [DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [MyDate(ErrorMessage = "Back date entry not allowed")]
    [DateGreaterThanAttribute(otherPropertyName = "StartDate", ErrorMessage = "End date must be greater than start date")]
    public DateTime?  EndDate { get; set; }
}

自定义属性相关类代码

public class MyDateAttribute : ValidationAttribute, IClientValidatable
{
    private DateTime _MinDate;
    public MyDateAttribute()
    {
        _MinDate = DateTime.Today;
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        DateTime _EndDat = DateTime.Parse(value.ToString(), CultureInfo.InvariantCulture);
        DateTime _CurDate = DateTime.Today;
        int cmp = _EndDat.CompareTo(_CurDate);
        if (cmp > 0)
        {
            // date1 is greater means date1 is comes after date2
            return ValidationResult.Success;
        }
        else if (cmp < 0)
        {
            // date2 is greater means date1 is comes after date1
            return new ValidationResult(ErrorMessage);
        }
        else
        {
            // date1 is same as date2
            return ValidationResult.Success;
        }
    }
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "restrictbackdates",
        };
        rule.ValidationParameters.Add("mindate", _MinDate);
        yield return rule;
    }
}
public class DateGreaterThanAttribute : ValidationAttribute, IClientValidatable
{
    public string otherPropertyName;
    public DateGreaterThanAttribute() { }
    public DateGreaterThanAttribute(string otherPropertyName, string errorMessage)
        : base(errorMessage)
    {
        this.otherPropertyName = otherPropertyName;
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ValidationResult validationResult = ValidationResult.Success;
        try
        {
            // Using reflection we can get a reference to the other date property, in this example the project start date
            var containerType = validationContext.ObjectInstance.GetType();
            var field = containerType.GetProperty(this.otherPropertyName);
            var extensionValue = field.GetValue(validationContext.ObjectInstance, null);
            if(extensionValue==null)
            {
                //validationResult = new ValidationResult("Start Date is empty");
                return validationResult;
            }
            var datatype = extensionValue.GetType();
            //var otherPropertyInfo = validationContext.ObjectInstance.GetType().GetProperty(this.otherPropertyName);
            if (field == null)
                return new ValidationResult(String.Format("Unknown property: {0}.", otherPropertyName));
            // Let's check that otherProperty is of type DateTime as we expect it to be
            if ((field.PropertyType == typeof(DateTime) || (field.PropertyType.IsGenericType && field.PropertyType == typeof(Nullable<DateTime>))))
            {
                DateTime toValidate = (DateTime)value;
                DateTime referenceProperty = (DateTime)field.GetValue(validationContext.ObjectInstance, null);
                // if the end date is lower than the start date, than the validationResult will be set to false and return
                // a properly formatted error message
                if (toValidate.CompareTo(referenceProperty) < 1)
                {
                    validationResult = new ValidationResult(ErrorMessageString);
                }
            }
            else
            {
                validationResult = new ValidationResult("An error occurred while validating the property. OtherProperty is not of type DateTime");
            }
        }
        catch (Exception ex)
        {
            // Do stuff, i.e. log the exception
            // Let it go through the upper levels, something bad happened
            throw ex;
        }
        return validationResult;
    }
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "isgreater",
        };
        rule.ValidationParameters.Add("otherproperty", otherPropertyName);
        yield return rule;
    }
}

使用 js 查看代码

@model AuthTest.Models.DateValTest
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <h4>DateValTest</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.StartDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.StartDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.StartDate, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.EndDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.EndDate, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
<script src="https://cdn.jsdelivr.net/momentjs/2.12.0/moment.min.js"></script>
<script type="text/javascript">
    $.validator.unobtrusive.adapters.add('restrictbackdates', ['mindate'], function (options) {
        options.rules['restrictbackdates'] = { mindate: options.params.mindate };
        options.messages['restrictbackdates'] = options.message;
    });
    $.validator.addMethod("restrictbackdates", function (value, element, param) {
        var date = new Date(value);
        var minDate = new Date(param.mindate);
        return date >= minDate;
    });
    $.validator.unobtrusive.adapters.add('isgreater', ['otherproperty'], function (options) {
        options.rules['isgreater'] = { otherproperty: options.params.otherproperty };
        options.messages['isgreater'] = options.message;
    });
    $.validator.addMethod("isgreater", function (value, element, param) {
        var otherProp = $('#' + param.otherproperty);
        if (otherProp.val() != '') {
            var StartDate = new Date(moment(otherProp.val(), 'MM/DD/YYYY'));
            var Enddate = new Date(value);
            if (StartDate != '') {
                return Enddate >= StartDate;
            }
        }
        return true;
    });
</script>
}
如果我

做对了 - 那么您需要根据开始日期(即取决于值)在结束日期添加验证。使用Foolproof可以很容易地完成.js其中有各种属性,如RequiredIf,RequiredIfRegexMatch等。您还可以编写自定义代码,以覆盖默认属性的方式,就像我们对 MVC 属性所做的那样。举个例子:

using Foolproof;
public class MustBeTrueIfAttribute : RequiredIfAttribute
{
    static MustBeTrueIfAttribute()
    {
        Register.Attribute(typeof(MustBeTrueIfAttribute));
    }
    public MustBeTrueIfAttribute(string dependentProperty, object dependentValue)
        : base(dependentProperty, dependentValue)
    {
    }
    public MustBeTrueIfAttribute(string dependentProperty, Operator @operator, object dependentValue)
        : base(dependentProperty, @operator, dependentValue)
    {
    }

    public override string ClientTypeName => "mustbetrueif";
    public override bool IsValid(object value, object dependentValue, object container)
    {
        return !this.Metadata.IsValid(dependentValue, this.DependentValue) || (value != null && (bool)value);
    }
}

用于客户端验证,如果您使用的是jQuery UI(日期选择器),您需要做的就是

   $(function () {
    $("#txtFrom").datepicker({
        numberOfMonths: 2,
        onSelect: function (selected) {
            var dt = new Date(selected);
            dt.setDate(dt.getDate() + 1);
            $("#txtTo").datepicker("option", "minDate", dt);
        }
    });
    $("#txtTo").datepicker({
        numberOfMonths: 2,
        onSelect: function (selected) {
            var dt = new Date(selected);
            dt.setDate(dt.getDate() - 1);
            $("#txtFrom").datepicker("option", "maxDate", dt);
        }
    });
});

来源 :http://www.aspsnippets.com/Articles/jQuery-DatePicker-Start-Date-should-be-less-than-End-date-validation.aspx

最新更新