2011-06-17 100 views
5

我在ViewModel中拥有DateTime MyDate类型的属性。我想,以确保用户只输入在一个特定的格式(DD.MM.YYYY)文本框的日期部分,并试图以下属性:在ASP.NET MVC中以特定格式验证日期3

[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辅助
  • 服务器端验证总是失败两个帮手预期,即使像“2011年6月17日”,它通过正则表达式的有效日期。 MyDate属性填写正确,输入日期为viewModel,并传递给操作。所以看起来,模型绑定工作。
  • DisplayFormat属性仅受到EditorFor的尊重,但不受TextBoxFor的尊重。 TextBoxFor显示 “DD.MM.YYYY HH:MM:SS”

问题:

  1. 我可以申请一个RegularExpressionAttribute在所有上这不是一个string的属性?如果允许在服务器端如何评估reg ex等非字符串属性(如DateTime)?是否像MyDate.ToString()与reg ex相比? (这可以解释的是,验证失败,因为的ToString将返回一个字符串,包括其不通过正则表达式的时间部分。)

  2. 是在DisplayFormat属性一般只能通过EditorFor从不推崇的TextBoxFor

  3. 我该如何进行日期验证?

回答

4

我现在扔掉了RegularExpression。它似乎不适用于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属性会启动,并且她会收到仅应输入日期的警告。

10

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

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

您可以使用web.config中的<globalization>元素来设置服务器端文化。你可以在它使用相同的文化为客户这样一种方式进行配置:

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

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

+0

感谢您的链接,我已将其加入书签以供将来参考。但是:我认为我的问题与本地化没有任何关系。我不相信正则表达式会被忽略:客户端验证工作和服务器端验证也会对reg ex进行一些操作(它违背了这个reg ex,就像ModelState所说的那样)。我测试开发机器(客户端和服务器=相同的机器),所以语言环境是相同的。但我同时也相信,使用reg ex是错误的(虽然没有忽略)。你如何验证用户只输入没有时间部分的日期? – Slauma

+1

@Slauma,你在同一台机器上试过这个事实并不意味着浏览器和服务器的文化设置没有差异。就时间部分而言,我只是告诉用户他需要输入日期的格式,而在服务器上,如果我的应用程序不需要它,我会简单地忽略时间部分。甚至可能提供一个jQuery日期选择器来简化用户输入正确格式的日期。 –

+0

你说得对,我想它太复杂了。现在作为一个额外的帮助用户输入,我创建了一个'DateOnly'属性(请参阅我自己的答案)。日期选择器对用户来说是更好的帮助!我会尝试将其作为下一步之一。 – Slauma