【问题标题】:Is the DataTypeAttribute validation working in MVC2?DataTypeAttribute 验证是否在 MVC2 中工作?
【发布时间】:2011-01-24 09:17:45
【问题描述】:

据我所知 System.ComponentModel.DataAnnotations.DataTypeAttribute 在 MVC v1 的模型验证中不起作用。例如,

public class Model
{
  [DataType("EmailAddress")]
  public string Email {get; set;}
}

在上面的代码中,电子邮件属性将不会在 MVC v1 中进行验证。它在 MVC v2 中工作吗?

【问题讨论】:

    标签: c# asp.net-mvc validation email data-annotations


    【解决方案1】:

    [DataType("EmailAddress")] 默认情况下不影响验证。这是该属性的IsValid 方法(来自反射器):

    public override bool IsValid(object value)
    {
        return true;
    }
    

    这是用于验证电子邮件的自定义 DataTypeAttribute 示例(取自该站点 http://davidhayden.com/blog/dave/archive/2009/08/12/CustomDataTypeAttributeValidationCustomDisplay.aspx):

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple  = false)]
    public class EmailAddressAttribute : DataTypeAttribute
    {
        private readonly Regex regex = new Regex(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", RegexOptions.Compiled);
    
        public EmailAddressAttribute() : base(DataType.EmailAddress)
        {
    
        }
    
        public override bool IsValid(object value)
        {
    
            string str = Convert.ToString(value, CultureInfo.CurrentCulture);
            if (string.IsNullOrEmpty(str))
                return true;
    
            Match match = regex.Match(str);   
            return ((match.Success && (match.Index == 0)) && (match.Length == str.Length));
        }
    }
    

    【讨论】:

    • 我认为您想让该正则表达式变为静态,因为设置编译选项可能会导致在使用该属性的任何地方都进行编译,并且如果内存服务,则每次都会生成一个新的内存中程序集。
    • @Mike Scott:新的内存组件?你这是什么意思?
    • LukLed,它在锡上所说的 - 在内存中动态创建的程序集 ;-) 带有已编译选项的正则表达式将 IL 发送到内存中的程序集。因此,为了确保每次调用都不会耗尽内存,您应该保存已编译的正则表达式实例并重用它。见blogs.msdn.com/b/bclteam/archive/2004/11/12/256783.aspx
    • @Mike Scott:你是对的,但如果我没记错的话,一个属性只被实例化一次每个类,而不是每个对象。这意味着在实践中成本非常小。尽管如此,你是对的,它是静态的没有成本。如果语言允许,应该是 const。
    • @skrebbel,所以如果你将属性放在 10 个类上,这是否意味着属性的 10 个实例化,因此为同一个正则表达式创建了 10 个内存程序集?
    【解决方案2】:

    LukLed pointed out 一样,DataTypeAttribute 默认不进行任何验证。但它确实会影响有关数据呈现方式的模板。

    例如,如果您在具有 DataType(DataType.EmailAddress) 属性的模型上调用 Html.DisplayFor() 方法,它将使用 <a href="mailto:{0}">{0}</a> 格式化其值(至少在 MVC RC2 中)。

    【讨论】:

    • 感谢您指出 DataTypeAttribute 不是验证属性。
    • @Wayne:实际上是 ValidationAttribute。它继承自 ValidationAttribute,但始终返回 true。您可以覆盖 IsValid 方法并定义自己的方法,就像在 David Hayden 的解决方案中一样。
    • @LukLed,它确实继承自 ValidationAttribute。我想知道为什么。无论如何,会更正那部分。
    • DataAnnotationsModelValidator 遍历每个 ValidationAttribute。 DataTypeAttribute 是 ValidationAttribute,因此可以很容易地继承和引入验证。当您定义自己的数据类型时,您可以轻松添加验证。
    • @LukLed,谢谢。我再次编辑了答案以删除它说它不用于验证的部分。
    【解决方案3】:

    或者,您可以直接在您的字段上使用 RegularExpression 属性,而不是创建自己的属性,该属性最终将检查正则表达式匹配。

    [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = PaErrorMessages.InvalidEmailAddress)]
    public string Email { get; set; }
    

    【讨论】:

      【解决方案4】:

      从 .NET 4.5 开始有 EmailAddressAttribute,它正确实现了 IsValid 方法。因此,如果您的目标是 .NET 4.5,那么为了进行验证,请考虑使用 EmailAddressAttribute 而不是自定义的。例如,

      public class Model
      {
          [EmailAddress(ErrorMessage = "INVALID EMAIL")]
          public string Email {get; set;}
      }
      

      如果你对EmailAddressAttribute的实现感到好奇,那么这里是该类的反编译(使用JetBrains dotPeek反编译器)源代码:

      using System;
      using System.ComponentModel.DataAnnotations.Resources;
      using System.Text.RegularExpressions;
      
      namespace System.ComponentModel.DataAnnotations
      {
        [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
        public sealed class EmailAddressAttribute : DataTypeAttribute
        {
          private static Regex _regex = new Regex("^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
      
          static EmailAddressAttribute()
          {
          }
      
          public EmailAddressAttribute()
            : base(DataType.EmailAddress)
          {
            this.ErrorMessage = DataAnnotationsResources.EmailAddressAttribute_Invalid;
          }
      
          public override bool IsValid(object value)
          {
            if (value == null)
              return true;
            string input = value as string;
            if (input != null)
              return EmailAddressAttribute._regex.Match(input).Length > 0;
            else
              return false;
          }
        }
      }
      

      【讨论】:

        【解决方案5】:

        查看 Scott Guthrie 关于 MVC 2 验证的博文。它非常好。 http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多