为什么 MVC4 验证 js 自动将数字验证添加到日期时间

Why does MVC4 validate js auto adds number validation to datetime?

本文关键字:验证 添加 日期 数字 时间 MVC4 js 为什么      更新时间:2023-12-28

我最近升级到MVC 4并使用validate.js和validate.unobtrosive.js进行客户端验证。自 MVC 4 以来,我注意到 html 输出发生了变化。

MVC3:

<input class="dutchDate date_datepicker hasDatepicker" id="FirstDate" name="FirstDate" type="text" value="18-02-2015">

MVC4:

<input class="dutchDate date_datepicker hasDatepicker" data-val="true" data-val-number="Waarde moet numeriek zijn" id="FirstDate" name="FirstDate" type="text" value="18-02-2015">

所以现在日期时间字段由我的自定义验证和数字验证进行验证。我不明白为什么要将数字验证添加到输入标签中。有些人有过同样的经历吗?我不想在日期输入上进行数字验证。

型:

public class TripFilter : IResultFilter
{
    ...
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? FirstDate { get; set; }
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? UntilDate { get; set; }
    ...
}

渲染:

@Html.TextBox("", dt.ToString("dd-MM-yyyy"), new { @class = ViewData["class"] + " dutchDate date_datepicker", @type = "text" }

编辑

在全局 asax 中进行一些检查后,我注意到以下行:

ModelValidatorProviders.Providers.Add(new ClientNumberValidatorProvider());

它执行以下操作:

public class ClientNumberValidatorProvider : ClientDataTypeModelValidatorProvider
{
    public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
    {
        bool isNumericField = base.GetValidators(metadata, context).Any();
        if (isNumericField)
            yield return new ClientSideNumberValidator(metadata, context);
    }
}
public class ClientSideNumberValidator : ModelValidator
{
    public ClientSideNumberValidator(ModelMetadata metadata,
        ControllerContext controllerContext)
        : base(metadata, controllerContext) { }
    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
        yield break; // Do nothing for server-side validation
    }
    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        yield return new ModelClientValidationRule
        {
            ValidationType = "number",
            ErrorMessage = Resources.Global.InvalidField
        };
    }
}

似乎这就是添加数字验证的原因。现在让我感到困惑的是,为什么这只发生在日期时间字段而不是字符串字段上?

我遇到了类似的问题,并通过添加解决了它

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

Application_Start Global.asax.cs

这适用于所有值类型 - string不是值类型,DateTime是。您不需要更改ClientNumberValidatorProvider

MVC 4 正在生成这些属性,因为您使用的是 web.config 中设置的不显眼的验证:

 <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>

您可以在 web.config 中将这些属性设置为 false:

<add key="ClientValidationEnabled" value="false" />
<add key="UnobtrusiveJavaScriptEnabled" value="false" />

但我想你真的想在客户端验证你的日期,所以你必须使用@Html.TextBoxFor而不是@Html.TextBox

@Html.TextBoxFor(m=>m.FirstDate)

或者更好的是在Views/Shared/EditorTemplates下创建一个名为DateTime.cshtml的模板,然后使用@Html.EditorFor(m=>m.FirstDate)模板可以是这样的(带有正确的标记和属性(:

@model DateTime?
@{
    var value = "";
    const string format = "{0:yyyy-MM-dd HH:mm}";
    if (Model.HasValue) {
        value = string.Format(format, Model.Value);
    }
}
<label class="form-group">
    <i class="glyphicon glyphicon-calendar"></i>
    @Html.TextBox("", null,
        new
        {
            @class = "form-control date", placeholder = ViewData.ModelMetadata.DisplayName ?? ViewData.ModelMetadata.PropertyName,
            data_format = "dd/mm/yy HH:ii P",
            data_initial_value = value
        })
</label>

EditFor帮助程序将自动推断要传递的属性的类型,并使用在本例中称为类型的模板DateTime 。请注意,该模板还键入了允许处理空日期的@model DateTime?

我已经通过调整 ClientNumberValidatorProvider 解决了我的问题。它现在看起来像这样:

public class ClientNumberValidatorProvider : ClientDataTypeModelValidatorProvider
{
    private static readonly HashSet<Type> numericTypes = new HashSet<Type>(new Type[]
    {
        typeof(byte), typeof(sbyte),
        typeof(short), typeof(ushort),
        typeof(int), typeof(uint),
        typeof(long), typeof(ulong),
        typeof(float), typeof(double), typeof(decimal)
    });
    public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
    {
        if (numericTypes.Contains(metadata.ModelType))
            yield return new ClientSideNumberValidator(metadata, context);
    }
}

仅当模型的属性是 HashSet 中的类型之一时,它才会返回 ClientSideNumberValidator。感谢彼得·史密斯为我指出了正确的方向。HashSet也被Microsoft使用:ClientDataTypeModelValidatorProvider.cs