【问题标题】:Validate a Date in a specific format in ASP.NET MVC 3在 ASP.NET MVC 3 中以特定格式验证日期
【发布时间】:2011-09-17 07:27:02
【问题描述】:

我的 ViewModel 中有一个 DateTime MyDate 类型的属性。我想确保用户仅以特定格式(dd.mm.yyyy)在文本框中输入日期部分并尝试了以下属性:

[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode=true)]
[RegularExpression(@"^(([0-2]\d|[3][0-1])\.([0]\d|[1][0-2])\.[2][0]\d{2})$",
    ErrorMessage="Failed...")]
public DateTime MyDate { get; set; }

HttpPost 的控制器操作签名如下所示:

[HttpPost]
public ActionResult Edit(int id, MyViewModel viewModel)
{
    // MyViewModel contains the MyDate property ...
    // ...
    if (ModelState.IsValid)
    {
        // ...
    }
    // ...
}

在 Razor 视图中我尝试了以下两种方式:

  1. @Html.TextBoxFor(model => model.MyDate)

  2. @Html.EditorFor(model => model.MyDate)

它没有按我的意愿工作。结果是:

  • 客户端验证与两个 Html 帮助程序都按预期工作
  • 两个助手的服务器端验证总是失败,即使像“17.06.2011”这样通过正则表达式的有效日期也是如此。 MyDate 属性已正确填充 viewModel 中输入的日期,该日期已传递给操作。所以看起来模型绑定是有效的。
  • DisplayFormat 属性仅受 EditorFor 尊重,但不受 TextBoxFor 尊重。 TextBoxFor 显示“dd.mm.yyyy hh:mm:ss”

问题:

  1. 我可以在不是string 的属性上应用RegularExpressionAttribute 吗?如果允许,reg ex 如何在服务器端评估非字符串属性,如DateTime?与 reg ex 相比,MyDate.ToString() 之类的东西吗? (它会解释验证失败,因为 ToString 将返回一个包含不通过正则表达式的时间部分的字符串。)

  2. DisplayFormat 属性是否通常只被 EditorFor 尊重,而从不被 TextBoxFor 尊重?

  3. 如何正确进行日期验证?

【问题讨论】:

    标签: asp.net asp.net-mvc validation asp.net-mvc-3


    【解决方案1】:

    不要使用正则表达式来验证日期,它们会被忽略。

    文化差异可能是您问题的根源。客户端验证使用浏览器的文化来验证日期。例如,如果将其配置为en-US,则预期格式为MM/dd/yyyy。如果您的服务器配置为使用fr-FR,则预期格式为dd/MM/yyyy

    您可以使用 web.config 中的 <globalization> 元素来设置服务器端文化。您可以对其进行配置,使其使用与客户端相同的文化:

    <globalization culture="auto" uiCulture="auto"/>
    

    Hanselman 有一个关于 ASP.NET MVC 中的全球化和本地化的 nice blog post

    【讨论】:

    • 感谢您的链接,我已将其添加为书签以供将来参考。但是:我认为我的问题与本地化无关。我不相信正则表达式被忽略:客户端验证有效,服务器端验证也对 reg ex 做一些事情(正如 ModelState 所说,它对这个 reg ex 失败)。我在开发机器上测试(客户端和服务器=同一台机器),所以语言环境是相同的。但同时我也相信使用 reg ex 是错误的(尽管没有被忽略)。您将如何验证用户只输入了没有时间部分的日期?
    • @Slauma,您在同一台机器上尝试过这个事实并不意味着浏览器和服务器的文化设置没有差异。就时间部分而言,我会简单地告诉用户他需要输入日期的格式,如果我的应用程序不需要它,我会在服务器上忽略时间部分。甚至可能提供一个 jquery 日期选择器来简化用户输入正确格式的日期。
    • 你说得对,我试的太复杂了。现在作为对用户输入的一点额外帮助,我创建了一个DateOnly 属性(请参阅我自己的答案here)。日期选择器是对用户更好的帮助!我将尝试将其作为后续步骤之一。
    【解决方案2】:

    我现在已经扔掉了RegularExpression。它似乎不适合DateTime 类型的属性。然后我为 DateTime 和可为空的 DateTime 创建了一个新的验证属性:

    [AttributeUsage(AttributeTargets.Property, Inherited = false,
        AllowMultiple = false)]
    public sealed class DateOnlyAttribute : ValidationAttribute
    {
        public DateOnlyAttribute() :
            base("\"{0}\" must be a date without time portion.")
        {
        }
    
        public override bool IsValid(object value)
        {
            if (value != null)
            {
                if (value.GetType() == typeof(DateTime))
                {
                    DateTime dateTime = (DateTime)value;
                    return dateTime.TimeOfDay == TimeSpan.Zero;
                }
                else if (value.GetType() == typeof(Nullable<DateTime>))
                {
                    DateTime? dateTime = (DateTime?)value;
                    return !dateTime.HasValue
                        || dateTime.Value.TimeOfDay == TimeSpan.Zero;
                }
            }
            return true;
        }
    
        public override string FormatErrorMessage(string name)
        {
            return string.Format(CultureInfo.CurrentCulture,
                ErrorMessageString, name);
        }
    }
    

    用法:

    [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode=true)]
    [DateOnly]
    public DateTime MyDate { get; set; }
    

    它不提供客户端验证。在服务器端,验证依赖于模型绑定(以确保输入的字符串完全可以转换为DateTime)。如果用户输入了除午夜之外的时间部分,DateOnly 属性将启动,她会收到一条警告,提示您只应输入日期。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-25
      相关资源
      最近更新 更多