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

时间:2016-03-16 10:52:06

标签: asp.net-mvc validation

我可以做服务器端部分。我想如果开始日期不为空,则结束日期必须等于或大于开始日期。服务器端逻辑几乎完成,但我有点混淆如何做客户端逻辑。基本上我想通过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>

}

2 个答案:

答案 0 :(得分:1)

如果我做对了 - 那么你需要根据开始日期在结束日期添加验证,即依据值。 使用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);
    }
}

答案 1 :(得分:0)

对于客户端验证,如果您使用的是jquery ui(datepicker),那么您需要做的就是

<!-- Client form -->
<form>
   <?php wp_nonce_field('my_form','_my_token'); ?>
   <!-- Additional form fields -->
</form>

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