日期的 MVC 模型验证

Posted

技术标签:

【中文标题】日期的 MVC 模型验证【英文标题】:MVC model validation for date 【发布时间】:2014-03-13 16:46:49 【问题描述】:

对于 MVC 5 是否有任何默认验证,我可以在其中设置日期的最小值和最大值?

在我的模型中我想要日期验证

    public class MyClass
                   
        [Required(ErrorMessage="Start date and time cannot be empty")]
        //validate:Must be greater than current date
        [DataType(DataType.DateTime)]
        public DateTime StartDateTime  get; set; 

        [Required(ErrorMessage="End date and time cannot be empty")]
        //validate:must be greater than StartDate
        [DataType(DataType.DateTime)]
        public DateTime EndDateTime  get; set;             
    

Ps:根据这个Asp.Net Website,使用Range验证器对DateTime有问题,不推荐。

注意:jQuery 验证不适用于 Range 属性和 约会时间。例如,以下代码将始终显示 客户端验证错误,即使日期在 指定范围:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

您需要禁用 jQuery 日期验证才能将 Range 属性与 DateTime 一起使用。硬编译通常不是一个好习惯 模型中的日期,因此使用 Range 属性和 DateTime 是 气馁。

我也知道有像 Fluent Validation 和 Foolproof 这样的 Nuget 包可以验证和检查一个日期是否大于另一个日期,但我想知道默认情况下是否有一些东西可以检查日期的最小值和最大值。

从我在Whats new in MVC 5.1 中看到的,支持MaxLengthMinLength 验证。

【问题讨论】:

你可以创建一个custom validator ***.com/questions/40543473/… 看到这个答案 【参考方案1】:

无需禁用 jQuery 日期验证(这可能会导致其他问题)。您只需要覆盖$.validatorrange 方法即可。

默认情况下,它适用于数值(然后回退到字符串比较),因此您可以添加以下脚本(在 jquery.validate.jsjquery.validate.unobtrusive.js 之后,但不包含在 $(document).ready

$.validator.methods.range = function(value, element, param) 
    if ($(element).attr('data-val-date')) 
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime();
        var maxDate = new Date(max).getTime();
        return this.optional(element) || (date >= minDate && date <= maxDate);
    
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
;

然后你可以在你的财产上使用RangeAttribute

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
public DateTime Date  get; set; 

【讨论】:

谁能解释一下如何实现这个解决方案?如何添加提供的脚本? @Klicker 只需将此 JS 部分放在 $(function () $.validator.methods.range = function... 中,并在您的输入模型中使用 Range 属性 在 ASP.NET Core 5.0 中,'data-val-date' 未添加到输入元素,因此您必须手动将其添加到输入标记帮助程序。此外,如果您将绑定设置为 [DataType(DataType.Date)],则它不会在输入元素值中包含时间部分。 Date(value) 需要有一个时间值,否则 minDate 检查失败一天。【参考方案2】:

我会使用 System.ComponentModel.DataAnnotations 中的 IValidatableObject 接口来执行此操作,它允许您添加额外的验证规则,以便进行更多检查。将接口添加到您的类中,然后实现Validate 方法,您可以在其中将 StartDateTime 与当前日期/时间进行比较,并将 EndDateTime 与 StartDateTime 进行比较,例如

public class MyClass : IValidatableObject
               
    [Required(ErrorMessage="Start date and time cannot be empty")]
    //validate:Must be greater than current date
    [DataType(DataType.DateTime)]
    public DateTime StartDateTime  get; set; 

    [Required(ErrorMessage="End date and time cannot be empty")]
    //validate:must be greater than StartDate
    [DataType(DataType.DateTime)]
    public DateTime EndDateTime  get; set;        

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    
        List<ValidationResult> results = new List<ValidationResult>();

        if (StartDateTime < DateTime.Now)
        
            results.Add(new ValidationResult("Start date and time must be greater than current time", new []"StartDateTime"));
        

        if (EndDateTime <= StartDateTime)
        
            results.Add(new ValidationResult("EndDateTime must be greater that StartDateTime", new [] "EndDateTime"));
        

        return results;
         

唯一的潜在缺点是 Validate 在服务器端运行,而不是在 jQuery 验证中。

【讨论】:

【参考方案3】:

通常,当我想验证服务器中的某些内容时,我会使用此解决方案。 我知道您可以依赖 MVC 使用的验证模型,但是当我进行验证时,我会尝试使用单独的项目,以防我需要为它们进行单元测试。假设您有两个应用程序,一个桌面和一个 Web,那么两者都可以共享 ValidationProject,而不是在两个应用程序中为相同的“视图”/“屏幕”重复代码。这里的想法是将验证项目隔离为解决方案的独立项目。

所以你可以从 NuGet 下载 FluentValidation 项目,FluentValidation 在构造函数中使用规则,你可以在这里查看文档https://github.com/JeremySkinner/FluentValidation/wiki

你的日期规则可以这样使用,例如,你可以为你的最小值和最大值设置规则:

public class CustomerValidator: AbstractValidator<Customer> 
  public CustomerValidator() 
                    RuleFor(customer => customer.startDate)
                    .NotNull()
                    .WithMessage("You should select a start date")
                    .Must(d => d.HasValue && d.Value <= DateTime.Today)
                    .WithMessage("The start date should not be greather than current month/year");
  

现在在您的控制器中

[HttpPost]
public ActionResult Index(Customer c)

  if(ModelState.IsValid)
  
    var validator= new CustomerValidator();
    var valResult = validator.Validate(c);

    if (valResult.Errors.Count != 0)
    
       valResult.Errors.ForEach(x => ModelState.AddModelError(x.PropertyName, x.ErrorMessage));
       return View(vm);
    

    //Your code here
  

【讨论】:

【参考方案4】:

我认为只添加属性“范围”就可以了

[Range(typeof(DateTime), "01/01/1900", "06/06/2079", ErrorMessageResourceType = typeof(Resources.Patient), ErrorMessageResourceName = "DateOfBirth_Range")] 

【讨论】:

如果你查看这个网站 asp.net/mvc/tutorials/mvc-5/introduction/adding-validation 它说"Note: jQuery validation does not work with the Range attribute and DateTime. For example, the following code will always display a client side validation error, even when the date is in the specified range: [Range(typeof(DateTime), "1/1/1966", "1/1/2020")] You will need to disable jQuery date validation to use the Range attribute with DateTime. It's generally not a good practice to compile hard dates in your models, so using the Range attribute and DateTime is discouraged."

以上是关于日期的 MVC 模型验证的主要内容,如果未能解决你的问题,请参考以下文章

日期格式客户端验证 - MVC

使用父模型值的子模型验证。流畅的验证。 MVC4

自定义格式日期的 MVC3 不显眼日期验证

该字段必须是日期 - Chrome 中的 DatePicker 验证失败 - mvc

asp.net mvc 代码优先方法中的日期验证

Asp.net MVC 设置验证日期格式在 Chrome 上失败