ASP.NET MVC的四种验证编程方式

2019-05-23 00:58:54丽君

表示性别的Gender属性的值必需是“M”(Male)或者“F”(Female),其余的均为无效值。
Age属性表示的年龄必须在18到25周岁之间。
如下所示的是Action方法Index对应View的定义,这是一个Model类型为Person的强类型View,它包含一个用于编辑人员信息的表单。我们直接调用HtmlHelper<TModel> 的扩展方法EditorForModel将作为Model的Person对象以编辑模式呈现在表单之中。

@model Person 
<html> 
<head> 
  <title>编辑人员信息</title> 
</head> 
<body> 
  @using (Html.BeginForm()) 
  {  
    @Html.EditorForModel() 
    <input type="submit" value="保存"/> 
  } 
</body> 
</html> 

直接运行该程序后,一个用于编辑人员基本信息的页面会被呈现出来,如果我们在输入不合法的数据并提交后,相应的验证信息会以图1所示的形式呈现出来。

二、使用ValidationAttribute特性

将针对输入参数的验证逻辑和业务逻辑定义在Action方法中并不是一种值得推荐的编程方式。在大部分情况下,同一个数据类型在不同的应用场景中具有相同的验证规则,如果我们能将验证规则与数据类型关联在一起,让框架本身来实施数据验证,那么最终的开发者就可以将关注点更多地放在业务逻辑的实现上面。实际上这也是ASP.NET MVC的Model验证系统默认支持的编程方式。当我们在定义数据类型的时候,可以在类型及其数据成员上面应用相应的ValidationAttribute特性来定义默认采用的验证规则。

“System.ComponentModel.DataAnnotations”命名空间定义了一系列具体的ValidationAttribute特性类型,它们大都可以直接应用在自定义数据类型的某个属性上对目标数据成员实施验证。这些预定义验证特性不是本章论述的重点,我们会在“下篇”中对它们作一个概括性的介绍。

常规验证可以通过上面列出的这些预定义ValidationAttribute特性来完成,但是在很多情况下我们需要通过创建自定义的ValidationAttribute特性来解决一些特殊的验证。比如上面演示实例中针对Person对象的验证中,我们要求Gender属性指定的表示性别的值必须是“M/m”和“F/f”两者之一,这样的验证就不得不通过自定义的ValidationAttribute特性来实现。

针对 “某个值必须在指定的范围内”这样的验证规则,我们定义一个DomainAttribute特性。如下面的代码片断所示,DomainAttribute具有一个IEnumerable<string>类型的只读属性Values提供了一个有效值列表,该列表在构造函数中被初始化。具体的验证实现在重写的IsValid方法中,如果被验证的值在这个列表中,则视为验证成功并返回True。为了提供一个友好的错误消息,我们重写了方法FormatErrorMessage。

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,  AllowMultiple = false)] 
public class DomainAttribute : ValidationAttribute 
{ 
  public IEnumerable<string> Values { get; private set; } 
 
  public DomainAttribute(string value) 
  { 
    this.Values = new string[] { value }; 
  } 
 
  public DomainAttribute(params string[] values) 
  { 
    this.Values = values; 
  } 
 
  public override bool IsValid(object value) 
  { 
    if (null == value) 
    { 
      return true; 
    } 
    return this.Values.Any(item => value.ToString() == item); 
  } 
 
  public override string FormatErrorMessage(string name) 
  { 
    string[] values = this.Values.Select(value => string.Format("'{0}'", value)).ToArray(); 
    return string.Format(base.ErrorMessageString, name,string.Join(",",  values)); 
  } 
}