【问题标题】:Validation for DateTime in MVCMVC 中的 DateTime 验证
【发布时间】:2016-04-15 08:57:53
【问题描述】:

来自winforms,我对MVC和学习很陌生。所以请多多包涵。 我正在尝试在 MVC 中以正确的方式进行一些验证。我有一些使用 JS 的代码,但我想修改它以使用 MVC 进行验证。

这是我的模特

public class MyViewModel
{

    /// <summary>
    /// Start Date
    /// </summary>
     [DataType(DataType.Date)] 
    [DisplayFormat(DataFormatString = "{0:d}",ApplyFormatInEditMode=true)]
    [Display(ResourceType = typeof(UIResources.GeneralPurpose), Name = "StartDate")]
    public DateTime StartDate { get; set; }

    /// <summary>
    /// End Date
    /// </summary>
     [DataType(DataType.Date)]
     [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
     [Display(ResourceType = typeof(UIResources.GeneralPurpose), Name = "EndDate")]
    public DateTime EndDate { get; set; }
}

这就是我的 html 的样子

@model MyViewModel
@using ...
{
    <div id="ErrMsg" class="validation-summary-errors center">
    </div>

    using (Ajax.BeginForm("someAction", "someController", new AjaxOptions()))
    {

        @Html.ValidationSummary()

        <fieldset class="control-set-container no-border">
            <ul class="undecorated-list inline-list-items">
                <li>
                    @Html.LabelFor(model => model.StartDate)
                    @Html.MyDateTimePicker(model => model.StartDate)
                </li>
                <li>
                    @Html.LabelFor(model => model.EndDate)
                    @Html.MyDateTimePicker(model => model.EndDate)
                </li>
            </ul>
        </fieldset>
    }

@Html.MyDateTimePicker 编写一些 HTML,给出一个文本框和一个日期选择器控件(用于以某种日期格式显示日期的文本框)。

这是我要验证的内容,

  1. 如果日期格式不正确 (dd/MM/yyyy),则应将 errMsg.Html 设置为视图模型中指定的消息。
  2. 如果 startDate 大于 endDate,则在 errMsg.Html 中显示消息。
  3. 在此期间,我想验证日期是否为 2 种不同格式之一(dd/MM/yyyy 或 M/d/yyyy),在验证失败时显示错误消息。

【问题讨论】:

  • 首先您需要@Html.ValidationMessageFor(m =&gt; m.StartDate) 来显示验证错误消息。 (1) 如果您想覆盖无效值的默认错误消息,请参阅this answer。 (2) 使用foolproof[GreaterThan] 或类似的条件验证属性。 (3) 不可能 - 如果您允许两种格式,控制器如何知道 16/04/2016 是否是有效日期。
  • 但是您没有显示MyDateTimePicker() 的代码,所以我们不可能知道它是否生成了正确的html,并带有客户端验证所需的适当data-val-* 属性。并且在您的 DisplayFormatAttribute 中包含 ApplyFormatInEditMode = true 是没有意义的,因为它仅在 EditorFor() 方法中受到尊重,并且它必须是 DataFormatString = "{0:yyyy-MM-dd}" 才能正常工作。

标签: c# asp.net-mvc-4 razor


【解决方案1】:

MVC 允许您通过使用Remote 属性或创建新属性来创建自定义验证属性。

Remote 属性允许您让 jquery 在字段验证期间向指定方法发送 Ajax 调用,此时将抛出 onfocusout 事件。

例如,我的 UserController 中有一个方法可以确保在应用程序中不会两次使用相同的 UserId:

[Remote("UnicityUserId", "User", ErrorMessageResourceName = "ErrorUnicity", ErrorMessageResourceType = typeof(Resources.Resources), AdditionalFields = "ID")]
public string UserId {get;set;}

然后,在我的控制器中:

public JsonResult UnicityUserId(string UserId, string ID)
{
    int id = 0;
    Int32.TryParse(ID, out id);
    bool ok = false;

    if (!String.IsNullOrEmpty(UserId))
        ok = !UserDb.Exist(this.db, this.Tracer, UserDb.UserId, UserId, id); //Checks wether there is already another user with the same UserId

    return (Json(ok, JsonRequestBehavior.AllowGet));
}

更多信息here

当 MVC 将接收您的 POST 数据并尝试将其绑定到您的模型时,将执行另一种验证模式。

对于此方法,您必须创建自己的属性。

仍然来自唯一性示例:

public class UnicityAttribute : ValidationAttribute

这个类必须实现一个名为 IsValid 的方法,该方法将执行验证并将 ValidationResult 返回到 MVC 的 ModelBinder

为了确保 MVC 会调用它,只需将属性放在你的字段上:

[UnicityAttribute]
public string UserId {get;set;}

更多信息here

【讨论】:

  • 感谢 Marrow 的链接。撇开简单的验证不谈,我注意到链接中的示例提到了服务器端验证(无需刷新整个页面)。这是 MVC 的典型使用 C# 和 MVC 的服务器端验证,而不是使用 JS 的客户端验证?所以总是有回调到服务器。
  • 我不知道这是否是典型的,但是使服务器端验证使代码更易于阅读(视图包含更少的 JS),并且在 c# 中比在 JS 中更容易管理很多事情(日期、小数等...)。
【解决方案2】:
    enter code here
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Attributes
{
    [AttributeUsage(AttributeTargets.Property)]
    public sealed class MinimumPaymentDateAttribute : ValidationAttribute, IClientValidatable
    {
        private readonly string errorMessage;
        public string ValidationErrorMessage { get { return errorMessage; } }
        /// <summary>
        /// Constructor for intializing variables
        /// </summary>
        public MinimumPaymentDateAttribute()
        {
        }

        /// <summary>
        ///  Constructor for intializing variables
        /// </summary>
        /// <param name="validationErrorMessage"></param>
        public MinimumPaymentDateAttribute(string validationErrorMessage)
        {
            this.errorMessage = validationErrorMessage;
        }
        /// <summary>
        /// Validation for of Rule implement Client Validation
        /// </summary>
        /// <param name="value"></param>
        /// <param name="validationContext"></param>
        /// <returns></returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (null != validationContext)
            {
                PaymentInformation paymentInfo = (PaymentInformation)validationContext.ObjectInstance;
                if (value != null && validationContext != null)
                {
                    if (paymentInfo.PaymentDate < paymentInfo.MinDate)
                    {
                        return new ValidationResult(this.ValidationErrorMessage);
                    }
                }
            }
            return ValidationResult.Success;
        }

        /// <summary>
        ///  Validation rules client side for Minimum Date
        /// </summary>
        /// <param name="metadata"></param>
        /// <param name="context"></param>
        /// <returns>IEnumerable<ModelClientValidationRule></returns>
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            string errorMessage = this.FormatErrorMessage(metadata.DisplayName);
            ModelClientValidationRule MinDateRule = new ModelClientValidationRule();
            DateTime? validationData = GetValidationParameters(context.Controller.ViewData.Model);
            MinDateRule.ErrorMessage = errorMessage;
            MinDateRule.ValidationType = "validminpaymentdate";(Java script function name)
            MinDateRule.ValidationParameters.Add("mindate", validationData);
            yield return MinDateRule;
        }


        /// <summary>
        ///  Checking for Model type for handling Different ViewData
        /// </summary>
        /// <param name="model"></param>   
        /// <returns>string[]</returns>
        private static DateTime? GetValidationParameters(object model)
        {
            DateTime? MinDate=null;
            if (model.GetType() == typeof(PaymentInformation))
            {
                PaymentInformation obj = (PaymentInformation)model;
                return obj.MinDate;
            }
            else if (model.GetType() == typeof(PaymentViewModel))
            {
                PaymentViewModel obj = (PaymentViewModel)model;
                return obj.PaymentInfo.MinDate;
            }
            return MinDate;
        }
    }
}


$.validator.addMethod("validminpaymentdate", function (value, element, params) {
    var valid = true;
    var mindate = new Date(params);
    var valdate = new Date(value);
    if (valdate < mindate) {
        valid = false;
    }
    return valid;

});
$.validator.unobtrusive.adapters.addSingleVal("validminpaymentdate", "mindate");

【讨论】:

    【解决方案3】:
    function checkdate(input) {
    
        //var validformat = /^\d{4}\-\d{2}\-\d{2}$/;
        var validformat = /^(\d{4})-(\d{2})-(\d{2})$/;  //Basic check for format validity
        if (input.val() != "") {
            if (!validformat.test(input.val()))
                return false;
            else { //Detailed check for valid date ranges
                var monthfield = input.val().split("-")[1];
                var dayfield = input.val().split("-")[2];
                var yearfield = input.val().split("-")[0];
                var dayobj = new Date(yearfield, monthfield - 1, dayfield);
                if ((dayobj.getMonth() + 1 != monthfield) || (dayobj.getDate() != dayfield) || (dayobj.getFullYear() != yearfield))
                //alert("Invalid Date Format.");
                    return false;
                else
                    return true;
            }
        }
        else {
            return true;
        }
    
    }
    

    参数值'input'会取日期时间控制的对象

    var obj=$('#txtDatetime');
    

    Call - CheckDate(obj); 你要验证的地方

    【讨论】:

    • 你读过这个问题吗? OP 根本不要求进行 javascript 验证(甚至在标签中也没有)
    • 我已经有JS了,不找更多的JS了。 MVC 主要围绕保持视图尽可能简单。
    • 好的,最好使用数据注释 Apply DataAnnotation like: [DisplayFormat(DataFormatString = "{0:MMM dd, yyyy}")]
    • 最好有 js。如果您认为您的观点会很沉重,那是错误的想法。因为你在 mvc 中捆绑了不依赖于视图的脚本加载。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    相关资源
    最近更新 更多